Haskell 将有效forall类型归因于let绑定变量时出现类型错误

Haskell 将有效forall类型归因于let绑定变量时出现类型错误,haskell,types,typechecking,Haskell,Types,Typechecking,这是类型检查器中的错误吗 Prelude> let (x :: forall a. a -> a) = id in x 3 <interactive>:0:31: Couldn't match expected type `forall a. a -> a' with actual type `a0 -> a0' In the expression: id In a pattern binding: (

这是类型检查器中的错误吗

Prelude> let (x :: forall a. a -> a) = id in x 3

<interactive>:0:31:
    Couldn't match expected type `forall a. a -> a'
                with actual type `a0 -> a0'
    In the expression: id
    In a pattern binding: (x :: forall a. a -> a) = id

这让我想到,“弱prenex转换”(见第23页)可能有某种关联。将
for all
嵌入到一个不能“浮动”的反变位置,似乎可以避免这个奇怪的错误。

不是一个真正的答案,但是对于注释来说太长了:
这很可能是一个错误。毫不奇怪,在表情上玩了一点

let x :: forall a. a -> a; x = id in x 3
如果启用了写入显式孔,则可以工作。不过,这是一种标准的一级沼泽类型。其他一些变化:

$ ghci-6.12.3 -ignore-dot-ghci -XRankNTypes -XScopedTypeVariables
Prelude> let (x :: forall a. a -> a) = \y -> id y in x 3
3
好吧,这是有效的,我不知道为什么lambda的行为不同,但它确实如此。然而:

$ ghci -ignore-dot-ghci -XRankNTypes -XScopedTypeVariables
Prelude> let (x :: forall a. a -> a) = \y -> id y in x 3

<interactive>:0:31:
    Couldn't match expected type `t0 -> t1'
                with actual type `forall a. a -> a'
    The lambda expression `\ y -> id y' has one argument,
    but its type `forall a. a -> a' has none
    In the expression: \ y -> id y
    In a pattern binding: (x :: forall a. a -> a) = \ y -> id y
$ghci-忽略点ghci-XRankNTypes-XScopedTypeVariables
前奏曲>让(x::对于所有a.a->a)=\y->id y在X3中
:0:31:
无法匹配预期的类型't0->t1'
使用实际类型`forall a。a->a'
lambda表达式“\y->id y”有一个参数,
但它是a型的。a->a'没有
在表达式中:\y->id y
在模式绑定中:(x::forall a.a->a)=\y->id y

(7.2.2;7.0.4给出了相同的误差)。这是令人惊讶的。

我认为这里发生的是:在标准的Damas–Milner类型推断中,让绑定成为唯一发生类型泛化的地方。失败的示例使用的类型签名是“以明显的方式约束模式类型”的。现在,在这个例子中,这个约束应该发生在泛化之前还是之后并不“明显”,但是你失败的例子表明,我认为,它在泛化之前得到应用

更具体地说:在一个let绑定中,
let x=id in…
,发生的是所有a的
id
类型。a->a被实例化为一个单类型,比如说
a0->a0
,然后它被指定为
x
的类型,然后被泛化为所有a0的
。a0->a0
。如果,正如我认为的,模式类型签名在泛化之前被检查,那么它实际上是要求编译器验证monotype
a0->a0
比所有a的polype
。a->a
,但它不是

如果我们将类型签名移动到绑定级别,
let x::forall a。a->a;在泛化后检查签名(因为为了启用多态递归明确允许这样做),并且不会出现类型错误


我认为,这是否是一个bug是一个意见问题。似乎没有一个实际的规范可以告诉我们什么是正确的行为;只有我们的期望。我建议与GHC人员讨论此事。

有趣。我在GHC 6.12.1上收到了一条不同的错误消息:“推断类型的多态性低于预期。量化类型变量“a”在表达式:id中转义。我可能错了(我使用的是较旧的GHC),但这不合法Haskell 98/2010。你们有什么分机?这也许可以解释发生了什么。(我得到了与hammar相同的错误,因此问题可能是
a
并不是你所期望的那样。)哦,我想我还需要-XScopedTypeVariables,这很奇怪……你需要
ScopedTypeVariables
来允许模式签名(
PatternSignatures
不推荐)。谢谢,这听起来像是一个非常合理的理论。我在GHC trac上备案了。
$ ghci -ignore-dot-ghci -XRankNTypes -XScopedTypeVariables
Prelude> let (x :: forall a. a -> a) = \y -> id y in x 3

<interactive>:0:31:
    Couldn't match expected type `t0 -> t1'
                with actual type `forall a. a -> a'
    The lambda expression `\ y -> id y' has one argument,
    but its type `forall a. a -> a' has none
    In the expression: \ y -> id y
    In a pattern binding: (x :: forall a. a -> a) = \ y -> id y