diff options
author | Greg Brown <greg.brown01@ed.ac.uk> | 2022-12-18 16:36:09 +0000 |
---|---|---|
committer | Greg Brown <greg.brown01@ed.ac.uk> | 2022-12-18 16:36:09 +0000 |
commit | ff4c5f15f354aa8da7bb5868d913dbbef23832a3 (patch) | |
tree | fbe5187d78f4c0de1947e2889aa08b406c06083b | |
parent | d59c8879e2476bbc9b1706d3e8b57139a46f4cb8 (diff) |
Add dependent products.
-rw-r--r-- | src/Obs/Abstract.idr | 25 | ||||
-rw-r--r-- | src/Obs/NormalForm.idr | 74 | ||||
-rw-r--r-- | src/Obs/Parser.idr | 95 | ||||
-rw-r--r-- | src/Obs/Substitution.idr | 34 | ||||
-rw-r--r-- | src/Obs/Syntax.idr | 34 | ||||
-rw-r--r-- | src/Obs/Term.idr | 47 | ||||
-rw-r--r-- | src/Obs/Typing.idr | 205 |
7 files changed, 373 insertions, 141 deletions
diff --git a/src/Obs/Abstract.idr b/src/Obs/Abstract.idr index 1b72965..0915152 100644 --- a/src/Obs/Abstract.idr +++ b/src/Obs/Abstract.idr @@ -33,18 +33,29 @@ printErr (Right x) = pure x export abstractSyntax : Context n -> Syntax -> Error (Term n) -abstractSyntax ctx (Var b str) = do - let Just i = lookup str ctx - | Nothing => report b "unbound variable: \{str}" - pure (Var b i) -abstractSyntax ctx (Sort b s) = pure (Sort b s) +abstractSyntax ctx (Var var) = do + let Just i = lookup var.val ctx + | Nothing => report var.bounds "unbound variable: \{var.val}" + pure (Var var i) +abstractSyntax ctx (Sort bounds s) = pure (Sort bounds s) +abstractSyntax ctx (Pi bounds var a b) = do + a <- abstractSyntax ctx a + b <- abstractSyntax (bind ctx var.val) b + pure (Pi bounds var.val a b) +abstractSyntax ctx (Lambda bounds var t) = do + t <- abstractSyntax (bind ctx var.val) t + pure (Lambda bounds var.val t) +abstractSyntax ctx (App t u) = do + t <- abstractSyntax ctx t + u <- abstractSyntax ctx u + pure (App t u) abstractSyntax ctx (Top b) = pure (Top b) abstractSyntax ctx (Point b) = pure (Point b) abstractSyntax ctx (Bottom b) = pure (Bottom b) -abstractSyntax ctx (Absurd b a t) = do +abstractSyntax ctx (Absurd bounds a t) = do a <- abstractSyntax ctx a t <- abstractSyntax ctx t - pure (Absurd b a t) + pure (Absurd bounds a t) export abstractDefinition : Context n -> Definition -> Error (Definition n) diff --git a/src/Obs/NormalForm.idr b/src/Obs/NormalForm.idr index 08354b4..8ee3b19 100644 --- a/src/Obs/NormalForm.idr +++ b/src/Obs/NormalForm.idr @@ -18,12 +18,15 @@ data NormalForm : Nat -> Type public export data Constructor : Nat -> Type where Sort : Sort -> Constructor n + Pi : Sort -> Sort -> NormalForm n -> NormalForm (S n) -> Constructor n + Lambda : NormalForm (S n) -> Constructor n Top : Constructor n Bottom : Constructor n public export data Neutral : Nat -> Type where Var : Fin n -> Neutral n + App : Neutral n -> NormalForm n -> Neutral n Absurd : Neutral n public export @@ -35,7 +38,7 @@ data NormalForm : Nat -> Type where public export record Definition (n : Nat) where constructor MkDefinition - name : Maybe String + name : String sort : Sort ty : NormalForm n tm : NormalForm n @@ -53,12 +56,15 @@ eqNtrl : Neutral n -> Neutral n -> Bool eqWhnf : NormalForm n -> NormalForm n -> Bool eqCnstr (Sort s) (Sort s') = s == s' -eqCnstr Top Top = True -eqCnstr Bottom Bottom = True +eqCnstr (Pi s s' a b) (Pi l l' a' b') = s == l && s' == l' && eqWhnf a a' && eqWhnf b b' +eqCnstr (Lambda t) (Lambda u) = eqWhnf t u +eqCnstr Top Top = True +eqCnstr Bottom Bottom = True eqCnstr _ _ = False eqNtrl (Var i) (Var j) = i == j -eqNtrl Absurd Absurd = True +eqNtrl (App t u) (App t' u') = eqNtrl t t' && eqWhnf u u' +eqNtrl Absurd Absurd = True eqNtrl _ _ = False eqWhnf (Ntrl t) (Ntrl u) = eqNtrl t u @@ -78,6 +84,14 @@ export Eq (NormalForm n) where t == u = eqWhnf t u +export +Cast Sort (Constructor n) where + cast = Sort + +export +Cast Sort (NormalForm n) where + cast = Cnstr . cast + -- Pretty Print ---------------------------------------------------------------- prettyPrecCnstr : Prec -> Constructor n -> Doc ann @@ -85,10 +99,24 @@ prettyPrecNtrl : Prec -> Neutral n -> Doc ann prettyPrecWhnf : Prec -> NormalForm n -> Doc ann prettyPrecCnstr d (Sort s) = prettyPrec d s +prettyPrecCnstr d (Pi _ _ a b) = + parenthesise (d > Open) $ + group $ + parens (prettyPrecWhnf Open a) <++> + pretty "->" <+> softline <+> + prettyPrecWhnf Open b +prettyPrecCnstr d (Lambda t) = + parenthesise (d > Open) $ + group $ + backslash <+> softline <+> prettyPrecWhnf Open t prettyPrecCnstr d Top = pretty "()" prettyPrecCnstr d Bottom = pretty "Void" prettyPrecNtrl d (Var i) = pretty "$\{show i}" +prettyPrecNtrl d (App t u) = + parenthesise (d >= App) $ + group $ + fillSep [prettyPrecNtrl Open t, prettyPrecWhnf App u] prettyPrecNtrl d Absurd = pretty "absurd" prettyPrecWhnf d (Ntrl t) = prettyPrecNtrl d t @@ -128,11 +156,14 @@ renameNtrl : Neutral n -> (Fin n -> Fin m) -> Neutral m renameWhnf : NormalForm n -> (Fin n -> Fin m) -> NormalForm m renameCnstr (Sort s) f = Sort s -renameCnstr Top f = Top -renameCnstr Bottom f = Bottom +renameCnstr (Pi s s' a b) f = Pi s s' (renameWhnf a f) (renameWhnf b $ lift 1 f) +renameCnstr (Lambda t) f = Lambda (renameWhnf t $ lift 1 f) +renameCnstr Top f = Top +renameCnstr Bottom f = Bottom renameNtrl (Var i) f = Var (f i) -renameNtrl Absurd f = Absurd +renameNtrl (App t u) f = App (renameNtrl t f) (renameWhnf u f) +renameNtrl Absurd f = Absurd renameWhnf (Ntrl t) f = Ntrl $ renameNtrl t f renameWhnf (Cnstr t) f = Cnstr $ renameCnstr t f @@ -150,31 +181,10 @@ export Rename NormalForm where rename = renameWhnf --- Substitution - -substCnstr : Constructor n -> (Fin n -> NormalForm m) -> Constructor m -substNtrl : Neutral n -> (Fin n -> NormalForm m) -> NormalForm m -substWhnf : NormalForm n -> (Fin n -> NormalForm m) -> NormalForm m - -substCnstr (Sort s) f = Sort s -substCnstr Top f = Top -substCnstr Bottom f = Bottom - -substNtrl (Var i) f = f i -substNtrl Absurd f = Ntrl Absurd - -substWhnf (Ntrl t) f = substNtrl t f -substWhnf (Cnstr t) f = Cnstr $ substCnstr t f -substWhnf Irrel f = Irrel - -export -Subst Constructor NormalForm Constructor where - subst = substCnstr - export -Subst Neutral NormalForm NormalForm where - subst = substNtrl +PointedRename Neutral where + point = Var export -Subst NormalForm NormalForm NormalForm where - subst = substWhnf +PointedRename NormalForm where + point = Ntrl . point diff --git a/src/Obs/Parser.idr b/src/Obs/Parser.idr index 67446bf..c9705fb 100644 --- a/src/Obs/Parser.idr +++ b/src/Obs/Parser.idr @@ -36,25 +36,31 @@ data ObsTokenKind | OTPOpen | OTPClose -- Definition characters + | OTBackslash + | OTThinArrow + | OTFatArrow | OTEqual | OTColon Eq ObsTokenKind where OTNewline == OTNewline = True - OTIgnore == OTIgnore = True - OTIdent == OTIdent = True - OTProp == OTProp = True - OTSet == OTSet = True - OTNat == OTNat = True - OTUnit == OTUnit = True - OTPoint == OTPoint = True - OTVoid == OTVoid = True - OTAbsurd == OTAbsurd = True - OTPOpen == OTPOpen = True - OTPClose == OTPClose = True - OTEqual == OTEqual = True - OTColon == OTColon = True - _ == _ = False + OTIgnore == OTIgnore = True + OTIdent == OTIdent = True + OTProp == OTProp = True + OTSet == OTSet = True + OTNat == OTNat = True + OTUnit == OTUnit = True + OTPoint == OTPoint = True + OTVoid == OTVoid = True + OTAbsurd == OTAbsurd = True + OTPOpen == OTPOpen = True + OTPClose == OTPClose = True + OTBackslash == OTBackslash = True + OTThinArrow == OTThinArrow = True + OTFatArrow == OTFatArrow = True + OTEqual == OTEqual = True + OTColon == OTColon = True + _ == _ = False TokenKind ObsTokenKind where TokType OTIdent = String @@ -62,19 +68,22 @@ TokenKind ObsTokenKind where TokType _ = () tokValue OTNewline s = () - tokValue OTIgnore s = () - tokValue OTIdent s = s - tokValue OTProp s = () - tokValue OTSet s = () - tokValue OTNat s = stringToNatOrZ s - tokValue OTUnit s = () - tokValue OTPoint s = () - tokValue OTVoid s = () - tokValue OTAbsurd s = () - tokValue OTPOpen s = () - tokValue OTPClose s = () - tokValue OTEqual s = () - tokValue OTColon s = () + tokValue OTIgnore s = () + tokValue OTIdent s = s + tokValue OTProp s = () + tokValue OTSet s = () + tokValue OTNat s = stringToNatOrZ s + tokValue OTUnit s = () + tokValue OTPoint s = () + tokValue OTVoid s = () + tokValue OTAbsurd s = () + tokValue OTPOpen s = () + tokValue OTPClose s = () + tokValue OTBackslash s = () + tokValue OTThinArrow s = () + tokValue OTFatArrow s = () + tokValue OTEqual s = () + tokValue OTColon s = () ObsToken : Type ObsToken = Token ObsTokenKind @@ -105,6 +114,9 @@ obsTokenMap = toTokenMap [(newline, OTNewline), (spaces, OTIgnore)] ++ , (exact "*", OTPoint) , (exact "(", OTPOpen) , (exact ")", OTPClose) + , (exact "=>", OTFatArrow) + , (exact "->", OTThinArrow) + , (exact "\\", OTBackslash) , (exact "=", OTEqual) , (exact ":", OTColon) ] @@ -121,9 +133,7 @@ ident : Grammar state ObsToken True (WithBounds String) ident = bounds $ match OTIdent var : Grammar state ObsToken True Syntax -var = do - id <- ident <* commit - pure (Var id.bounds id.val) +var = [| Var (ident <* commit) |] prop : Grammar state ObsToken True Syntax prop = do @@ -161,6 +171,11 @@ set = do i <- [| mergeBounds (bounds $ match OTSet) (bounds $ map Set $ option 0 $ match OTNat) |] <* commit pure (Sort i.bounds i.val) +lambda : Grammar state ObsToken True (Syntax -> Syntax) +lambda = do + name <- bounds $ match OTBackslash *> commit *> ident <* match OTFatArrow + pure (Lambda name.bounds name.val) + botElim : Grammar state ObsToken True (Syntax -> Syntax -> Syntax) botElim = do absurd <- bounds $ match OTAbsurd <* commit @@ -168,21 +183,27 @@ botElim = do -- NOTE: these functions are all total. partial +pi : Grammar state ObsToken True (Syntax -> Syntax) +partial term : Grammar state ObsToken True Syntax - partial precGteApp : Grammar state ObsToken True Syntax - +partial +exp' : Grammar state ObsToken True Syntax partial exp : Grammar state ObsToken True Syntax +partial +decl : Grammar state ObsToken True (WithBounds String, Syntax) + +pi = do + decl <- bounds $ parens decl <* match OTThinArrow <* commit + pure (uncurry (Pi decl.bounds) decl.val) term = atomic <|> parens exp precGteApp = atomicNoSet <|> set <|> parens exp -exp = precGteApp <|> (botElim <*> term <*> term) - -partial -decl : Grammar state ObsToken True (WithBounds String, Syntax) -decl = [| MkPair ident (commit *> match OTColon *> exp) |] +exp' = precGteApp <|> (botElim <*> term <*> term) +exp = (pi <*> exp) <|> (lambda <*> exp) <|> (map (\(t, ts) => foldl1 App (t :: ts)) [| MkPair exp' (many term) |]) +decl = [| MkPair ident (match OTColon *> commit *> exp) |] partial def : Grammar state ObsToken True (WithBounds String, Syntax) diff --git a/src/Obs/Substitution.idr b/src/Obs/Substitution.idr index 54df355..340afff 100644 --- a/src/Obs/Substitution.idr +++ b/src/Obs/Substitution.idr @@ -5,9 +5,39 @@ import Data.Fin %default total public export -interface Rename (x : Nat -> Type) where +interface Rename (0 x : Nat -> Type) where rename : forall m, n . x n -> (Fin n -> Fin m) -> x m public export -interface Subst (x, y, z : Nat -> Type) where +interface Rename x => PointedRename x where + point : forall n . Fin n -> x n + +public export +interface Subst (0 x, y, z : Nat -> Type) where subst : forall m, n . x n -> (Fin n -> y m) -> z m + +public export +Rename x => Subst x Fin x where + subst = rename + +public export +Rename Fin where + rename i f = f i + +public export +PointedRename Fin where + point = id + +public export +add : (0 x : _) -> x n -> (Fin m -> x n) -> Fin (S m) -> x n +add x v f FZ = v +add x v f (FS i) = f i + +public export +lift : PointedRename x => (k : _) -> (Fin m -> x n) -> Fin (k + m) -> x (k + n) +lift 0 f = f +lift (S k) f = add x (point FZ) (\i => rename (lift k f i) FS) + +public export +weaken : Rename x => (m : _) -> x n -> x (m + n) +weaken m t = rename t (shift m) diff --git a/src/Obs/Syntax.idr b/src/Obs/Syntax.idr index 6b95910..4a7ee0c 100644 --- a/src/Obs/Syntax.idr +++ b/src/Obs/Syntax.idr @@ -11,9 +11,13 @@ import Text.PrettyPrint.Prettyprinter public export data Syntax : Type where - Var : Bounds -> String -> Syntax + Var : WithBounds String -> Syntax -- Sorts Sort : Bounds -> Sort -> Syntax + -- Dependent Products + Pi : Bounds -> WithBounds String -> Syntax -> Syntax -> Syntax + Lambda : Bounds -> WithBounds String -> Syntax -> Syntax + App : Syntax -> Syntax -> Syntax -- True Top : Bounds -> Syntax Point : Bounds -> Syntax @@ -33,14 +37,30 @@ record Definition where export Pretty Syntax where - prettyPrec d (Var x str) = pretty str - prettyPrec d (Sort x s) = prettyPrec d s - prettyPrec d (Top x) = pretty "()" - prettyPrec d (Point x) = pretty "*" - prettyPrec d (Bottom x) = pretty "Void" - prettyPrec d (Absurd x a t) = + prettyPrec d (Var var) = pretty var.val + prettyPrec d (Sort _ s) = prettyPrec d s + prettyPrec d (Pi _ var a b) = parenthesise (d > Open) $ group $ + parens (pretty var.val <++> colon <+> softline <+> prettyPrec Open a) <++> + pretty "->" <+> softline <+> + prettyPrec Open b + prettyPrec d (Lambda _ var t) = + parenthesise (d > Open) $ + group $ + backslash <+> pretty var.val <++> + pretty "=>" <+> softline <+> + prettyPrec Open t + prettyPrec d (App t u) = + parenthesise (d >= App) $ + group $ + fillSep [prettyPrec Open t, prettyPrec App u] + prettyPrec d (Top _) = pretty "()" + prettyPrec d (Point _) = pretty "*" + prettyPrec d (Bottom _) = pretty "Void" + prettyPrec d (Absurd _ a t) = + parenthesise (d >= App) $ + group $ fillSep [pretty "absurd", prettyPrec App a, prettyPrec App t] export diff --git a/src/Obs/Term.idr b/src/Obs/Term.idr index 05b9a7f..366a4b7 100644 --- a/src/Obs/Term.idr +++ b/src/Obs/Term.idr @@ -12,9 +12,13 @@ import Text.PrettyPrint.Prettyprinter public export data Term : Nat -> Type where - Var : Bounds -> Fin n -> Term n + Var : WithBounds String -> Fin n -> Term n -- Sorts Sort : Bounds -> Sort -> Term n + -- Dependent Product + Pi : Bounds -> String -> Term n -> Term (S n) -> Term n + Lambda : Bounds -> String -> Term (S n) -> Term n + App : Term n -> Term n -> Term n -- True Top : Bounds -> Term n Point : Bounds -> Term n @@ -39,23 +43,42 @@ data Block : Nat -> Type where export fullBounds : Term n -> WithBounds (Term n) -fullBounds tm@(Var x i) = MkBounded tm False x -fullBounds tm@(Sort x s) = MkBounded tm False x -fullBounds tm@(Top x) = MkBounded tm False x -fullBounds tm@(Point x) = MkBounded tm False x -fullBounds tm@(Bottom x) = MkBounded tm False x +fullBounds tm@(Var var i) = map (\_ => tm) var +fullBounds tm@(Sort x s) = MkBounded tm False x +fullBounds tm@(Pi x var a b) = mergeBounds (mergeBounds (fullBounds a) (fullBounds b)) (MkBounded tm False x) +fullBounds tm@(Lambda x var t) = mergeBounds (fullBounds t) (MkBounded tm False x) +fullBounds tm@(App t u) = map (\_ => tm) (mergeBounds (fullBounds t) (fullBounds u)) +fullBounds tm@(Top x) = MkBounded tm False x +fullBounds tm@(Point x) = MkBounded tm False x +fullBounds tm@(Bottom x) = MkBounded tm False x fullBounds tm@(Absurd x a t) = mergeBounds (mergeBounds (fullBounds a) (fullBounds t)) (MkBounded tm False x) -- Pretty Print ---------------------------------------------------------------- export Pretty (Term n) where - prettyPrec d (Var x i) = pretty "$\{show i}" - prettyPrec d (Sort x s) = prettyPrec d s - prettyPrec d (Top x) = pretty "()" - prettyPrec d (Point x) = pretty "*" - prettyPrec d (Bottom x) = pretty "Void" - prettyPrec d (Absurd x a t) = + prettyPrec d (Var var _) = pretty var.val + prettyPrec d (Sort _ s) = prettyPrec d s + prettyPrec d (Pi _ var a b) = + parenthesise (d > Open) $ + group $ + parens (pretty var <++> colon <+> softline <+> prettyPrec Open a) <++> + pretty "->" <+> softline <+> + prettyPrec Open b + prettyPrec d (Lambda _ var t) = + parenthesise (d > Open) $ + group $ + backslash <+> pretty var <++> + pretty "=>" <+> softline <+> + prettyPrec Open t + prettyPrec d (App t u) = + parenthesise (d >= App) $ + group $ + fillSep [prettyPrec Open t, prettyPrec App u] + prettyPrec d (Top _) = pretty "()" + prettyPrec d (Point _) = pretty "*" + prettyPrec d (Bottom _) = pretty "Void" + prettyPrec d (Absurd _ a t) = parenthesise (d > Open) $ group $ fillSep [pretty "absurd", prettyPrec App a, prettyPrec App t] diff --git a/src/Obs/Typing.idr b/src/Obs/Typing.idr index e59de5d..e23a9a2 100644 --- a/src/Obs/Typing.idr +++ b/src/Obs/Typing.idr @@ -15,91 +15,208 @@ import Text.PrettyPrint.Prettyprinter.Render.Terminal %default total +-- Errors ---------------------------------------------------------------------- + +export +Error : Type -> Type -> Type +Error ann = Either (Maybe Bounds, Doc ann) + +export +printErr : Error ? a -> IO a +printErr (Left (Just b, p)) = do + () <- putDoc (pretty "typing: \{show b.startLine}:\{show b.startCol}-\{show b.endLine}:\{show b.endCol}:" <+> softline <+> p) + exitFailure +printErr (Left (Nothing, p)) = do + () <- putDoc (pretty "typing:" <+> softline <+> p) + exitFailure +printErr (Right x) = pure x + +report : Bounds -> Doc ann -> Error ann a +report = curry Left . Just + +internal : Doc ann -> Error ann a +internal = Left . (Nothing, ) + +Rename (Error ann . NormalForm) where + rename t f = pure $ rename !t f + +PointedRename (Error ann . NormalForm) where + point = pure . point + +-- Substitution ---------------------------------------------------------------- + +wkn : (k : _) -> (Fin n -> Error ann (NormalForm m)) -> Fin (k + n) -> Error ann (NormalForm (k + m)) +wkn = lift {x = Error ann . NormalForm} + +covering partial +substCnstr : Constructor n -> (Fin n -> Error ann (NormalForm m)) -> Error ann (Constructor m) +covering partial +substNtrl : Neutral n -> (Fin n -> Error ann (NormalForm m)) -> Error ann (NormalForm m) +covering partial +subst : NormalForm n -> (Fin n -> Error ann (NormalForm m)) -> Error ann (NormalForm m) +covering partial +doApp : NormalForm n -> NormalForm n -> Error ann (NormalForm n) + +substCnstr (Sort s) f = pure $ Sort s +substCnstr (Pi s s' a b) f = do + a <- subst a f + b <- subst b (wkn 1 f) + pure (Pi s s' a b) +substCnstr (Lambda t) f = do + t <- subst t (wkn 1 f) + pure (Lambda t) +substCnstr Top f = pure $ Top +substCnstr Bottom f = pure $ Bottom + +substNtrl (Var i) f = f i +substNtrl (App t u) f = do + t <- substNtrl t f + u <- subst u f + doApp t u +substNtrl Absurd f = pure $ Ntrl Absurd + +subst (Ntrl t) f = substNtrl t f +subst (Cnstr t) f = map Cnstr $ substCnstr t f +subst Irrel f = pure Irrel + +doApp (Ntrl t) u = pure $ Ntrl (App t u) +doApp Irrel u = pure $ Irrel +doApp (Cnstr (Lambda t)) u = subst t (add (Error ann . NormalForm) (pure u) (pure . point)) +doApp (Cnstr t) u = internal (pretty "wrong constructor in apply:" <++> pretty t) + +partial +subst1 : NormalForm n -> NormalForm (S n) -> Error ann (NormalForm n) +subst1 t u = subst u (add (Error ann . NormalForm) (pure t) (pure . point)) + -- Conversion ------------------------------------------------------------------ -- invariant: all definitions fully expanded -- invariant: m |- t, u <- a : s -convert : (t, u, a : NormalForm n) -> Sort -> Bool +covering partial +convert : (t, u, a : NormalForm n) -> Sort -> Error ann Bool -- In sort Prop -convert Irrel Irrel a Prop = True +convert Irrel Irrel a Prop = pure True -- In unknown type in set -convert t u (Ntrl _) (Set k) = t == u +convert t u (Ntrl _) (Set k) = pure $ t == u -- In type Set -convert (Cnstr (Sort s')) (Cnstr (Sort s'')) (Cnstr (Sort _)) (Set _) = s' == s'' -convert (Cnstr Top) (Cnstr Top) (Cnstr (Sort _)) (Set _) = True -convert (Cnstr Bottom) (Cnstr Bottom) (Cnstr (Sort _)) (Set _) = True -convert (Ntrl t) u (Cnstr (Sort s)) (Set k) = Ntrl t == u -convert t (Ntrl u) (Cnstr (Sort s)) (Set k) = t == Ntrl u +convert (Cnstr (Sort s')) (Cnstr (Sort s'')) (Cnstr (Sort _)) (Set _) = pure $ s' == s'' +convert (Cnstr (Pi s s' a b)) (Cnstr (Pi l l' a' b')) (Cnstr (Sort _)) (Set _) = + pure $ + s == l && s' == l' && !(convert a a' (cast s) (suc s)) && !(convert b b' (cast s') (suc s')) +convert (Cnstr Top) (Cnstr Top) (Cnstr (Sort _)) (Set _) = pure True +convert (Cnstr Bottom) (Cnstr Bottom) (Cnstr (Sort _)) (Set _) = pure True +convert (Ntrl t) u (Cnstr (Sort s)) (Set k) = pure $ Ntrl t == u +convert t (Ntrl u) (Cnstr (Sort s)) (Set k) = pure $ t == Ntrl u +convert t u (Cnstr (Sort s)) (Set k) = pure $ False +-- In type Pi +convert t u (Cnstr (Pi s s' a b)) (Set k) = do + t <- doApp (weaken 1 t) (point FZ) + u <- doApp (weaken 1 u) (point FZ) + convert t u b s' -- Default -convert _ _ _ _ = False +convert t u a s = internal $ fillSep ["invalid convert:", prettyPrec App t, prettyPrec App u, prettyPrec App a, prettyPrec App s] + -- Typing Contexts ------------------------------------------------------------- -weaken : (m : _) -> NormalForm n -> NormalForm (m + n) -weaken m t = rename t (shift m) +infix 5 ::< -index : Context n -> Fin n -> (NormalForm n, NormalForm n, Sort) -index (ctx :< def) FZ = bimap (weaken 1) (mapFst (weaken 1)) (def.tm, def.ty, def.sort) -index (ctx :< def) (FS i) = bimap (weaken 1) (mapFst (weaken 1)) $ index ctx i +data TyContext : Nat -> Nat -> Type where + Nil : TyContext 0 0 + (:<) : TyContext m n -> NormalForm.Definition n -> TyContext m (S n) + (::<) : TyContext m n -> (String, NormalForm n, Sort) -> TyContext (S m) (S n) -asSubst : Context n -> Fin n -> NormalForm 0 -asSubst (ctx :< def) FZ = subst def.tm (asSubst ctx) -asSubst (ctx :< def) (FS i) = asSubst ctx i +fromContext : Context n -> TyContext 0 n +fromContext [] = [] +fromContext (ctx :< def) = fromContext ctx :< def --- Checking and Inference ------------------------------------------------------ +countVars : TyContext m n -> Fin (S n) +countVars [] = FZ +countVars (ctx :< y) = weaken $ countVars ctx +countVars (ctx ::< y) = FS $ countVars ctx -export -Error : Type -> Type -> Type -Error ann = Either (Bounds, Doc ann) +index : TyContext m n -> Fin n -> (NormalForm n, NormalForm n, Sort) +index (ctx :< def) FZ = (weaken 1 def.tm, weaken 1 def.ty, def.sort) +index (ctx ::< (_, ty, s)) FZ = (point FZ, weaken 1 ty, s) +index (ctx :< _) (FS i) = bimap (weaken 1) (mapFst (weaken 1)) $ index ctx i +index (ctx ::< _) (FS i) = bimap (weaken 1) (mapFst (weaken 1)) $ index ctx i -export -printErr : Error ? a -> IO a -printErr (Left (b, p)) = do - () <- putDoc (pretty "typing: \{show b.startLine}:\{show b.startCol}-\{show b.endLine}:\{show b.endCol}:" <+> softline <+> p) - exitFailure -printErr (Right x) = pure x +covering partial +asSubst : (ctx : TyContext m n) -> Fin n -> Error ann (NormalForm m) +asSubst (ctx :< def) FZ = subst def.tm (asSubst ctx) +asSubst (ctx ::< _) FZ = pure $ point FZ +asSubst (ctx :< def) (FS i) = asSubst ctx i +asSubst (ctx ::< _) (FS i) = map (weaken 1) (asSubst ctx i) -report : Bounds -> Doc ann -> Error ann a -report = curry Left - -check : Context n -> Term n -> NormalForm n -> Sort -> Error ann (NormalForm n) -infer : Context n -> Term n -> Error ann (NormalForm n, NormalForm n, Sort) +-- Checking and Inference ------------------------------------------------------ +covering partial +check : TyContext m n -> Term n -> NormalForm n -> Sort -> Error ann (NormalForm n) +covering partial +infer : TyContext m n -> Term n -> Error ann (NormalForm n, NormalForm n, Sort) +covering partial +inferSort : {default "type mismatch" tag : String} + -> TyContext m n -> Term n -> Error ann (NormalForm n, Sort) + +check ctx (Lambda _ var t) (Cnstr (Pi s s' a b)) _ = do + t <- check (ctx ::< (var, a, s)) t b s' + pure (Cnstr $ Lambda t) +check ctx tm@(Lambda _ _ _) ty _ = + report (fullBounds tm).bounds + (pretty "type mismatch: expected pi" <+> comma <+> softline <+> "got" <++> pretty ty) check ctx tm ty s = do let bounds = (fullBounds tm).bounds (tm, ty', s') <- infer ctx tm let True = s == s' | False => report bounds (pretty "sort mismatch: expected" <++> pretty s <+> comma <+> softline <+> "got" <++> pretty s') - let True = convert (subst ty $ asSubst ctx) (subst ty' $ asSubst ctx) (Cnstr (Sort s)) (suc s) + True <- convert !(subst ty $ asSubst ctx) !(subst ty' $ asSubst ctx) (cast s) (suc s) | False => report bounds (pretty "type mismatch: expected" <++> pretty ty <+> comma <+> softline <+> "got" <++> pretty ty') pure tm infer ctx (Var b i) = pure $ index ctx i -infer ctx (Sort b s) = pure $ (Cnstr (Sort s), Cnstr (Sort (suc s)), suc (suc s)) -infer ctx (Top b) = pure $ (Cnstr Top, Cnstr (Sort Prop), Set 0) +infer ctx (Sort b s) = pure $ (cast s, cast (suc s), suc (suc s)) +infer ctx (Pi _ var a b) = do + (a, s) <- inferSort ctx a + let aDef = MkDefinition {name = var, sort = suc s, ty = cast s, tm = a} + (b, s') <- inferSort (ctx :< aDef) b + pure (Cnstr (Pi s s' a b), cast (s ~> s'), suc (s ~> s')) +infer ctx tm@(Lambda _ _ _) = report (fullBounds tm).bounds (pretty "cannot infer type:" <+> softline <+> pretty tm) +infer ctx (App t u) = do + let bounds = (fullBounds t).bounds + (t, Cnstr (Pi s s' a b), _) <- infer ctx t + | (_, t, _) => report bounds (pretty "wrong type to apply:" <+> softline <+> pretty t) + u <- check ctx u a s + res <- doApp t u + ty <- subst1 t b + pure (res, ty, s') +infer ctx (Top b) = pure $ (Cnstr Top, cast Prop, Set 0) infer ctx (Point b) = pure $ (Irrel, Cnstr Top, Prop) -infer ctx (Bottom b) = pure $ (Cnstr Bottom, Cnstr (Sort Prop), Set 0) +infer ctx (Bottom b) = pure $ (Cnstr Bottom, cast Prop, Set 0) infer ctx (Absurd b a t) = do - (a, Cnstr (Sort s), _) <- infer ctx a - | (_, ty, _) => report (fullBounds a).bounds - (pretty "type mismatch: expected sort" <+> comma <+> softline <+> "got" <++> pretty ty) + (a, s) <- inferSort ctx a _ <- check ctx t (Cnstr Bottom) Prop pure (Ntrl Absurd, a, s) +inferSort ctx a = do + (a, Cnstr (Sort s), _) <- infer ctx a + | (_, ty, _) => report (fullBounds a).bounds + (pretty "\{tag}: expected sort" <+> comma <+> softline <+> "got" <++> pretty ty) + pure (a, s) + -- Checking Definitions and Blocks --------------------------------------------- +covering partial checkDef : Context n -> Term.Definition n -> Error ann (NormalForm.Definition n) checkDef ctx def = do let tyBounds = (fullBounds def.ty).bounds let tmBounds = (fullBounds def.tm).bounds - (ty, Cnstr (Sort sort), _) <- infer ctx def.ty - | (_, a, _) => report tyBounds - (pretty "invalid declaration: expected sort" <+> comma <+> softline <+> "got" <++> pretty a) - tm <- check ctx def.tm ty sort - pure $ MkDefinition {name = Just def.name, ty, tm, sort} + (ty, sort) <- inferSort {tag = "invalid declaration"} (fromContext ctx) def.ty + tm <- check (fromContext ctx) def.tm ty sort + pure $ MkDefinition {name = def.name, ty, tm, sort} +covering partial export checkBlock : Block n -> Error ann (Context n) checkBlock [] = pure [] |