添加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.5中reads
的{{1}}示例的说明是否可以应用于baz
个案例?
即。添加签名会删除单态限制,并且没有限制,右侧[]的歧义会出现,并且会出现forall a . Eq a => [a]
的“天生暧昧”类型?
答案 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的类型算法有一些其他机制可以消除歧义。