{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveFunctor #-}
module KleenePlugin.Types
( RE (..)
, simplifyRE
, Proof (..)
, proofStr
, proofTy
, traverseProofC,
) where
import qualified Data.Generics as SYB
import qualified Outputable as PP
import qualified DynFlags
data RE a
= E
| V a
| RE a :<> RE a
| RE a :\/ RE a
| S (RE a)
#ifdef KLEENE_TOP
| T
#endif
deriving (Functor, Show, SYB.Data)
simplifyRE :: RE a -> RE a
simplifyRE r@E {} = r
simplifyRE r@V {} = r
simplifyRE (r :<> s) = case (simplifyRE r, simplifyRE s) of
(E, x) -> x
(x, E) -> x
(x :<> y, z) -> x :<> simplifyRE (y :<> z)
(x, y) -> x :<> y
simplifyRE (r :\/ s) = case (simplifyRE r, simplifyRE s) of
(x :\/ y, z) -> x :\/ simplifyRE (y :\/ z)
(x, y) -> x :\/ y
simplifyRE (S E) = E
simplifyRE (S (S r)) = simplifyRE (S r)
simplifyRE (S r) = S (simplifyRE r)
#ifdef KLEENE_TOP
simplifyRE T = T
#endif
data Proof c b a
= ProofE
| ProofV c b a
| ProofA (RE a) (RE a) [b] [b] (Proof c b a) (Proof c b a)
| ProofL (RE a) (RE a) [b] (Proof c b a)
| ProofR (RE a) (RE a) [b] (Proof c b a)
| ProofN (RE a)
| ProofC (RE a) [b] [b] (Proof c b a) (Proof c b a)
#ifdef KLEENE_TOP
| ProofT [b]
#endif
deriving (Functor, Show, SYB.Data)
traverseProofC :: Applicative f => (a -> b -> c -> f c') -> Proof c b a -> f (Proof c' b a)
traverseProofC f = go where
go ProofE = pure ProofE
go (ProofV c b a) = (\c' -> ProofV c' b a)
<$> f a b c
go (ProofA r s xs ys p q) = ProofA r s xs ys
<$> go p
<*> go q
go (ProofL r s xs p) = ProofL r s xs <$> go p
go (ProofR r s xs p) = ProofR r s xs <$> go p
go (ProofN r) = pure (ProofN r)
go (ProofC r xs ys p q) = ProofC r xs ys
<$> go p
<*> go q
#ifdef KLEENE_TOP
go (ProofT xs) = pure (ProofT xs)
#endif
proofStr :: Proof c b a -> [b]
proofStr ProofE = []
proofStr (ProofV _ b _) = [b]
proofStr (ProofA _ _ xs ys _ _ ) = xs ++ ys
proofStr (ProofL _ _ xs _) = xs
proofStr (ProofR _ _ xs _) = xs
proofStr (ProofN _) = []
proofStr (ProofC _ xs ys _ _) = xs ++ ys
#ifdef KLEENE_TOP
proofStr (ProofT xs) = xs
#endif
proofTy :: Proof c b a -> RE a
proofTy ProofE = E
proofTy (ProofV _ _ t) = V t
proofTy (ProofA r s _ _ _ _) = r :<> s
proofTy (ProofL r s _ _) = r :\/ s
proofTy (ProofR r s _ _) = r :\/ s
proofTy (ProofN r) = S r
proofTy (ProofC r _ _ _ _) = S r
#ifdef KLEENE_TOP
proofTy (ProofT _) = T
#endif
instance PP.Outputable a => PP.Outputable (RE a) where
pprPrec _ E = PP.unicodeSyntax (PP.text "ε") (PP.text "[]")
pprPrec d (V a) = PP.pprPrec d a
pprPrec d a@(_ :<> _) = PP.cparen (d > 6) $ PP.sep $
punctuate (PP.unicodeSyntax (PP.char '⋅') (PP.text "<>")) $
map (PP.pprPrec 6) (peelApp a)
pprPrec d a@(_ :\/ _) = PP.cparen (d > 5) $ PP.sep $
punctuate (PP.unicodeSyntax (PP.char '∨') (PP.text "\\/")) $
map (PP.pprPrec 6) (peelAlt a)
pprPrec d (S r) = PP.cparen (d > 10) $
PP.hang (PP.text "list") 2 $
PP.pprPrec 11 r
#ifdef KLEENE_TOP
pprPrec _ T = PP.unicodeSyntax (PP.text "⊤") (PP.text "T")
#endif
punctuate
:: PP.SDoc
-> [PP.SDoc]
-> [PP.SDoc]
punctuate _ [] = []
punctuate p (x:xs) = go x xs where
go d [] = [d]
go d (e:es) = (d PP.<+> p) : go e es
peelApp :: RE a -> [RE a]
peelApp (a :<> b) = a : peelApp b
peelApp a = [a]
peelAlt :: RE a -> [RE a]
peelAlt (a :\/ b) = a : peelAlt b
peelAlt a = [a]
pprExpr :: DynFlags.DynFlags -> Rational -> String -> [PP.SDoc] -> [PP.SDoc] -> PP.SDoc
pprExpr dflags d f xs ys
| null zs = PP.text f
| otherwise = PP.cparen (d > 10) $ PP.hang (PP.text f) 2 $ PP.sep zs
where
zs | DynFlags.gopt DynFlags.Opt_PrintExplicitForalls dflags = xs ++ ys
| otherwise = ys
pprPrecTerm :: (PP.Outputable a, PP.Outputable b) => DynFlags.DynFlags -> Rational -> Proof c b a -> PP.SDoc
pprPrecTerm dflags = go where
go _ ProofE = PP.text "top"
go d (ProofV _ _ t) = PP.pprPrec d t
go d (ProofA r s xs ys p q) = pprExpr dflags d "times"
[ PP.char '@' PP.<> PP.pprPrec 11 r
, PP.char '@' PP.<> PP.pprPrec 11 s
, PP.char '#' PP.<> PP.ppr xs
, PP.char '#' PP.<> PP.ppr ys
]
[ go 11 p
, go 11 q
]
go d (ProofR r s xs p) = pprExpr dflags d "inr"
[ PP.char '@' PP.<> PP.pprPrec 11 r
, PP.char '@' PP.<> PP.pprPrec 11 s
, PP.char '#' PP.<> PP.ppr xs
]
[ go 11 p
]
go d (ProofL r s xs p) = pprExpr dflags d "inl"
[ PP.char '@' PP.<> PP.pprPrec 11 r
, PP.char '@' PP.<> PP.pprPrec 11 s
, PP.char '#' PP.<> PP.ppr xs
]
[ go 11 p
]
go d (ProofN re) = pprExpr dflags d "nil"
[ PP.char '@' PP.<> PP.pprPrec 11 re
]
[]
go d (ProofC re xs ys p q) = pprExpr dflags d "cons"
[ PP.char '@' PP.<> PP.pprPrec 11 re
, PP.char '#' PP.<> PP.ppr xs
, PP.char '#' PP.<> PP.ppr ys
]
[ go 11 p
, go 11 q
]
#ifdef KLEENE_TOP
go d (ProofT xs) = pprExpr dflags d "top"
[ PP.char '#' PP.<> PP.ppr xs
]
[]
#endif
instance (PP.Outputable a, PP.Outputable b) => PP.Outputable (Proof c b a) where
pprPrec d proof = PP.sdocWithDynFlags $ \flags -> pprPrecTerm flags d proof