在Haskell中覆盖(==)

oad*_*ams 13 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)
Run Code Online (Sandbox Code Playgroud)

这表示用简单的玩具语言表达.

但是,因为我得出了Eq,即使我想把它视为一个平等的表达式,Op Plus (Var "a") (Var "b)也不算等于.Op Plus (Var "b") (Var "a")a+bb+a

如何更改(==)这些实例,而不必指定(==)所有其他实例的行为?

Jak*_*nge 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
Run Code Online (Sandbox Code Playgroud)

这将以所需的方式比较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]
Run Code Online (Sandbox Code Playgroud)


Don*_*art 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
Run Code Online (Sandbox Code Playgroud)

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

  • +1.虽然您的特定Eq实例不一定适合OP的需要,但将其拆分为自己的数据类型的技术当然是. (2认同)