谁能解释这个错误:(构造函数预期)为什么构造预计在实例定义在Haskell
语法错误的情况下头部
class Nullable v where
default_val :: v
instance Num a => Nullable a where -- error reported here
default_val = 0::a
感谢
谁能解释这个错误:(构造函数预期)为什么构造预计在实例定义在Haskell
语法错误的情况下头部
class Nullable v where
default_val :: v
instance Num a => Nullable a where -- error reported here
default_val = 0::a
感谢
其次,不写形式
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。有一个真正的诱惑,只要翻转GHC告诉你的语言标志。阅读@ ezyang的Type Technology Tree后,我发现自己能够做出更好的决定:http://blog.ezyang.com/2011/03/type-tech-tree/ – acfoltzer
有在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
,这在这里没有任何意义。
对于':: a'的显式类型,您可以使用范围类型变量扩展。 –
这是否适用于实例?我没有在GHC文档中看到它(也许我正在寻找错误的地方)并尝试使用'forall'语法似乎不起作用。 – Dan
它适合我。 –
讨论
您的代码是无效的Haskell。不要误会我的意思 - 它是Haskell社区常见的形式,可以由GHC编译,但我强烈建议您不要将“Haskell”与“Haskell以及GHC可提供的所有扩展”混为一谈。
1)您正在使用另一个类型类作为约束实例化一个类型类,并且没有类型构造函数。 2010年哈斯克尔,你必须有一个类型构造:
The general form of the corresponding instance declaration is: instance cx′ => C (T u1 … uk) where { d } where k ≥ 0. The type (T u1 … uk) must take the form of a type constructor T applied to simple type variables u1, … uk; furthermore, T must not be a type synonym, and the ui must all be distinct.
GHC提供了这里的扩展是FlexibleInstances和UndecidableInstances。
2)您在您的实例中明确给default_val
一个类型。这完全是不必要的,但如果你坚持,那么这也有一个名为ScopedTypeVariables的扩展名。
需要可以启用或者在一个文件通过文件的基础上短期
的扩展使用language pragma:
{-# LANGUAGE FlexibleInstance UndecidableInstances ScopedTypeVariables #-}
或者在任ghc
或ghci
的命令行(其中实际上只是一个包装ghc
):
ghci -XFLexibleInstances -XUnderstandMyIntent
再次,许多扩展是以GHC为中心的。你的代码永远不会在任何其他Haskell编译器上运行,或者我的名字不是John Meacham。
还有另一种解决方案:这里所描述的约束家庭:
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(释放时)。
我不能重现这个错误 - 我得到一个非法的实例声明错误,而不是语法错误。 –
@Daniel:这个错误出现在拥抱中。 – sdcvvc