在Haskell中覆盖(==)

时间:2011-05-10 08:32:36

标签: haskell types typeclass algebraic-data-types

我有以下代数数据类型:

data Exp
  = Con Int
  | Var String
  | Op Opkind Exp Exp
  | Input
  deriving (Show,Eq)

data Opkind
  = Plus | Minus | Mult | Div | More | Equal
  deriving (Show,Eq)

用简单的玩具语言表示表达。

但是,因为我导出Eq,Op Plus (Var "a") (Var "b)不等于Op Plus (Var "b") (Var "a"),即使我想将a+b视为b+a的平等表达式。

如何仅针对这些实例更改(==),而无需为所有其他实例指定(==)的行为?

2 个答案:

答案 0 :(得分:18)

你可以通过使Exp成为Eq的实例而不是导出Eq:

来实现这一点
instance Eq Exp where
    (Con a) == (Con b) = a == b
    (Var a) == (Var b) = a == b
    (Op Plus a b) == (Op Plus c d) = (a == c && b == d) || (a == d && c == b)
    Input == Input = True
    _ == _ = False

这会按照想要的方式比较Op Plus,但仍然缺少Op的其他案例

修改

在Op上实现(==)特殊情况而不会丢失Exp的派生的最简单方法,我想到的就是这样:

data Exp
  = Con Int
  | Var String
  | EOp Op
  | Input
  deriving (Show, Eq)

data Op = Op Opkind Exp Exp deriving (Show)
instance Eq Op where
    (Op Plus e1 e2) == (Op Plus e3 e4) = (e1 == e3 && e2 == e4) || ( e1 == e4 && e2 == e3)
    (Op kind1 e1 e2) == (Op kind2 e3 e4) = and [kind1 == kind2, e1 == e3, e2 == e4]

答案 1 :(得分:8)

如果您想要Op的自定义行为,但是您的数据类型的所有其他变体的常规行为,则需要将Op分解为自己的类型。

例如:

data Exp
  = Con Int
  | Var String
  | Input
  | PrimOp Op
  deriving (Show,Eq)

data Op = Op Opkind Exp Exp
  deriving Show

data Opkind
  = Plus | Minus | Mult | Div | More | Equal
  deriving (Show,Eq) 

-- equality on (symbolic) functions, perhaps?
instance Eq Op where
  (Op a _ _) == (Op b _ _) = a == b

让你定义所有在结构上相等的表达式,除了函数到参数的应用,它们只是名称相同(可能有用也可能没用)。