Reputation: 37
I've got a little problem on recursion with data constructors.
data Proposition = Const Bool | Var [Char] | And Proposition Proposition | Or Proposition Proposition | Not Proposition deriving (Show, Eq)
simplify prop = whether (whether prop)
where whether x = case x of (Const a) -> x
(Var b) -> x
(And (Const y) (Const z)) -> if y && z then Const True else Const False
(And y z) -> And (simplify y)(simplify z)
(Or (Const y) (Const z)) -> if y || z then Const True else Const False
(Or y z) -> Or (simplify y)(simplify z)
(Not (Const c)) -> Const (not c)
(Not (Var b)) -> Not (Var b)
(Not (Not (Const c))) -> Const c
(Not x) -> Not (whether x)
So this is the code. The function is supposed to simplify expressions containing And, Or and Not. The function itself does what it should to single expressions. But it doesnt for expressions containing more than one And, Or or Not.
For example
simplify (Not (Const False)) == Const True
is true, but
simplify (Not (Var "var2" `Or` Const True))
only evaluates to
Not (Or (Var "var2") (Const True))
instead of Const False
I cannot get my head to find a solution, so a hint would be nice on how to get the function recursive. Thank you!
Upvotes: 1
Views: 388
Reputation: 7149
It is quite specific question, but I'll try to explain how I'd do it.
First of all you don't handle sufficient cases. Your program will "simplify" (Var "var2" `Or` Const True)
to (Var "var2" `Or` Const True)
, because it does not care whether second value is Const True
, while first is not Const _
.
I would write another program that will evaluate your Proposition
in 3-valued logics:
eval :: Proposition -> Maybe Bool
eval (Val _) = Nothing
eval (Const x) = Just x
eval (Or a b) = case (eval a, eval b) of
(Just True, _) -> Just True
(_, Just True) -> Just True
(Just False, Just False) -> Just False
_ -> Nothing -- because we don't know the resulting value
-- ...etc
And then perform simplification, for example
simplify o@(Or a b) = case (eval o) of
Just v -> Const v
Nothing -> Or (simplify a) (simplify b) -- we cannot simplify the `Or` usage
-- ...etc
This will greatly reduce cases that you need to check, and provide you and interpreter for your propositions as side effect. I believe it could be written more elegant using some Haskell's magic, but let's leave it as an exercise for a reader
Upvotes: 3
Reputation: 8227
You need to add some explicit matches for reducing constants:
(And (Const False) _) -> Const False
(And _ (Const False)) -> Const False
(And (Const True) x) -> x
(And x (Const True)) -> x
(Or (Const True) _) -> Const True
(Or _ (Const True)) -> Const True
(Or (Const False) x) -> x
(Or x (Const False)) -> x
There are some others that can be applied in a similar fashion.
Upvotes: 3