function - 是否可以使用通用函数在元组中获取元组的第二个元素?
问题描述
有人在做一个关于将一个函数两次应用于某事物的函数的练习时问我这个问题,我认为这很有趣。
这个想法是我们应该使函数两次,它接受一个函数和一个输入,然后两次应用该函数,例如
twice :: (a -> a) -> a -> a
twice f x = f ( f x )
一般来说,打字很有意义。不幸的是,对于元组中的元组和函数fst
,我们可能认为可以使用它,((1,2),3)
但这是不可能的,因为twice
.
有没有办法让这样的东西有效?
解决方案
使用您的类型是不可能的,因为您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
,而不是作为参数传递。