单同性约束对类型约束的影响

时间:2011-11-25 14:33:29

标签: haskell types recursion polymorphism monomorphism-restriction

添加baz的类型声明时,此代码会中断:

baz (x:y:_) = x == y
baz [_] = baz []
baz [] = False

一个常见的解释(参见Why can't I declare the inferred type?的例子)是因为多态递归。

但是这个解释并没有解释为什么效果会随着另一个多态递归示例而消失:

foo f (x:y:_) = f x y
foo f [_] = foo f []
foo f [] = False

它也没有解释为什么GHC认为在没有类型声明的情况下递归是单态的。

http://www.haskell.org/onlinereport/decls.html#sect4.5.5reads的{​​{1}}示例的说明是否可以应用于baz个案例?

即。添加签名会删除单态限制,并且没有限制,右侧[]的歧义会出现,并且会出现forall a . Eq a => [a]的“天生暧昧”类型?

2 个答案:

答案 0 :(得分:13)

baz的等式在一个绑定组中,在输入整个组之后进行泛化。没有类型签名,这意味着baz被假定具有单型,因此递归调用中[]的类型由此给出(查看ghc的-ddump-simpl输出)。使用类型签名,编译器被明确告知该函数是多态的,因此它不能假定递归调用中[]的类型是相同的,因此它是不明确的。

正如John L所说,在foo中,类型由f的出现来确定 - 只要f有一个单型。您可以通过将f(==)相同的类型(需要Rank2Types)来创建相同的歧义,

{-# LANGUAGE Rank2Types #-}
foo :: Eq b => (forall a. Eq a => a -> a -> Bool) -> [b] -> Bool
foo f (x:y:_) = f x y
foo f[_] = foo f []
foo _ [] = False

这给了

Ambiguous type variable `b0' in the constraint:
  (Eq b0) arising from a use of `foo'
Probable fix: add a type signature that fixes these type variable(s)
In the expression: foo f []
In an equation for `foo': foo f [_] = foo f []

答案 1 :(得分:11)

你的第二个例子不是多态递归的。这是因为函数f出现在递归定义的LHS和RHS上。另请考虑foo(a -> a -> Bool) -> [a] -> Bool的类型。这会将列表元素类型修复为与f的参数类型相同。因此,GHC可以确定RHS上的空列表必须与输入列表具有相同的类型。

我不认为reads示例适用于baz情况,因为GHC能够编译baz而没有类型签名且禁用单态限制。因此,我希望GHC的类型算法有一些其他机制可以消除歧义。

相关问题