module Data.Katydid.Relapse.Exprs.Logic
( mkNotExpr
, notExpr
, mkAndExpr
, andExpr
, mkOrExpr
, orExpr
)
where
import Data.Katydid.Relapse.Expr
import Data.Katydid.Relapse.Exprs.Var
mkNotExpr :: [AnyExpr] -> Either String AnyExpr
mkNotExpr es = do
e <- assertArgs1 "not" es
b <- assertBool e
return $ mkBoolExpr (notExpr b)
notExpr :: Expr Bool -> Expr Bool
notExpr e = trimBool Expr
{ desc = notDesc (desc e)
, eval = \v -> case eval e v of
(Left _) -> return True
(Right b) -> return $ not b
}
notDesc :: Desc -> Desc
notDesc d
| _name d == "not"
= let child0 = head $ _params d in mkDesc (_name child0) (_params child0)
| _name d == "and"
= let [left, right] = _params d
in mkDesc "or" [mkDesc "not" [left], mkDesc "not" [right]]
| _name d == "or"
= let [left, right] = _params d
in mkDesc "and" [mkDesc "not" [left], mkDesc "not" [right]]
| _name d == "ne"
= mkDesc "eq" $ _params d
| _name d == "eq"
= mkDesc "ne" $ _params d
| otherwise
= mkDesc "not" [d]
mkAndExpr :: [AnyExpr] -> Either String AnyExpr
mkAndExpr es = do
(e1, e2) <- assertArgs2 "and" es
b1 <- assertBool e1
b2 <- assertBool e2
return $ mkBoolExpr $ andExpr b1 b2
andExpr :: Expr Bool -> Expr Bool -> Expr Bool
andExpr a b = case (evalConst a, evalConst b) of
(Just False, _ ) -> boolExpr False
(_ , Just False) -> boolExpr False
(Just True , _ ) -> b
(_ , Just True ) -> a
_ -> andExpr' a b
andExpr' :: Expr Bool -> Expr Bool -> Expr Bool
andExpr' a b
| a == b = a
| name a == "not" && head (params a) == desc b = boolExpr False
| name b == "not" && head (params b) == desc a = boolExpr False
| name a == "eq" && name b == "eq" = case (varAndConst a, varAndConst b) of
(Just ca, Just cb) -> if ca == cb then a else boolExpr False
_ -> defaultAnd a b
| name a == "eq" && name b == "ne" = case (varAndConst a, varAndConst b) of
(Just ca, Just cb) -> if ca == cb then boolExpr False else a
_ -> defaultAnd a b
| name a == "ne" && name b == "eq" = case (varAndConst a, varAndConst b) of
(Just ca, Just cb) -> if ca == cb then boolExpr False else b
_ -> defaultAnd a b
| otherwise = defaultAnd a b
defaultAnd :: Expr Bool -> Expr Bool -> Expr Bool
defaultAnd a b = Expr
{ desc = mkDesc "and" [desc a, desc b]
, eval = \v -> (&&) <$> eval a v <*> eval b v
}
varAndConst :: Expr Bool -> Maybe Desc
varAndConst e =
let ps = params e
in if length ps /= 2
then Nothing
else
let [a, b] = ps
in if isVar a && isConst b
then Just b
else if isVar b && isConst a then Just a else Nothing
mkOrExpr :: [AnyExpr] -> Either String AnyExpr
mkOrExpr es = do
(e1, e2) <- assertArgs2 "or" es
b1 <- assertBool e1
b2 <- assertBool e2
return $ mkBoolExpr $ orExpr b1 b2
orExpr :: Expr Bool -> Expr Bool -> Expr Bool
orExpr a b = case (evalConst a, evalConst b) of
(Just True , _ ) -> boolExpr True
(_ , Just True ) -> boolExpr True
(Just False, _ ) -> b
(_ , Just False) -> a
_ -> orExpr' a b
orExpr' :: Expr Bool -> Expr Bool -> Expr Bool
orExpr' a b
| a == b = a
| name a == "not" && head (params a) == desc b = boolExpr True
| name b == "not" && head (params b) == desc a = boolExpr True
| otherwise = Expr
{ desc = mkDesc "or" [desc a, desc b]
, eval = \v -> (||) <$> eval a v <*> eval b v
}