Переопределение (==) в Haskell
У меня есть следующие типы алгебраических данных:
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
.
Как мне изменить (==)
только для этих экземпляров, не указывая поведение (==)
для всех остальных экземпляров?
Ответы
Ответ 1
Вы можете добиться этого, сделав 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.
Edit:
Самый простой способ реализовать специальные случаи для (==) на 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]
Ответ 2
Если вы хотите настраивать поведение для 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
Позвольте вам определить все выражения структурно равными, за исключением приложений функций к аргументам, которые являются равными только по имени (что может быть или не быть полезным).