Похоже, вы обычно хотите следовать шаблону
- Упростить все подвыражения.
- Упростить выражение.
Для меня,это предполагает пакет recursion-schemes
.
{-# language TemplateHaskell, TypeFamilies, DeriveTraversable #-}
import Data.Functor.Foldable
import Data.Functor.Foldable.TH
data Proposition
= Const Bool
| Var String
| And Proposition Proposition
| Or Proposition Proposition
| Not Proposition
deriving (Show, Eq)
makeBaseFunctor ''Proposition
Это волшебным образом генерирует тип
data PropositionF x
= ConstF Bool
| VarF String
| AndF x x
| OrF x x
| NotF x
deriving (Functor, Foldable, Traversable)
вместе с некоторыми связанными экземплярами.Обратите внимание, что PropositionF
заменяет каждое вхождение Proposition
копией параметра типа.Теперь вы можете написать
simplify :: Proposition -> Proposition
simplify = cata go
where
go :: PropositionF Proposition -> Proposition
go (AndF (Const True) x) = x
go (AndF f@(Const False) _) = f
go (AndF x (Const True)) = x
go (AndF _ f@(Const False)) = f
go (OrF t@(Const True) _) = t
go (OrF (Const False) x) = x
go (OrF _ t@(Const True)) = t
go (OrF x (Const False)) = x
go (NotF (Const x)) = Const (not x)
go x = embed x -- Catch-all: no rules apply
Все рекурсивное упрощение обрабатывается «автоматически», а все случаи «ничего интересного здесь» обрабатываются в одну строку.