2014-09-20 75 views
7

我不明白,为什么下面的代码不会编译:类型变量“A0”是不明确的

{-# 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) 

以下是错误消息:

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) 

有人能解释这是怎么回事上 ?

+5

'ScopedTypeVariables'要求你明确地写出哪些类型的签名应该被写出来:'toBool :: forall a。 D a - > Bool'。 – user2407038 2014-09-20 05:00:17

回答

10

在顶层类型声明中引入的类型变量与在函数体内引入的类型变量不同。另一种说法是嵌套类型声明引入了“新鲜”变量。另一种方式说,这是把明确forall在你的代码中哈斯克尔自动介绍他们,默默:

toBool :: forall a . D a -> Bool 
toBool D = c (undefined :: forall a . a) -- another forall here? 

你真的打算什么

toBool :: forall a . D a -> Bool 
toBool D = c (undefined :: a) -- capture `a` from prior scope 

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

{-# LANGUAGE ScopedTypeVariables #-} 

toBool :: forall a . D a -> Bool 
toBool D = c (undefined :: a) 

注意,以便调用ScopedTypeVariables现在必须手动介绍要特殊对待的forall秒。没有那个手册forall Haskell会自动将它们引入到它通常所用的所有相同位置。