{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Language.PTS.Term (
Term,
TermInf (..),
TermChk (..),
ScopeInf,
ScopeChkInf,
) where
import Control.Monad (ap)
import Data.Functor.Classes
import Data.String (IsString (..))
import Text.Show.Extras
import Language.PTS.Bound
import Language.PTS.Pretty
import Language.PTS.Specification
import Language.PTS.Sym
#ifdef LANGUAGE_PTS_HAS_NAT
import Numeric.Natural
#endif
#ifdef LANGUAGE_PTS_HAS_QUARKS
import Data.Set (Set)
import Data.Map (Map)
import qualified Data.Set as Set
import qualified Data.Map as Map
#endif
type Term s = TermInf s Sym
type ScopeInf n s a = ScopeH n (TermInf s) (TermInf s) a
type ScopeChkInf n s a = ScopeH n (TermChk s) (TermInf s) a
data TermInf s a
= Var a
| Ann (TermChk s a) (TermInf s a)
| Pi IrrSym (TermInf s a) (ScopeH IrrSym (TermInf s) (TermInf s) a)
| App (TermInf s a) (TermChk s a)
| Sort s
#ifdef LANGUAGE_PTS_HAS_SIGMA
| Sigma IrrSym (TermInf s a) (ScopeH IrrSym (TermInf s) (TermInf s) a)
#endif
#ifdef LANGUAGE_PTS_HAS_EQUALITY
| Equality (TermInf s a) (TermChk s a) (TermChk s a)
| J (V3 IrrSym)
(TermInf s a)
(ScopeInf IrrSym3 s a)
(TermChk s a)
(TermChk s a)
(TermChk s a)
(TermChk s a)
#endif
#ifdef LANGUAGE_PTS_HAS_PROP
| Unit
| I
| Empty
#endif
#ifdef LANGUAGE_PTS_HAS_BOOL
| TermBool
| TermTrue
| TermFalse
| TermBoolElim IrrSym (ScopeInf IrrSym s a) (TermChk s a) (TermChk s a) (TermChk s a)
#ifdef LANGUAGE_PTS_HAS_BOOL_PRIM
| TermAnd (TermChk s a) (TermChk s a)
#endif
#endif
#ifdef LANGUAGE_PTS_HAS_NAT
| TermNat
| TermNatZ
| TermNatS (TermChk s a)
| TermNatElim IrrSym (ScopeInf IrrSym s a) (TermChk s a) (TermChk s a) (TermChk s a)
#ifdef LANGUAGE_PTS_HAS_NAT_PRIM
| TermPlus (TermChk s a) (TermChk s a)
| TermTimes (TermChk s a) (TermChk s a)
#endif
#endif
#ifdef LANGUAGE_PTS_HAS_QUARKS
| Hadron (Set Sym)
| QuarkElim IrrSym (ScopeInf IrrSym s a) (Map Sym (TermChk s a)) (TermChk s a)
#endif
deriving (Functor, Foldable, Traversable)
data TermChk s a
= Inf (TermInf s a)
| Lam IrrSym (ScopeChkInf IrrSym s a)
#ifdef LANGUAGE_PTS_HAS_SIGMA
| Pair (TermChk s a) (TermChk s a)
| Match (TermInf s a) IrrSym IrrSym (ScopeChkInf IrrSym2 s a)
#endif
#ifdef LANGUAGE_PTS_HAS_EQUALITY
| Refl
#endif
#ifdef LANGUAGE_PTS_HAS_PROP
| Absurd (TermChk s a)
#endif
#ifdef LANGUAGE_PTS_HAS_QUARKS
| Quark Sym
#endif
deriving (Functor, Foldable, Traversable)
instance Show s => Show1 (TermChk s) where
liftShowsPrec sp sl d (Inf x) = showsUnaryWith
(liftShowsPrec sp sl)
"Inf" d x
liftShowsPrec sp sl d (Lam x y) = showsBinaryWith
showsPrec
(liftShowsPrec sp sl)
"Lam" d x y
#ifdef LANGUAGE_PTS_HAS_SIGMA
liftShowsPrec sp sl d (Pair x y) = showsBinaryWith
(liftShowsPrec sp sl)
(liftShowsPrec sp sl)
"Pair" d x y
liftShowsPrec sp sl d (Match x y z w) = showsQuadWith
(liftShowsPrec sp sl)
showsPrec
showsPrec
(liftShowsPrec sp sl)
"Match" d x y z w
#endif
#ifdef LANGUAGE_PTS_HAS_EQUALITY
liftShowsPrec _ _ _ Refl = showString "Refl"
#endif
#ifdef LANGUAGE_PTS_HAS_PROP
liftShowsPrec sp sl d (Absurd x) = showsUnaryWith
(liftShowsPrec sp sl)
"Absurd" d x
#endif
#ifdef LANGUAGE_PTS_HAS_QUARKS
liftShowsPrec _ _ d (Quark q) = showsUnaryWith
showsPrec
"Quark" d q
#endif
instance Show s => Show1 (TermInf s) where
liftShowsPrec sp _ d (Var x) = showsUnaryWith
sp
"Var" d x
liftShowsPrec sp sl d (Ann x y) = showsBinaryWith
(liftShowsPrec sp sl)
(liftShowsPrec sp sl)
"Ann" d x y
liftShowsPrec sp sl d (Pi x y z) = showsTernaryWith
showsPrec
(liftShowsPrec sp sl)
(liftShowsPrec sp sl)
"Pi" d x y z
liftShowsPrec sp sl d (App x y) = showsBinaryWith
(liftShowsPrec sp sl)
(liftShowsPrec sp sl)
"App" d x y
liftShowsPrec _ _ d (Sort x) = showsUnaryWith
showsPrec
"Sort" d x
#ifdef LANGUAGE_PTS_HAS_SIGMA
liftShowsPrec sp sl d (Sigma x y z) = showsTernaryWith
showsPrec
(liftShowsPrec sp sl)
(liftShowsPrec sp sl)
"Sigma" d x y z
#endif
#ifdef LANGUAGE_PTS_HAS_EQUALITY
liftShowsPrec sp sl d (J v3 a p r u v w) = showParen (d >= 10)
$ showString "J"
. showChar ' ' . showsPrec 11 v3
. showChar ' ' . liftShowsPrec sp sl 11 a
. showChar ' ' . liftShowsPrec sp sl 11 p
. showChar ' ' . liftShowsPrec sp sl 11 r
. showChar ' ' . liftShowsPrec sp sl 11 u
. showChar ' ' . liftShowsPrec sp sl 11 v
. showChar ' ' . liftShowsPrec sp sl 11 w
#endif
#ifdef LANGUAGE_PTS_HAS_EQUALITY
liftShowsPrec sp sl d (Equality x y z) = showsTernaryWith
(liftShowsPrec sp sl)
(liftShowsPrec sp sl)
(liftShowsPrec sp sl)
"Equality" d x y z
#endif
#ifdef LANGUAGE_PTS_HAS_PROP
liftShowsPrec _ _ _ Unit = showString "Unit"
liftShowsPrec _ _ _ I = showString "I"
liftShowsPrec _ _ _ Empty = showString "Empty"
#endif
#ifdef LANGUAGE_PTS_HAS_BOOL
liftShowsPrec _ _ _ TermBool = showString "TermBool"
liftShowsPrec _ _ _ TermTrue = showString "TermTrue"
liftShowsPrec _ _ _ TermFalse = showString "TermFalse"
liftShowsPrec sp sl d (TermBoolElim x y z w u) = showsQuintWith
showsPrec
(liftShowsPrec sp sl)
(liftShowsPrec sp sl)
(liftShowsPrec sp sl)
(liftShowsPrec sp sl)
"TermBoolElim" d x y z w u
#ifdef LANGUAGE_PTS_HAS_BOOL_PRIM
liftShowsPrec sp sl d (TermAnd x y) = showsBinaryWith
(liftShowsPrec sp sl)
(liftShowsPrec sp sl)
"TermAnd" d x y
#endif
#endif
#ifdef LANGUAGE_PTS_HAS_NAT
liftShowsPrec _ _ _ TermNat = showString "TermNat"
liftShowsPrec _ _ _ TermNatZ = showString "TermNatZ"
liftShowsPrec sp sl d (TermNatS x) = showsUnaryWith
(liftShowsPrec sp sl)
"TermNatS" d x
liftShowsPrec sp sl d (TermNatElim x y z w u) = showsQuintWith
showsPrec
(liftShowsPrec sp sl)
(liftShowsPrec sp sl)
(liftShowsPrec sp sl)
(liftShowsPrec sp sl)
"TermNatElim" d x y z w u
#ifdef LANGUAGE_PTS_HAS_NAT_PRIM
liftShowsPrec sp sl d (TermPlus x y) = showsBinaryWith
(liftShowsPrec sp sl)
(liftShowsPrec sp sl)
"TermPlus" d x y
liftShowsPrec sp sl d (TermTimes x y) = showsBinaryWith
(liftShowsPrec sp sl)
(liftShowsPrec sp sl)
"TermTimes" d x y
#endif
#endif
#ifdef LANGUAGE_PTS_HAS_QUARKS
liftShowsPrec _ _ d (Hadron qs) = showsUnaryWith
showsPrec
"Hadron" d (Set.toList qs)
liftShowsPrec sp sl d (QuarkElim x p qs q) = showsQuadWith
showsPrec
(liftShowsPrec sp sl)
(liftShowsPrec sp sl)
(liftShowsPrec sp sl)
"QuarkElim" d x p (P $ Map.toList qs) q
#endif
instance (Show a, Show s) => Show (TermInf s a) where showsPrec = showsPrec1
instance (Show a, Show s) => Show (TermChk s a) where showsPrec = showsPrec1
instance Specification s => PrettyPrec1 (TermInf s) where
liftPpp p d t = traverse (p PrecApp) t >>= pppInf d
pppInf :: Specification s => Prec -> TermInf s Doc -> PrettyM Doc
pppInf _ (Var a) = return a
pppInf d (Sort s) = ppp d s
pppInf d t@Pi {} = uncurry (pppPi d) =<< pppPeelPi t
pppInf d t@App {} = uncurry (pppApplication d) (pppPeelApplication t)
pppInf d (Ann x t'@Pi {}) =
uncurry (pppAnnotationPi d (pppChk PrecAnn x)) =<< pppPeelPi t'
pppInf d (Ann x t) = pppAnnotation d (pppChk PrecAnn x) (pppInf PrecAnn t)
#ifdef LANGUAGE_PTS_HAS_SIGMA
pppInf d t@Sigma {} = uncurry (pppPi d) =<< pppPeelPi t
#endif
#ifdef LANGUAGE_PTS_HAS_EQUALITY
pppInf d (Equality a x y) = pppApplication d
"Eq"
[ pppInf PrecApp a
, pppChk PrecApp x
, pppChk PrecApp y
]
pppInf d (J (V3 x y z) a p r u v w) = pppApplication d
(pppText "J")
[ pppInf PrecApp a
, pppScopedIrrSym x $ \xDoc ->
pppScopedIrrSym y $ \yDoc ->
pppScopedIrrSym z $ \zDoc ->
pppLambda PrecApp [xDoc,yDoc,zDoc] $ pppInf PrecLambda $ instantiate3Hreturn xDoc yDoc zDoc p
, pppChk PrecApp r
, pppChk PrecApp u
, pppChk PrecApp v
, pppChk PrecApp w
]
#endif
#ifdef LANGUAGE_PTS_HAS_PROP
pppInf _ Unit = pppChar '⊤'
pppInf _ I = pppChar 'I'
pppInf _ Empty = pppChar '⊥'
#endif
#ifdef LANGUAGE_PTS_HAS_BOOL
pppInf _ TermBool = pppChar '𝔹'
pppInf _ TermTrue = pppText "true"
pppInf _ TermFalse = pppText "false"
pppInf d (TermBoolElim x p t f b) = pppApplication d
(pppText "𝔹-elim")
[ pppScopedIrrSym x $ \xDoc -> pppLambda PrecApp [xDoc] $ pppInf PrecLambda $ instantiate1Hreturn xDoc p
, pppChk PrecApp t
, pppChk PrecApp f
, pppChk PrecApp b
]
#ifdef LANGUAGE_PTS_HAS_BOOL_PRIM
pppInf d (TermAnd x y) = pppApplication d
(pppText "𝔹-and")
[ pppChk PrecApp x
, pppChk PrecApp y
]
#endif
#endif
#ifdef LANGUAGE_PTS_HAS_NAT
pppInf _ TermNat = pppChar 'ℕ'
pppInf _ TermNatZ = pppChar '0'
pppInf d (TermNatS n)
| Just m <- termChkToNatural n = pppIntegral $ succ m
| otherwise = pppApplication d (pppChar 'S') [pppChk PrecApp n]
pppInf d (TermNatElim x p z s n) = pppApplication d
(pppText "ℕ-elim")
[ pppScopedIrrSym x $ \xDoc -> pppLambda PrecApp [xDoc] $ pppInf PrecLambda $ instantiate1Hreturn xDoc p
, pppChk PrecApp z
, pppChk PrecApp s
, pppChk PrecApp n
]
#ifdef LANGUAGE_PTS_HAS_NAT_PRIM
pppInf d (TermPlus x y) = pppApplication d
(pppText "ℕ-plus")
[ pppChk PrecApp x
, pppChk PrecApp y
]
pppInf d (TermTimes x y) = pppApplication d
(pppText "ℕ-times")
[ pppChk PrecApp x
, pppChk PrecApp y
]
#endif
#endif
#ifdef LANGUAGE_PTS_HAS_QUARKS
pppInf _ (Hadron qs) = pppHadron qs
pppInf d (QuarkElim x p qs q) = pppQuarkElim d x
(\xDoc -> pppInf PrecLambda $ instantiate1Hreturn xDoc p)
(fmap (pppChk PrecApp) qs)
(pppChk PrecApp q)
#endif
pppPeelPi :: Specification s => TermInf s Doc -> PrettyM ([PPPi], PrettyM Doc)
pppPeelPi (Pi n a b)
| Just b' <- unusedScopeH b = do
~(xs, ys) <- pppPeelPi b'
return (PPArrow (pppInf PrecPi a) : xs, ys)
| Sort a' <- a, a' == typeSort =
pppScopedIrrSym n $ \nDoc -> do
~(xs, ys) <- pppPeelPi (instantiate1H (return nDoc) b)
return (PPForall nDoc : xs, ys)
| otherwise =
pppScopedIrrSym n $ \nDoc -> do
~(xs, ys) <- pppPeelPi (instantiate1H (return nDoc) b)
return (PPPi nDoc (pppInf PrecPi a) : xs, ys)
#ifdef LANGUAGE_PTS_HAS_SIGMA
pppPeelPi (Sigma n a b)
| Sort a' <- a, a' == typeSort =
pppScopedIrrSym n $ \nDoc -> do
~(xs, ys) <- pppPeelPi (instantiate1H (return nDoc) b)
return (PPExists nDoc : xs, ys)
| otherwise =
pppScopedIrrSym n $ \nDoc -> do
~(xs, ys) <- pppPeelPi (instantiate1H (return nDoc) b)
return (PPSigma nDoc (pppInf PrecPi a) : xs, ys)
#endif
pppPeelPi t = return ([], pppInf PrecPi t)
pppPeelApplication :: Specification s => TermInf s Doc -> (PrettyM Doc, [PrettyM Doc])
pppPeelApplication (App f x) =
let ~(f', xs) = pppPeelApplication f
in (f', xs ++ [pppChk PrecApp x])
pppPeelApplication t = (pppInf PrecApp t, [])
unusedScopeH :: (Module f g, Traversable f) => ScopeH n f g a -> Maybe (f a)
unusedScopeH s = sequence (instantiate1H (return Nothing) (fmap Just s))
instance Specification s => PrettyPrec1 (TermChk s) where
liftPpp p d t = traverse (p PrecApp) t >>= pppChk d
pppChk :: forall s. Specification s => Prec -> TermChk s Doc -> PrettyM Doc
pppChk d (Inf x) = pppInf d x
pppChk d t@Lam {} = uncurry (pppLambda d) =<< pppPeelLam t
where
pppPeelLam :: TermChk s Doc -> PrettyM ([Doc], PrettyM Doc)
pppPeelLam (Lam n b) = pppScopedIrrSym n $ \nDoc -> do
~(xs, ys) <- pppPeelLam (instantiate1H (return nDoc) b)
return (nDoc : xs, ys)
pppPeelLam x = do
x' <- pppChk PrecLambda x
return ([], return x')
#ifdef LANGUAGE_PTS_HAS_SIGMA
pppChk d (Pair x y) = pppApplication d
"pair"
[ pppChk PrecApp x
, pppChk PrecApp y
]
pppChk d (Match p x y b) = pppApplication d
(pppText "match")
[ pppInf PrecApp p
, pppScopedIrrSym x $ \xDoc -> pppScopedIrrSym y $ \yDoc ->
pppLambda PrecApp [xDoc, yDoc] $ pppChk PrecLambda $ instantiate2Hreturn xDoc yDoc b
]
#endif
#ifdef LANGUAGE_PTS_HAS_EQUALITY
pppChk _ Refl = "refl"
#endif
#ifdef LANGUAGE_PTS_HAS_PROP
pppChk d (Absurd x) = pppApplication d
(pppText "absurd") [ pppChk PrecApp x ]
#endif
#ifdef LANGUAGE_PTS_HAS_QUARKS
pppChk _ (Quark q) = pppQuark q
#endif
instance (Specification s, PrettyPrec a) => PrettyPrec (TermInf s a) where ppp = ppp1
instance (Specification s, PrettyPrec a) => PrettyPrec (TermChk s a) where ppp = ppp1
instance Applicative (TermInf s) where
pure = Var
(<*>) = ap
instance Monad (TermInf s) where
return = pure
Var a >>= f = f a
Ann x t >>= f = Ann (x >>== f) (t >>= f)
Sort s >>= _ = Sort s
App u d >>= f = App (u >>= f) (d >>== f)
Pi n a b >>= f = Pi n (a >>= f) (b >>== f)
#ifdef LANGUAGE_PTS_HAS_SIGMA
Sigma x a b >>= f = Sigma x (a >>= f) (b >>== f)
#endif
#ifdef LANGUAGE_PTS_HAS_EQUALITY
Equality a x y >>= f = Equality (a >>= f) (x >>== f) (y >>== f)
J v3 a p r u v w >>= f = J v3 (a >>= f) (p >>== f) (r >>== f) (u >>== f) (v >>== f) (w >>== f)
#endif
#ifdef LANGUAGE_PTS_HAS_PROP
Unit >>= _ = Unit
I >>= _ = I
Empty >>= _ = Empty
#endif
#ifdef LANGUAGE_PTS_HAS_BOOL
TermBool >>= _ = TermBool
TermTrue >>= _ = TermTrue
TermFalse >>= _ = TermFalse
TermBoolElim x p z s n >>= k = TermBoolElim x
(p >>== k)
(z >>== k)
(s >>== k)
(n >>== k)
#ifdef LANGUAGE_PTS_HAS_BOOL_PRIM
TermAnd x y >>= k = TermAnd (x >>== k) (y >>== k)
#endif
#endif
#ifdef LANGUAGE_PTS_HAS_NAT
TermNat >>= _ = TermNat
TermNatZ >>= _ = TermNatZ
TermNatS n >>= k = TermNatS (n >>== k)
TermNatElim x p z s n >>= k = TermNatElim x
(p >>== k)
(z >>== k)
(s >>== k)
(n >>== k)
#ifdef LANGUAGE_PTS_HAS_NAT_PRIM
TermPlus x y >>= k = TermPlus (x >>== k) (y >>== k)
TermTimes x y >>= k = TermTimes (x >>== k) (y >>== k)
#endif
#endif
#ifdef LANGUAGE_PTS_HAS_QUARKS
Hadron qs >>= _ = Hadron qs
QuarkElim x p qs q >>= k = QuarkElim x
(p >>== k)
(fmap (>>== k) qs)
(q >>== k)
#endif
instance Module (TermChk s) (TermInf s) where
Inf u >>== k = Inf (u >>= k)
Lam n b >>== k = Lam n (b >>== k)
#ifdef LANGUAGE_PTS_HAS_SIGMA
Pair x y >>== k = Pair (x >>== k) (y >>== k)
Match p x y b >>== k = Match (p >>= k) x y (b >>== k)
#endif
#ifdef LANGUAGE_PTS_HAS_EQUALITY
Refl >>== _ = Refl
#endif
#ifdef LANGUAGE_PTS_HAS_PROP
Absurd x >>== k = Absurd (x >>== k)
#endif
#ifdef LANGUAGE_PTS_HAS_QUARKS
Quark q >>== _ = Quark q
#endif
instance Module (TermInf s) (TermInf s) where
(>>==) = (>>=)
#ifdef LANGUAGE_PTS_HAS_NAT
termChkToNatural :: TermChk s a -> Maybe Natural
termChkToNatural (Inf TermNatZ) = Just 0
termChkToNatural (Inf (TermNatS n)) = succ <$> termChkToNatural n
termChkToNatural _ = Nothing
#endif
instance IsString a => IsString (TermInf s a) where
fromString = Var . fromString
instance IsString a => IsString (TermChk s a) where
fromString = Inf . fromString
instance IsString a => Num (TermInf s a) where
fromInteger n
#ifdef LANGUAGE_PTS_HAS_NAT
| n <= 0 = TermNatZ
| otherwise = TermNatS (Inf (fromInteger (pred n)))
#else
= fromString (show n)
#endif
n + m = App (App "plus" (Inf n)) (Inf m)
n * m = App (App "times" (Inf n)) (Inf m)
n - m = App (App "minus" (Inf n)) (Inf m)
abs n = App "abs" (Inf n)
signum n = App "signum" (Inf n)
negate n = App "negate" (Inf n)
instance IsString a => Num (TermChk s a) where
fromInteger = Inf . fromInteger
n + m = Inf (App (App "plus" n) m)
n * m = Inf (App (App "times" n) m)
n - m = Inf (App (App "minus" n) m)
abs n = Inf (App "abs" n)
signum n = Inf (App "signum" n)
negate n = Inf (App "negate" n)