为什么在Haskell中的实例定义中期望构造函数

时间:2011-09-23 01:10:12

标签: class haskell instance

任何人都可以解释这个错误:

实例头中的语法错误(构造函数预期)

class Nullable v where
  default_val :: v


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

由于

4 个答案:

答案 0 :(得分: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)

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提供的扩展程序为FlexibleInstancesUndecidableInstances

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

您可以使用language pragma逐个文件启用所需的扩展程序:

{-# LANGUAGE FlexibleInstance UndecidableInstances ScopedTypeVariables #-}

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

ghci -XFLexibleInstances -XUnderstandMyIntent

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

答案 3 :(得分:0)

还有另一种解决方案:此处描述的约束族:

http://dorchard.wordpress.com/2011/09/22/constraint-kinds-in-haskell-finally-bringing-us-constraint-families/

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(发布时)中使用。