Haskell 忽略显式forall会产生不明确的类型错误

Haskell 忽略显式forall会产生不明确的类型错误,haskell,types,ghc,Haskell,Types,Ghc,我遇到过这样一种情况:函数无法进行类型检查,除非在其类型签名的开头显式添加forall 有关职能是: test :: (Typeable a) => a -> a test x | typeOf (undefined :: a) == typeOf (undefined :: a) = x | otherwise = x GHC针对上述情况发出以下警告: Ambiguous type variable `a0' in the constraint: (Ty

我遇到过这样一种情况:函数无法进行类型检查,除非在其类型签名的开头显式添加forall

有关职能是:

test :: (Typeable a) => a -> a
test x 
    | typeOf (undefined :: a) == typeOf (undefined :: a) = x
    | otherwise = x
GHC针对上述情况发出以下警告:

  Ambiguous type variable `a0' in the constraint:
  (Typeable a0) arising from a use of `typeOf'
Probable fix: add a type signature that fixes these type variable(s)
In the first argument of `(==)', namely `typeOf (undefined :: a)'
In the expression:
  typeOf (undefined :: a) == typeOf (undefined :: a)
In a stmt of a pattern guard for
               an equation for `test':
  typeOf (undefined :: a) == typeOf (undefined :: a)

Ambiguous type variable `a1' in the constraint:
  (Typeable a1) arising from a use of `typeOf'
Probable fix: add a type signature that fixes these type variable(s)
In the second argument of `(==)', namely `typeOf (undefined :: a)'
In the expression:
  typeOf (undefined :: a) == typeOf (undefined :: a)
In a stmt of a pattern guard for
               an equation for `test':
  typeOf (undefined :: a) == typeOf (undefined :: a)
所以它无法统一这两种类型的未定义值。但是,如果我在前面添加一个forall a:

test :: forall a. (Typeable a) => a -> a
test x 
    | typeOf (undefined :: a) == typeOf (undefined :: a) = x
    | otherwise = x
它编译得很好。这在GHC 7.4.2中使用

{-# LANGUAGE GADTs, StandaloneDeriving, DeriveDataTypeable,
ScopedTypeVariables, FlexibleInstances, UndecidableInstances,
Rank2Types #-}

我的印象是,在类型签名中省略“forall”相当于在所有相关类型变量的开头隐式地附加forall(如GHC文档中所建议的:)。为什么第一个代码片段不进行类型检查,而第二个代码片段进行类型检查?

ScopedTypeVariables扩展为所有量词的顶级
添加语义值。它为绑定体上的类型变量提供作用域


如果没有该
forall
,则第3行上的类型变量
a
与第1行上的
a
是不同的类型变量。错误消息通过将它们标记为
a0
a1
来表明这一点。如果没有相同的类型,第3行的类型是不明确的,因为它完全不受约束。

ref:谢谢你们,这很有意义。我感到困惑,因为多亏了
ScopedTypeVariables
,我在类声明中使用了类似的结构,没有遇到麻烦;该文档解释了这是因为类声明将类型变量带入范围,就像本例中的
forall
一样。