изменить: дать реальный ответ на вопрос ...
Я считаю, что самый простой способ увидеть, какие шаблоны соответствуют друг другу, это добавить trace
операторов, например, так:
import Debug.Trace
instance Eq Expr where
(Add (Const a1) (Const a2)) == Const b = trace "Expr Eq pat 1" $ a1+a2 == b
(Add (Const a1) (Const a2)) == (Add (Const b1) (Const b2)) = trace "Expr Eq pat 2" $ a1+a2 == b1 + b2
-- catch any unmatched patterns
l == r = error $ "Expr Eq failed pattern match. \n l: " ++ show l ++ "\n r: " ++ show r
Если вы не включите окончательный оператор для отлова каких-либо несопоставимых шаблонов, вы получите исключение времени выполнения, но я считаю, что более полезно посмотреть, какие данные вы получаете. Тогда обычно просто понять, почему он не соответствует предыдущим шаблонам.
Конечно, вы не хотите оставлять это в рабочем коде. Я только вставляю следы по мере необходимости, затем удаляю их, когда закончу. Вы также можете использовать CPP, чтобы исключить их из производственных сборок.
Я также хочу сказать, что я считаю, что сопоставление с образцом - неправильный путь для этого. Вы закончите комбинаторным взрывом числа паттернов, который быстро становится неуправляемым. Если вы хотите сделать экземпляр Float
для Expr
, например, вам понадобится еще несколько примитивных конструкторов.
Вместо этого, вы, вероятно, имеете функцию интерпретатора interpret :: Expr -> Double
, или, по крайней мере, можете написать ее. Тогда вы можете определить
instance Eq Expr where
l == r = interpret l == interpret r
Путем сопоставления с образцом вы по существу переписываете свою интерпретирующую функцию в экземпляре Eq
. Если вы хотите создать экземпляр Ord
, вам придется переписать функцию интерпретации еще раз.