我不明白为什么以下代码无法编译:
{-# 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)
有人可以解释一下发生了什么吗?
答案 0 :(得分:11)
顶级类型声明中引入的类型变量与函数体内引入的类型变量不同。另一种说法是嵌套类型声明引入" fresh"变量。另一种说法是在您的代码中将显式forall
放在Haskell自动引入它们的地方:
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会自动在它通常所做的所有相同位置引入它们。