任何人都可以解释这个错误:
实例头中的语法错误(构造函数预期)
class Nullable v where
default_val :: v
instance Num a => Nullable a where -- error reported here
default_val = 0::a
由于
答案 0 :(得分:8)
其次,不要写表格
的实例instance OtherClass a => Class a where
他们不像你想要的那样工作。 (YMMV与GHC以外的编译器,但即便如此,我也看不出它是个好主意)。大概你的意图是创建几个实例,如:
instance Num a => Nullable a where -- error reported here
default_val = 0::a
instance Bounded a => Nullable a where
default_val = minBound
您可以将类型类约束视为函数的额外参数,如下所示:
instance Num a => Nullable a where
default_val = NumDict a -> 0::a
instance Bounded a => Nullable a where
default_val = BoundedDict a -> minBound
然后ghc实际上看到这样的类实例:
instance Nullable a where
default_val = NumDict a -> 0::a
instance Nullable a where
default_val = BoundedDict a -> minBound
现在,编译器应该选择哪个实例?有两个实例都声称对所有类型都有效。所以有编译错误。
即使您有一个基于类型类的实例,这也是一个问题。假设您有这些实例:
instance Num a => Nullable a where
default_val = 0::a
instance Nullable String where
default_val = ""
instance Nullable BS.ByteString where
default_val = BS.empty
第一个仍然被认为对所有类型都有效,所以ghc说它需要OverlappingInstances扩展才能全部使用它们。那不完全是邪恶的。但是当你试图使用它时,不久之后ghc将需要另一个扩展,IncoherentInstances
。
很多人都害怕使用UndecidableInstances
,但这种恐惧是错误的。 UndecidableInstances
可能发生的最坏情况是编译不会终止(但通常会终止)。 IncoherentInstances
是应该激发恐惧的扩展,因为它会给你的代码带来厄运。如果GHC说您必须启用IncoherentInstances
,则表示您需要更改代码。
TL;博士
不要写表格的实例
instance OtherClass a => Class a where
他们没有做你想做的事。
答案 1 :(得分:1)
Haskell中有一条规则,约束必须比实例本身“更小”。我并不完全理解它背后的理论上的理由,但作为一个实际问题,你可以用newtype
解决它。
newtype N a = N a
instance Num a => Nullable (N a) where
default_val = N 0
GHC还可以选择禁用其中一些规则。见http://www.haskell.org/ghc/docs/latest/html/users_guide/type-class-extensions.html
另请注意,您无法将::a
放在那里。它在实例声明中没有引用相同的a
,但被认为是通用a
,在那里没有任何意义。
答案 2 :(得分:1)
<强>讨论强>
您的代码无效Haskell。不要误解我的意思 - 它是在Haskell社区中常见的形式,它可以由GHC编译,但我强烈建议您不要将“Haskell”与“Haskell加上GHC可以提供的所有扩展”混淆。
1)您正在使用另一个类型类作为约束来实例化一个类型类,而没有使用类型构造函数。在Haskell 2010中,您必须具有类型构造函数:
相应实例声明的一般形式是: 实例cx'=&gt; C(T u1 ... uk)其中{d}其中k≥0。类型(T u1 ... uk)必须采用类型构造函数T的形式应用于简单 类型变量u1,... uk;此外,T不能是类型同义词, 并且ui必须都是截然不同的。
此处GHC提供的扩展程序为FlexibleInstances和UndecidableInstances。
2)您在实例中明确指定default_val
类型。这完全没必要,但如果你坚持,那么它也有一个名为ScopedTypeVariables的扩展名。
短
您可以使用language pragma逐个文件启用所需的扩展程序:
{-# LANGUAGE FlexibleInstance UndecidableInstances ScopedTypeVariables #-}
或者在ghc
或ghci
的命令行中(实际上它只是ghc
的包装):
ghci -XFLexibleInstances -XUnderstandMyIntent
同样,许多扩展都是以GHC为中心的。您的代码永远不会在任何其他Haskell编译器上运行,或者我的名字不是John Meacham。
答案 3 :(得分:0)
还有另一种解决方案:此处描述的约束族:
class Expr sem where
constraint Pre sem a
constant :: Pre sem a => a -> sem a
add :: Pre sem a => sem a -> sem a -> sem a
instance Expr E where
constraint Pre E a = Num a
...
它表示它可以在GHC HEAD或GHC 7.4(发布时)中使用。