混淆Haskell类型推断

时间:2016-04-13 02:39:23

标签: haskell polymorphism type-inference

我刚开始学习Haskell。由于Haskell是静态类型且具有多态类型推断,因此标识函数的类型为

id :: a -> a

建议id可以将任何类型作为其参数并返回自身。我尝试时工作正常:

a = (id 1, id True)

我只是假设在编译时,第一个id是Num a :: a - > a,第二个id是Bool - >布尔。当我尝试以下代码时,它会出错:

foo f a b = (f a, f b)
result = foo id 1 True

它显示a的类型必须与b的类型相同,因为它与

一起正常工作
result = foo id 1 2

但是,id的参数类型是多态的,所以a和b可以是不同的类型吗?

1 个答案:

答案 0 :(得分:9)

好吧,这是Haskell的类型系统中一个奇怪的怪异角落。这里的问题是有两种方法可以对函数foo进行类型推断。

-- rank 1
foo :: forall a b. (a -> b) -> a -> a -> (b, b)
foo f a b = (f a, f b)

-- rank 2
foo' :: (forall a. a -> a) -> a -> b -> (a, b)
foo' f a b = (f a, f b)

第二种类型是您想要的类型,但第一种类型是您正在获得的类型。第二种类型,如合金指出的那样,是一种排名2类型(如果你想要对排名进行一个很好的解释,我们将忽略这两种方式,但会阅读"Practical type inference for arbitrary-rank types"中的介绍 - 不要&#39因为PDF文件的学术性质可以推迟,因为开头是可读且清晰的。)

我们现在推迟排名较高的类型的定义,并且只是说问题是GHC无法推断排名-2类型。引用论文:

  

已知完整类型推断对于更高级别(impredicative)类型系统是不可判定的,但在实践中,程序员更愿意添加类型注释来指导类型推理引擎,并记录其代码.... / p>      

Kfoury和Wells表明,对于等级≤2,可归类性是可判定的,并且对于所有等级≥3都不可判定(Kfoury& Wells,1994)。对于rank-2片段,同一篇论文给出了一种类型推断算法。这种推理算法有点微妙,与用户提供的类型注释不能很好地交互,据我们所知,它还没有在生产编译器中实现。

不可判定意味着没有任何算法总能导致正确的“是或否”决策。所以你有它:不可能推断出等级3或更高的类型,并且它太难以推断出等级2类型。

现在,回到排名2. (forall a. a -> a)是排名第2的原因。 There's already an excellent Stack Overflow question about what the forall keyword means所以我会将您推荐给您,但基本上这意味着您可以在表达式f a中调用f b(f a, f b)而非ab成为不同的类型,这首先是你想要的,在所有这些热点之前。

最后一件事:您通常在GHCi中看到forall s的原因是,外部范围内的任何forall都被取消了。因此forall a b. (a -> b) -> a -> a -> (b, b)相当于(a -> b) -> a -> a -> (b, b)

总的来说,这是一个很难解释的语言的痛点。

(在评论中给@amalloy提示。)