2011-09-23 46 views
1

谁能解释这个错误:(构造函数预期)为什么构造预计在实例定义在Haskell

语法错误的情况下头部

class Nullable v where 
    default_val :: v 


instance Num a => Nullable a where -- error reported here 
    default_val = 0::a 

感谢

+0

我不能重现这个错误 - 我得到一个非法的实例声明错误,而不是语法错误。 –

+0

@Daniel:这个错误出现在拥抱中。 – sdcvvc

回答

8

首先,hackage has you covered

其次,不写形式

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。有一个真正的诱惑,只要翻转GHC告诉你的语言标志。阅读@ ezyang的Type Technology Tree后,我发现自己能够做出更好的决定:http://blog.ezyang.com/2011/03/type-tech-tree/ – acfoltzer

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,这在这里没有任何意义。

+0

对于':: a'的显式类型,您可以使用范围类型变量扩展。 –

+0

这是否适用于实例?我没有在GHC文档中看到它(也许我正在寻找错误的地方)并尝试使用'forall'语法似乎不起作用。 – Dan

+0

它适合我。 –

1

讨论

您的代码是无效的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提供了这里的扩展是FlexibleInstancesUndecidableInstances

2)您在您的实例中明确给default_val一个类型。这完全是不必要的,但如果你坚持,那么这也有一个名为ScopedTypeVariables的扩展名。

需要可以启用或者在一个文件通过文件的基础上短期

的扩展使用language pragma

{-# LANGUAGE FlexibleInstance UndecidableInstances ScopedTypeVariables #-} 

或者在任ghcghci的命令行(其中实际上只是一个包装ghc):

ghci -XFLexibleInstances -XUnderstandMyIntent 

再次,许多扩展是以GHC为中心的。你的代码永远不会在任何其他Haskell编译器上运行,或者我的名字不是John Meacham。

相关问题