【发布时间】:2019-01-10 22:43:54
【问题描述】:
考虑这个函数:
doToBoth f x y = (f x, f y)
它在简单的情况下按预期工作:
doToBoth (2 *) 10 15 == (20, 30)
doToBoth head [1,2] [3,4,5] == (1, 3)
然后我尝试了这些:
doToBoth head [1,10,100] "apple"
doToBoth pred 2 'b'
我希望它们都导致(1, 'a'),但它们只会导致类型错误。问题是doToBoth 的推断类型不够多态:
doToBoth :: (a1 -> a2) -> a1 -> a1 -> (a2, a2)
看到这一点,我尝试添加显式类型签名来修复它:
doToBoth :: (t ~ (i1 -> o1), t ~ (i2 -> o2)) => t -> i1 -> i2 -> (o1, o2)
这个类型签名被接受了,但它并没有解决问题,检查:t doToBoth 发生的事情发现它最终得到了一个与原始推断的类型相同的类型:
doToBoth :: (i2 -> o2) -> i2 -> i2 -> (o2, o2)
编写类型签名以使此函数按我想要的方式工作的正确方法是什么?
【问题讨论】:
-
^ 如果这不能完全回答您的问题,您可以告诉我。在这里得到满足您特定问题的东西应该是一个稍微小的修改,但如果您愿意,我可以提供有关该修改的更多详细信息。
-
@DavidYoung 你的答案看起来几乎完美。将其转换为使用可见类型应用程序而不是代理并添加新的类/实例以支持
head函数非常简单(如果需要,我可以将其中一个或两个编辑到您的答案中)。唯一的缺点是它实际上不适用于length函数,而是用于length . toList函数。自从你在 2015 年写了这些新的 GHC 扩展后,我尝试了一段时间来解决这个问题,但没有运气。
标签: haskell types parametric-polymorphism