> module WeberLogic.Actions (
>   toNand, toNor, truthTree,
>   and, or, implies, iff, nand, nor, isConsistent,
>   truthTableStrs, truthTableValues) 
> where
> import Prelude hiding (and, or)
> import Text.Printf
> import Data.List (union)
> import WeberLogic.Parser
> instance Show Letter where
>     show exp =
>         case exp of
>             Name a          -> [a]
>             Variable a      -> [a]
> instance Eq Letter where
>     (==) exp1 exp2 =
>         case (exp1, exp2) of
>             (Name a, Name b)         -> a == b
>             (Variable a, Variable b) -> a == b
>             (_, _)                   -> False   
> instance Show LogicExp where
>     show exp =
>         case exp of
>             Not a           -> printf "~%s" (show a)
>             Or a b          -> printf "(%s+%s)" (show a) (show b)
>             Xor a b         -> printf "(%s⊕%s)" (show a) (show b)
>             And a b         -> printf "(%s&%s)" (show a) (show b)
>             Implies a b     -> printf "(%s->%s)" (show a) (show b)
>             Iff a b         -> printf "(%s<->%s)" (show a) (show b)
>             Nand a b        -> printf "(%s|%s)" (show a) (show b)
>             Nor a b         -> printf "(%s/%s)" (show a) (show b)
>             Predicate a bs  -> printf "%c%s" a $ concatMap (show) bs
> instance Eq LogicExp where
>     (==) exp1 exp2 =
>         case (exp1, exp2) of
>             (Predicate a as, Predicate b bs) -> a == b && as == bs
>             (Not a, Not b)                   -> a == b
>             (Or a b, Or c d)                 -> a == c && b == d
>             (Xor a b, Xor c d)               -> a == c && b == d
>             (And a b, And c d)               -> a == c && b == d
>             (Implies a b, Implies c d)       -> a == c && b == d
>             (Iff a b, Iff c d)               -> a == c && b == d
>             (Nand a b, Nand c d)             -> a == c && b == d
>             (Nor a b, Nor c d)               -> a == c && b == d
>             (_, _)                           -> False
> lmap :: (LogicExp -> LogicExp) -> LogicExp -> LogicExp
> lmap f exp =
>     case exp of 
>         Not a          -> f $ Not (lmap f a)
>         Or a b         -> f $ Or (lmap f a) (lmap f b)
>         And a b        -> f $ And (lmap f a) (lmap f b)
>         Xor a b        -> f $ Xor (lmap f a) (lmap f b)
>         Implies a b    -> f $ Implies (lmap f a) (lmap f b)
>         Iff a b        -> f $ Iff (lmap f a) (lmap f b)
>         Nand a b       -> f $ Nand (lmap f a) (lmap f b)
>         Nor a b        -> f $ Nor (lmap f a) (lmap f b)
>         Predicate a bs -> f exp 
> toNand :: LogicExp -> LogicExp
> toNand exp = lmap (toNand') exp
>     where toNand' e = case e of
>             Not a       -> a `Nand` a
>             Or a b      -> (a `Nand` a) `Nand` (b `Nand` b)
>             And a b     -> (a `Nand` b) `Nand` (a `Nand` b)
>             Nand a b    -> a `Nand` b
>             Nor a b     -> ((a `Nand` a) `Nand` (b `Nand` b)) `Nand` 
>                                ((a `Nand` a) `Nand` (b `Nand` b))
>             Implies a b -> toNand $ Or (toNand $ Not a) b
>             Iff a b     -> toNand $ (a `Implies` b) `And` (b `Implies` a)
>             _           -> e
> toNor :: LogicExp -> LogicExp
> toNor exp = lmap (toNor') exp
>     where toNor' e = case e of
>             Not a       -> a `Nor` a
>             Or a b      -> (a `Nor` b) `Nor` (a `Nor` b)
>             And a b     -> (a `Nor` a) `Nor` (b `Nor` b)
>             Nor a b     -> a `Nor` b
>             Nand a b    -> ((a `Nor` a) `Nor` (b `Nor` b)) `Nor` 
>                                ((a `Nor` a) `Nor` (b `Nor` b))
>             Implies a b -> toNor $ Or (toNor $ Not a) b
>             Iff a b     -> toNor $ (a `Implies` b) `And` (b `Implies` a)
>             _           -> e
> decompose :: [LogicExp] -> [[LogicExp]]
> decompose es = decompose' es []
> decompose' :: [LogicExp] -> [LogicExp] -> [[LogicExp]]
> decompose' exps as 
>     | null exps = [as]
>     | otherwise = let (e:es) = exps
>         in case e of
>            Predicate _ _      -> decompose' es (e:as)
>            Not(Predicate _ _) -> decompose' es (e:as)
>            And x y            -> decompose' (x:y:es) as 
>            Or x y             -> (decompose' (x:es) as) ++ (decompose' (y:es) as)
>            Implies x y        -> (decompose' ((Not x):es) as) ++ (decompose' (y:es) as)
>            Iff x y            -> decompose' (Or (And x y) (And (Not x) (Not y)):es) as
>            Not(And x y)       -> (decompose' ((Not x):es) as) ++ (decompose' ((Not y):es) as)
>            Not(Or x y)        -> decompose' ((Not x):(Not y):es) as 
>            Not(Implies x y)   -> decompose' ((And x (Not y)):es) as
>            Not(Iff x y)       -> decompose' (Or (And x y) (And (Not x) (Not y)):es) as
> isConsistent :: [LogicExp] -> Bool
> isConsistent es = isConsistent' es []
> isConsistent' :: [LogicExp] -> [LogicExp] -> Bool
> isConsistent' exps as 
>     | null exps = True
>     | otherwise = let (e:es) = exps
>         in case e of
>            Predicate _ _       -> if elem (Not e) as then False else isConsistent' es (e:as)
>            Not(Predicate x xs) -> if elem (Predicate x xs) as then False else isConsistent' es (e:as)
>            And x y             -> isConsistent' (x:y:es) as 
>            Or x y              -> (isConsistent' (x:es) as) || (isConsistent' (y:es) as)
>            Implies x y         -> (isConsistent' ((Not x):es) as) || (isConsistent' (y:es) as)
>            Iff x y             -> isConsistent' (Or (And x y) (And (Not x) (Not y)):es) as
>            Not(And x y)        -> (isConsistent' ((Not x):es) as) || (isConsistent' ((Not y):es) as)
>            Not(Or x y)         -> isConsistent' ((Not x):(Not y):es) as 
>            Not(Implies x y)    -> isConsistent' ((And x (Not y)):es) as
>            Not(Iff x y)        -> isConsistent' (Or (And x y) (And (Not x) (Not y)):es) as
> truthTree :: [LogicExp] -> IO()
> truthTree es = do 
>         printf "%s\n" $ show es 
>         truthTree' es [] 0
> truthTree' :: [LogicExp] -> [LogicExp] -> Int -> IO()
> truthTree' exps as indent = do
>   if null exps 
>   then print "Open" indent
>   else let (e:es) = exps
>     in do 
>       print (show e) indent
>       case e of
>         Predicate x xs      -> if elem (Not e) as 
>                              then print "Closed" indent
>                              else truthTree' es (e:as) indent
> 
>         Not(Predicate x xs) -> if elem (Predicate x xs) as 
>                              then print "Closed" indent
>                              else truthTree' es (e:as) indent
> 
>         Not(Not x)       -> truthTree' (x:es) as indent
> 
>         And x y          -> truthTree' (x:y:es) as indent
> 
>         Or x y           -> do 
>                               truthTree' (x:es) as (indent+1)
>                               truthTree' (y:es) as (indent+1)
> 
>         Implies x y      -> let z = Or (Not x) (y)
>                               in truthTree' (z:es) as indent
> 
>         Iff x y          -> let z = Or (And x y) (And (Not x) (Not y)) 
>                               in truthTree' (z:es) as indent
> 
>         Not(And x y)     -> let z = Or (Not x) (Not y) 
>                               in truthTree' (z:es) as indent
> 
>         Not(Or x y)      -> let z = And (Not x) (Not y) 
>                               in truthTree' (z:es) as indent
> 
>         Not(Implies x y) -> let z = Or (Not x) y
>                               in truthTree' (z:es) as indent
> 
>         Not(Iff x y)     -> let z = Or (And x y) (And (Not x) (Not y))
>                               in truthTree' (z:es) as indent
> 
>     where print str indent = printf "%s%s\n" (replicate (indent*2) ' ') str
> evalutateBinary :: (Bool -> Bool -> Bool) -> LogicExp -> LogicExp -> 
>                    [(LogicExp, Bool)] -> Bool
> evalutateBinary operator exp1 exp2 xs = exp1' `operator` exp2'
>     where exp1' = evaluate exp1 xs;
>           exp2' = evaluate exp2 xs
> evaluate :: LogicExp -> [(LogicExp, Bool)] -> Bool
> evaluate exp xs =
>     case exp of 
>         Predicate a as -> if exp == c then v else evaluate exp xs'
>                           where ((c,v):xs') = xs
>         Not a          -> not $ evaluate a xs
>         And a b        -> evalutateBinary and a b xs
>         Or a b         -> evalutateBinary or a b xs
>         Xor a b        -> evalutateBinary xor a b xs
>         Nand a b       -> evalutateBinary nand a b xs
>         Nor a b        -> evalutateBinary nor a b xs
>         Implies a b    -> evalutateBinary implies a b xs
>         Iff a b        -> evalutateBinary iff a b xs
> and :: Bool -> Bool -> Bool
> and True True = True
> and _    _    = False
> or :: Bool -> Bool -> Bool
> or True _    = True
> or _    True = True
> or _    _    = False
> implies :: Bool -> Bool -> Bool
> implies True False = False
> implies _    _     = True
> iff :: Bool -> Bool -> Bool
> iff True  True  = True
> iff False False = True
> iff _     _     = False
> xor :: Bool -> Bool -> Bool
> xor False False = False
> xor True  True  = False
> xor _     _     = True
> nand :: Bool -> Bool -> Bool
> nand x y = not (x `and` y)
> nor :: Bool -> Bool -> Bool
> nor x y = not (x `or` y)
> truthTableStrs :: LogicExp -> [String]
> truthTableStrs exp = 
>   let (predicates, values, results) = truthTableValues exp 
>       header_lhs = concatMap (printf "%-5s " . show) predicates
>       header_rhs = printf "| %-5s" $ show exp 
>       header     = header_lhs ++ header_rhs
>       rows_lhs   = map (concatMap (printf "%-5s " . show)) values
>       rows_rhs   = map (printf "| %-5s" . show) results
>       rows       = zipWith (++) rows_lhs rows_rhs
>   in header : rows
> truthTableValues :: LogicExp -> ([LogicExp], [[Bool]], [Bool])
> truthTableValues exp = 
>   let (_, _, preds) = getBasics exp
>       pred_values   = map (zip preds) (perm (length preds) [True, False])
>       values        = map (map (snd)) pred_values
>       results       = map (evaluate exp) pred_values
>   in (preds, values, results)
> perm i xs | i > 0 = [ x:ys | x <- xs, ys <- perm (i-1) xs]
>           | otherwise = [[]]
> --                       ([Names],  [Variables], [Predicates])
> getBasics :: LogicExp -> ([Letter], [Letter], [LogicExp])
> getBasics exp = 
>     case exp of 
>         Predicate a bs -> foldl sumTuples ([], [], [exp]) $ map toTuple bs
>             where toTuple p = case p of
>                     Name a     -> ([p], [], [])
>                     Variable a -> ([], [p], [])
>         Not a          -> getBasics a
>         Nor a b        -> sumTuples (getBasics a) (getBasics b)
>         Nand a b       -> sumTuples (getBasics a) (getBasics b)
>         And a b        -> sumTuples (getBasics a) (getBasics b)
>         Or a b         -> sumTuples (getBasics a) (getBasics b)
>         Xor a b        -> sumTuples (getBasics a) (getBasics b)
>         Iff a b        -> sumTuples (getBasics a) (getBasics b)
>         Implies a b    -> sumTuples (getBasics a) (getBasics b)
>     where sumTuples (xs1, xs2,  xs3) (ys1, ys2, ys3) = 
>             ((xs1 `union` ys1), (xs2 `union` ys2), (xs3 `union` ys3))