类型变量'a0'是不明确的

Joh*_*ith 7 haskell

我不明白为什么下面的代码不会编译:

{-# LANGUAGE GADTs, ScopedTypeVariables #-}

data A = A

class C a where
  c :: a -> Bool

instance C A where
  c _ = True

data D a where
  D :: C a => D a

toBool :: D a -> Bool
toBool D = c (undefined::a)
Run Code Online (Sandbox Code Playgroud)

这是错误消息:

Could not deduce (C a0) arising from a use of ‘c’
from the context (C a)
  bound by a pattern with constructor
             D :: forall a. C a => D a,
           in an equation for ‘toBool’
  at test.hs:15:8
The type variable ‘a0’ is ambiguous
Note: there is a potential instance available:
  instance C A -- Defined at test.hs:8:10
In the expression: c (undefined :: a)
In an equation for ‘toBool’: toBool D = c (undefined :: a)
Run Code Online (Sandbox Code Playgroud)

有人可以解释发生了什么吗?                                        

J. *_*son 11

顶级类型声明中引入的类型变量与函数体内引入的类型变量不同.另一种说法是嵌套类型声明引入"新鲜"变量.另一种说法是forall在你的代码中将显式s放在Haskell自动引入的代码中,默默地:

toBool :: forall a . D a -> Bool
toBool D = c (undefined :: forall a . a)   -- another forall here?
Run Code Online (Sandbox Code Playgroud)

你真正想要的是什么

toBool :: forall a . D a -> Bool
toBool D = c (undefined :: a)   -- capture `a` from prior scope
Run Code Online (Sandbox Code Playgroud)

而且,你很幸运.事实证明,几乎每个人都不时需要这种功能,因此存在一种非常常见的Haskell扩展ScopedTypeVariables.以下代码应该编译

{-# LANGUAGE ScopedTypeVariables #-}

toBool :: forall a . D a -> Bool
toBool D = c (undefined :: a)
Run Code Online (Sandbox Code Playgroud)

请注意,为了调用,ScopedTypeVariables您现在必须手动引入forall您想要特别处理的s.没有那个手册,forallHaskell会自动在它通常所做的所有相同位置引入它们.