在Haskell中为自定义数据类型创建Eq实例

时间:2016-11-19 16:07:10

标签: haskell typeclass instances custom-type

我已经在Haskell中为数字表示制作了一些自定义数据类型,现在我想为它实现Eq实例,但我不知何故被卡住了。所以我已经做过:

data Digit = Zero | One | Two
type Digits = [Digit]
data Sign = Pos | Neg -- Pos fuer Positive, Neg fuer Negative
newtype Numeral = Num (Sign,Digits)

instance Eq Sign where
(==) Pos Pos = True
(==) Neg Neg = True
(==) _ _ = False

instance Eq Digit where
(==) Zero Zero = True
(==) One One = True
(==) Two Two = True
(==) _ _ = False

现在我想查看登录我的自定义类型Numeral,所以我尝试了这个:

instance (Eq Sign) => Eq (Numeral) where
(==) Num(x,_)== Num(y,_) = x==y

但是我得到了这个错误:模式中的解析错误:(==)

1 个答案:

答案 0 :(得分:4)

主要是将我已经写在评论中的内容更加充实地展示出来:

您的代码存在一些问题:

  1. 您必须在instance声明下缩进代码。这样就告诉编译器什么代码属于实例声明。
  2. 在以下行中,您要求在具体类型(Eq Sign =>)上使用类型类约束。这在标准Haskell中是不可能的,即使您按照编译器指令并启用FlexibleInstances语言扩展也没有意义。

    instance (Eq Sign) => Eq (Numeral) where
    

    类型类约束仅用于类型变量。例如:

    double :: Num a => a -> a
    double x = x + x
    

    我们说,函数double仅适用于实现Num的所有类型。另一方面,double :: Num Int => Int -> Int是多余的,因为我们已经知道,IntNum个实例。 Eq Sign也一样。

    对于实例,这样的约束才有意义,如果您正在编写实例的类型包含另一个多态类型。 Fox示例instance Ord a => Ord [a]。在这里,我们将使用列表元素的Ord实例来按顺序排列列表。

  3. 您可以以中缀或前缀形式定义(==),但不能同时定义两者。因此,(==) (Num (x,_)) (Num (y,_)) = x == yNum (x,_) == Num (y,_) = x == y

  4. 用于创建产品类型的Newtyping元组相当奇怪。如果要使用已存在的更复杂底层类型的功能,通常会使用Newtypes。但是,情况并非如此,您只需要DigitsSign的正常产品。

  5. 您只是比较数字的Sign。虽然从技术上讲是一个有效的Eq实例,但我想你也想比较这个数字的数字,可能会截断前导零。在下面的代码中,我没有截断零,以保持简单。

  6. data Digit = Zero | One | Two
    type Digits = [Digit]
    data Sign = Pos | Neg
    data Numeral = Num Sign Digits
    
    instance Eq Sign where
      (==) Pos Pos = True
      (==) Neg Neg = True
      (==) _ _ = False
    
    instance Eq Digit where
      (==) Zero Zero = True
      (==) One One = True
      (==) Two Two = True
      (==) _ _ = False
    
    instance Eq Numeral where
      Num s1 x1 == Num s2 x2 = s1 == s2 && x1 == x2