import Control.Arrow
import Prelude hiding (not, and, or, Bool)
unit :: (a, ()) -> a
unit (x, ()) = x
distr :: (a, Either b c) -> Either (a, b) (a, c)
distr (x, Left y) = Left (x, y)
distr (x, Right y) = Right (x, y)
type Bool = Either () ()
true, false :: () -> Bool
true = Left
false = Right
quad :: (Bool, Bool) -> (Either () (Either () (Either () ())))
quad (Left (), Left ()) = Left ()
quad (Left (), Right ()) = Right (Left ())
quad (Right (), Left ()) = Right (Right (Left ()))
quad (Right (), Right ()) = Right (Right (Right ()))
not :: Bool -> Bool
not = false ||| true
and :: (Bool, Bool) -> Bool
and = quad >>> true ||| false ||| false ||| false
or :: (Bool, Bool) -> Bool
or = quad >>> true ||| true ||| true ||| false
cond :: (a -> Bool) -> (a -> b, a -> b) -> a -> b
cond p (f, g) = (id &&& p) >>> distr >>> (unit +++ unit) >>> (f ||| g)
printBool (Left ()) = putStr "true"
printBool (Right ()) = putStr "false"
main' = false &&& true >>> cond (and >>> not) (or, and) >>> printBool
main = main' ()