我有以下代数数据类型:
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
的平等表达式。
如何仅针对这些实例更改(==)
,而无需为所有其他实例指定(==)
的行为?
答案 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
让你定义所有在结构上相等的表达式,除了函数到参数的应用,它们只是名称相同(可能有用也可能没用)。