更高级别的类型看起来非常有趣。来自Haskell wikibook来自这个例子:
foo :: (forall a. a -> a) -> (Char,Bool)
foo f = (f 'c', f True)
现在我们可以在没有编译器爆炸的情况下评估foo id
。这个例子在本书中很快被我在其他几个地方看到的真实例子:ST monad和runST
。那太酷了。
但是我还没有遇到过这样一种情况:我通过使用更高级别的参数编写自己的函数来解决问题。你呢?您在野外有什么样的rank-2或rank-n多态性?
答案 0 :(得分:8)
Weirich和Washburnn的“Boxes go Bananas”! (paper,slides)
这是一个非常原始的,可能稍微不准确的解释它的全部内容:给定一个归纳类型,BGB允许你表示那种类型的函数空间是“积极的” - 它们从不区别于它们的论点。它们最多包含其参数作为其他值的一部分(通常是相同类型)。
Weirich + Washburn使用它来获得-XRankNTypes
Haskell中lambda演算的可能 - adequate HOAS表示(有人证明它已经足够了吗?)。
我使用它here(警告:凌乱的代码)转一个
(forall g . GArrow g => g () x -> g () y)
进入
(forall g . GArrow g => g x y)
这是有效的,因为rank-2多态类型不能“检查”其参数的结构 - 它能做的就是将该参数“粘贴”到更大的结构中。一些技巧让我弄清楚粘贴发生的位置,然后我将粘贴点(如果有的话)回到GArrow
的输入。
您无法使用Control.Arrow
类执行此操作,因为整个Haskell函数空间通过arr
“泄漏”到其中。
答案 1 :(得分:7)
查看Darcs source中的withRepoLock
等函数。
Darcs支持多种存储库格式,并且通过类型类表示支持。因此,您可以编写通用存储库格式的通用代码。在实际读取磁盘存储库时,您希望通过一些公共代码调度到该代码,该代码确定存储库所处的格式并选择正确的类型类实例化。
答案 2 :(得分:7)
最近有人asked a question here on Stack Overflow可以用更高级别的类型来解决。
另一个应用程序在Scrap Your Boilerplate论文中。
答案 3 :(得分:3)
您可能遇到过排名较高的类型有用但未能实现的问题。例如,在Darcs示例中,他们可以很容易地实现它而没有更高级别的类型。相反,调用者必须确保它们遵守某些函数的先决条件,例如为存储库格式选择正确的函数实例化。
排名较高的类型的优点是它将从程序员到编译器的权利转移到了。使用传统方法,如果Darcs开发人员使用存储库类型出错,结果将是运行时错误或其他损坏的数据。对于排名较高的类型,开发人员在编译时会收到类型错误。
答案 4 :(得分:0)
可以在 Luke Palmer 的 IO-free splittable supply - 他展示了如何 使用简单的唯一值供应可以获得一个纯粹的接口:
runSupply :: (forall a. Eq a => Supply a -> b) -> b