packages feed

syntactic-0.7: CEFP/Examples/Exercise10.hs

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE ViewPatterns #-}

import Language.Syntactic



----------------------------------------
-- a)
----------------------------------------

data Circ a
  where
    Const :: Bool -> Circ Bool
    Inv   :: Circ Bool -> Circ Bool
    And   :: Circ Bool -> Circ Bool -> Circ Bool

data ConstSym a where Const' :: Bool -> ConstSym (Full Bool)
data InvSym a   where Inv' :: InvSym (Bool :-> Full Bool)
data AndSym a   where And' :: AndSym (Bool :-> Bool :-> Full Bool)

type CircDom = InvSym :+: AndSym :+: ConstSym



----------------------------------------
-- b)
----------------------------------------

consT :: (ConstSym :<: dom) => Bool -> ASTF dom Bool
consT a = inject (Const' a)

inv :: (InvSym :<: dom) => ASTF dom Bool -> ASTF dom Bool
inv a = inject Inv' :$: a

anD :: (AndSym :<: dom) =>
    ASTF dom Bool -> ASTF dom Bool -> ASTF dom Bool
anD a b = inject And' :$: a :$: b



----------------------------------------
-- c)
----------------------------------------

circ1 :: Circ Bool
circ1 = And (Const False) (And (Const True) (Inv (Const False)))

circ2 :: ASTF CircDom Bool
circ2 = anD (consT False) (anD (consT True) (inv (consT False)))



----------------------------------------
-- d)
----------------------------------------

fromCirc :: Circ a -> ASTF CircDom a
fromCirc (Const a) = inject (Const' a)
fromCirc (Inv a)   = inject Inv' :$: fromCirc a
fromCirc (And a b) = inject And' :$: fromCirc a :$: fromCirc b

toCirc :: ASTF CircDom a -> Circ a
toCirc (project -> Just (Const' a))         = Const a
toCirc ((project -> Just Inv') :$: a)       = Inv (toCirc a)
toCirc ((project -> Just And') :$: a :$: b) = And (toCirc a) (toCirc b)



----------------------------------------
-- e)
----------------------------------------

instance Render ConstSym where render (Const' a) = show a
instance Render InvSym   where render Inv' = "inv"
instance Render AndSym   where render And' = "and"

instance Eval ConstSym where evaluate (Const' a) = fromEval a
instance Eval InvSym   where evaluate Inv' = fromEval not
instance Eval AndSym   where evaluate And' = fromEval (&&)



----------------------------------------
-- f)
----------------------------------------

data NandSym a where Nand :: NandSym (Bool :-> Bool :-> Full Bool)

instance Render NandSym where render Nand = "nand"

instance Eval NandSym where evaluate Nand = fromEval $ \a b -> not (a && b)

nandify' :: AST (InvSym :+: AndSym :+: dom) a -> AST (NandSym :+: dom) a
nandify' ((project -> Just Inv') :$: a) = inject Nand :$: a' :$: a'
  where
    a' = nandify a
nandify' ((project -> Just And') :$: a :$: b) = inject Nand :$: ab :$: ab
  where
    ab = inject Nand :$: nandify a :$: nandify b
nandify' (c :$: a) = nandify' c :$: nandify a
nandify' (Symbol (InjectR (InjectR a))) = Symbol (InjectR a)

nandify ::
    ASTF (InvSym :+: AndSym :+: dom) a -> ASTF (NandSym :+: dom) a
nandify = nandify'