texShow prec = \case
Nd "forall" [Txt v, t] -> showParen (prec > 0) $ tex "forall" . (v++) . ('.':) . texShow 0 t
Nd "exists" [Txt v, t] -> showParen (prec > 0) $ tex "exists". (v++) . ('.':) . texShow 0 t
Nd "<=>" [a, b] -> showParen (prec > 1) $ texShow 2 a . tex "iff" . texShow 2 b
Nd "=>" [a, b] -> showParen (prec > 2) $ texShow 3 a . tex "implies" . texShow 2 b
Nd "+" [a, b] -> showParen (prec > 3) $ texShow 3 a . tex "vee" . texShow 3 b
Nd "*" [a, b] -> showParen (prec > 4) $ texShow 4 a . tex "wedge" . texShow 4 b
Nd "@" [a, b] -> showParen (prec > 5) $ texShow 5 a . tex "" . texShow 6 b
Nd "~" [a] -> showParen (prec > 6) $ tex "neg" . texShow 6 a
Txt s -> (s++)
where tex s = ('\\':) . (s++) . (' ':)
nandShow x = foldr1 (.) $ intersperse ("; "++) $ f:defs where
(f, defs) = runState (go x) []
addDef f = get >>= put . (f:)
go = \case
Nd "NAND" [a, b] -> showParen True <$> ((.) <$> go a <*> go b)
Nd "=" [Txt v, a] -> do
addDef . ((v++) . ('=':) .) =<< go a
pure (v++)
Nd "UNAND" [Txt v, a, b] -> do
goA <- go a
goB <- go b
pure $ showParen True $ (v++) . ('.':) . goA . (" "++) . goB
Nd "@" [a, b] -> do
goA <- go a
goB <- go b
pure $ showParen True $ goA . (" "++) . goB
Txt s -> pure (s++)
nandify = \case
Nd "<=>" [a, b] -> nandify $ Nd "*" [Nd "=>" [a, b], Nd "=>" [b, a]]
Nd "=>" [a, b] -> nandify $ Nd "+" [anti a, b]
Nd "+" [a, b] -> nand (nandify $ anti a) (nandify $ anti b)
Nd "*" [a, b] -> nandify $ anti $ nand (nandify a) (nandify b)
Nd "~" [x] -> case x of
Nd "*" [a, b] -> nand (nandify a) (nandify b)
a -> nand na na where na = nandify a
t -> t
where
nand a b = Nd "NAND" [a, b]
anti = \case
Nd "~" [a] -> a
a -> Nd "~" [a]
shareNandify x = evalState (go x) 0 where
share a = case a of
Txt _ -> pure (a, a)
_ -> do
k <- get
put $ k + 1
let v = Txt $ show k
ga <- go a
pure (Nd "=" [v, ga], v)
go = \case
Nd "=" [v, a] -> Nd "=" . (v:) . (:[]) <$> go a
Nd "<=>" [a, b] -> do
(defA, refA) <- share a
(defB, refB) <- share b
go $ Nd "*" [Nd "=>" [defA, defB], Nd "=>" [refB, refA]]
Nd "=>" [a, b] -> go $ Nd "+" [anti a, b]
Nd "+" [a, b] -> nand <$> go (anti a) <*> go (anti b)
Nd "*" [a, b] -> go . anti =<< nand <$> go a <*> go b
Nd "~" [x] -> case x of
Nd "*" [a, b] -> nand <$> go a <*> go b
a -> do
(def, ref) <- share =<< go a
pure $ nand def ref
t -> pure t
nand a b = Nd "NAND" [a, b]
elimExists = \case
Nd "exists" [Txt v, t] -> anti $ Nd "forall" [Txt v, anti t]
Nd f xs -> Nd f $ elimExists <$> xs
t -> t
unandify = go . elimExists where
go = \case
Nd "forall" [Txt v, t] -> case t of
Nd "+" [a, b] -> unand v (go $ anti a) (go $ anti b)
Nd "~" [Nd "*" [a, b]] -> unand v (go a) (go b)
Nd "~" [a] -> unand v ua ua where ua = go a
_ -> unand v n n where n = go $ anti t
Nd "<=>" [a, b] -> go $ Nd "*" [Nd "=>" [a, b], Nd "=>" [b, a]]
Nd "=>" [a, b] -> go $ Nd "+" [anti a, b]
Nd "+" [a, b] -> unand "_" (go $ anti a) (go $ anti b)
Nd "*" [a, b] -> go $ anti $ unand "_" (go a) (go b)
Nd "~" [x] -> case x of
Nd "*" [a, b] -> unand "_" (go a) (go b)
a -> unand "_" ua ua where ua = go a
t -> t
unand v a b = Nd "UNAND" [Txt v, a, b]
shareUnandify = (`evalState` 0) . go . elimExists where
share a = case a of
Txt _ -> pure (a, a)
_ -> do
k <- get
put $ k + 1
let v = Txt $ show k
ga <- go a
pure (Nd "=" [v, ga], v)
go = \case
Nd "forall" [Txt v, t] -> case t of
Nd "+" [a, b] -> unand v <$> go (anti a) <*> go (anti b)
Nd "~" [Nd "*" [a, b]] -> unand v <$> go a <*> go b
Nd "~" [a] -> fmap (uncurry $ unand v) . share =<< go a
_ -> fmap (uncurry $ unand v) . share =<< go (anti t)
Nd "<=>" [a, b] -> do
(defA, refA) <- share a
(defB, refB) <- share b
go $ Nd "*" [Nd "=>" [defA, defB], Nd "=>" [refB, refA]]
Nd "=>" [a, b] -> go $ Nd "+" [anti a, b]
Nd "+" [a, b] -> unand "_" <$> go (anti a) <*> go (anti b)
Nd "*" [a, b] -> go . anti =<< unand "_" <$> go a <*> go b
Nd "~" [x] -> case x of
Nd "*" [a, b] -> unand "_" <$> go a <*> go b
a -> fmap (uncurry $ unand "_") . share =<< go a
t -> pure t
unand v a b = Nd "UNAND" [Txt v, a, b]
unandLamb = \case
Nd "UNAND" [Txt v, a, b] -> Nd "U" [] # lamb v a # lamb v b
Nd "@" as -> Nd "@" $ unandLamb <$> as
t -> t
where
f # x = Nd "@" [f, x]
lamb v a = Nd "\\" [Txt v, unandLamb a]
lambShow prec = \case
Nd "\\" [Txt v, a] -> showParen (prec > 0) $ ("\\"++) . (v++) . (" -> "++) . lambShow 0 a
Nd "@" [a, b] -> showParen (prec > 1) $ lambShow 1 a . (' ' :) . lambShow 2 b
Nd s [] -> (s++)
Txt s -> (s++)
combShow prec = \case
Nd "@" [a, b] -> showParen (prec > 0) $ combShow 0 a . (' ' :) . combShow 1 b
Nd s [] -> (s++)
Txt s -> (s++)