我想写一个这样的函数
inTransform tr f = tr . f . tr
但我很难把它打对。
我尝试使用Rank 2存在类型,如
inTransform :: (forall a. a -> a) -> (b -> c) -> (b -> c)
但当我尝试使用它时,例如,
inTransform reverse id [1, 6]
我有奇怪的错误,
Couldn't match type ‘a1’ with ‘[a0]’
Expected: a1 -> a1
Actual: [a0] -> [a0]
‘a1’ is a rigid type variable bound by
a type expected by the context:
forall a1. a1 -> a1
因此,存在类型可能不是正确的解决方案?
--编辑--
好的,建议的类型
inTransform :: (a -> b) -> (b -> a) -> a -> b
但实际上不适用于更复杂的用例,例如:
inTransform reverse (:[]) [1, 6]
问题是tr
函数的类型是a -> a
,但在之后应用时可能不是相同的a。这就是为什么我在考虑应用存在Rank 2类型
1条答案
按热度按时间e7arh2l61#
虽然rank-2类型的工作是允许在不同类型的上下文中使用转换,但
∀ a. a -> a
类型太强了,无法在任何非平凡的转换中使用它。对于您的特定示例,将其限制为列表将有效:
但是你可能会发现这太具体了,不能保证抽象。
一个折衷的方法是选择一个任意类型的构造函数,函数在该构造函数上被普遍量化,但在该构造函数的类型参数中保持秩为2:
这同样适用于反转列表,但也可以用于自逆多态函数的其他用例,只要多态参数和结果共享外部形状。