是否可以使用通用函数将元组的第二个元素获取到元组中?

时间:2019-02-19 08:34:13

标签: function haskell types nested tuples

有人在练习有关将函数两次应用于某项函数的练习时问我,我认为这很有趣。

我们的想法是,我们应该使函数两次,这需要一个函数和一个输入,然后两次应用该函数,例如

twice :: (a -> a) -> a -> a
twice f x = f ( f x )

通常来说,打字是很有意义的。 不幸的是,对于元组中的元组和函数fst,我们可能认为可以在((1,2),3)上使用它,但是由于twice的类型,这是不可能的。

有没有办法使类似的东西起作用?

1 个答案:

答案 0 :(得分:7)

由于您的f = fst是多态的,并且两个调用隐式涉及不同的类型,因此无法键入。如果我们使呼叫明确,则它们将变为:

 fst @ (Int,Int) (fst @ ((Int,Int),Int) ((1,2),3))

可能为twice使用不同的类型,要求参数必须是多态函数。这需要Rank2Types

twice' :: (forall a b . (a, b) -> a) -> ((a,b),c) -> a
twice' f x = f ( f x )

但是,上面的函数用途有限,因为f的唯一有意义的选择是fst -没有其他(forall a b . (a, b) -> a)类型的终止函数。

应该也可以使用类型类,并打开一些扩展名。

class C a where
   type Res a
   theF :: a -> Res a

instance C (a, b) where
   type Res (a, b) = a
   theF = fst

twiceC :: (C a, C (Res a)) => a -> Res (Res a)
twiceC x = theF (theF x)

但是,此函数必须在instance中定义,而不是作为参数传递。