由于类型变量不能容纳多型,因此似乎由于Rank * Types的单型限制,我们无法重用现有函数。
例如,当中间类型是多型时,我们不能使用函数(.)。我们被迫在现场重新实施(.)。对于(.),这当然是微不足道的,但是对于更大量的代码体来说,这是一个问题。
我还认为使((f .g)x)不等于(f(g x))对参照透明性及其好处造成严重打击。
在我看来,这似乎是一个制止性的问题,并且似乎使Rank * Types扩展对于广泛使用几乎是不切实际的。
我想念什么吗?是否有计划使Rank * Types与其余类型系统更好地交互?
编辑:如何使(runST。永远)的类型计算出来?
最佳答案
针对Rank-N类型的最新建议是Don的链接FPH文件。我认为这也是最好的。所有这些系统的主要目标是要求尽可能少的类型注释。问题是,当从Hindley / Milner转到System F时,我们会丢失主体类型,并且类型推断变得不可确定-因此需要类型注释。
“盒子类型”工作的基本思想是尽可能传播类型注释。类型检查器在类型检查和类型推断模式之间切换,希望不再需要任何注释。这里的缺点是很难解释是否需要类型注释,因为它取决于实现细节。
到目前为止,雷米(Remy)的MLF系统是最好的建议。它需要最少数量的类型注释,并且在许多代码转换中都稳定。问题在于它扩展了类型系统。以下标准示例说明了这一点:
choose :: forall a. a -> a -> a
id :: forall b. b -> b
choose id :: forall c. (c -> c) -> (c -> c)
choose id :: (forall c. c -> c) -> (forall c. c -> c)
以上两种类型在系统F中都是允许的。第一种是标准的Hindley / Milner类型,并使用谓词实例化,第二种是强制性实例化。两种类型都不比另一种更通用,因此类型推断必须猜测用户想要哪种类型,这通常是一个坏主意。
MLF则用有界量化扩展了系统F。上面示例的主体(=最通用)类型为:
choose id :: forall (a < forall b. b -> b). a -> a
您可以将其读为“
choose id
的类型为a
,其中a
必须是a
的实例”。有趣的是,仅此一项就没有标准的Hindley / Milner强大。因此,MLF还允许进行严格的定量。以下两种类型是等效的:
(forall b. b -> b) -> (forall b. b -> b)
forall (a = forall b. b -> b). a -> a
刚性量化是通过类型注释引入的,技术细节确实非常复杂。有利的是,MLF仅需要很少的类型注释,并且有一个简单的规则来确定何时需要它们。缺点是:
回到FPH,其基本思想是内部使用MLF技术,但需要在
forall b. b -> b
绑定(bind)上进行类型注释。如果只需要Hindley / Milner类型,则不需要任何注释。如果要使用更高级别的类型,则需要指定请求的类型,但只能在let
(或顶级)绑定(bind)处指定。FPH(如MLF)支持强制性实例化,因此我认为您的问题不适用。因此,在上面键入您的
let
表达式应该没有问题。但是,FPH尚未在GHC中实施,很可能不会实施。困难来自与相等强制的交互(可能还有类型类约束)。我不确定最新的状态是什么,但是我听说SPJ希望摆脱障碍。所有这些表达能力都是有代价的,到目前为止,还没有找到负担得起的,全面的解决方案。关于haskell - 没有多型变量,Rank2Types/RankNTypes是否可行?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3076909/