17

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

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

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

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

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应用于我的案例吗?baz

即添加签名消除了单态性限制,并且没有限制,右侧 [] 出现歧义,“固有歧义”类型为forall a . Eq a => [a]?

4

2 回答 2

13

的方程baz在一个绑定组中,在输入整个组后进行概括。如果没有类型签名,baz则假定该方法具有单型,因此[]递归调用中的类型由它给出(查看 ghc 的 -ddump-simpl 输出)。使用类型签名,编译器被明确告知该函数是多态的,因此它不能假定[]递归调用中的类型相同,因此它是模棱两可的。

正如 John L 所说,在 中,只要有单型foo,类型就由 - 的出现来固定。您可以通过提供与(需要)相同的类型来创建相同的歧义,fff(==)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 []
于 2011-11-25T15:38:51.260 回答
11

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

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

于 2011-11-25T14:59:26.493 回答