Включение равенства в соответствие шаблону Haskell

Я пишу функцию для упрощения булевого выражения. Например, Nand(A, A) == Not(A). Я попытался реализовать это правило с помощью сопоставления с образцом, например:

-- Operands equivalent - simplify!
simplify (Nand q q) = Not (simplify q)
-- Operands must be different, so recurse.
simplify (Nand q q') = Nand (simplify q) (simplify q')

При компиляции я получаю сообщение об ошибке:

Conflicting definitions for `q'
Bound at: boolean.hs:73:21
          boolean:73:29
In an equation for `simplify'

Я думаю, что понимаю, что происходит, и я работал над этим, но я просто хотел бы знать:

  • Почему такое сопоставление шаблонов невозможно?
  • Есть ли идиоматическое обходное решение?

Полное раскрытие: это связано с домашним заданием, но цель курса - не изучать Haskell, и я все равно решил его по-своему.

Ответ 1

Вы можете придерживаться своего оригинального стиля:

-- Operands equivalent - simplify!
simplify (Nand q q') | q == q' = Not (simplify q)
-- Operands must be different, so recurse.
simplify (Nand q q') = Nand (simplify q) (simplify q')

Кроме того, я думаю, вы должны упростить перед тестированием равенства, а не после:

simplify (Nand q q') = if qs == qs' then Not qs else Nand qs qs' where
    qs = simplify q
    qs' = simplify q'

Ответ 2

Решение, которое я нашел, это использовать защитные устройства для проверки равенства подструктур:

simplify (Nand q q')
    -- Operands equivalent - simplify!
    | q == q' = Not (simplify q)
    -- Operands different - recurse.
    | otherwise = Nand (simplify q) (simplify q')

Ответ 3

"Ответ" заключается в том, что вам не разрешается указывать одну и ту же переменную дважды в шаблоне. Так или иначе, в Хаскелле. Лучший способ решить эту проблему - тот, который вы уже обнаружили, - используйте шаблоны для проверки равенства или неравенства.