module Check where
open import Prelude
open import Exp
open import Term
private
variable
a b : Ty
Γ : Context
data CheckError : Set where
unboundIdentifier : Ident → _
tooManyArguments : Ty → List Exp → _
inferUntypedLambda : _
notSubtype : (a b : Ty) → _
data Scope : Context → Set where
empty : Scope []
cons : (x : Ident) (a : Ty) (sc : Scope Γ) → Scope (a ∷ Γ)
lookupIdent : Scope Γ → Ident → Maybe (∃ λ a → a ∈ Γ)
lookupIdent empty x = nothing
lookupIdent (cons y a sc) x =
case y String.≟ x of λ where
(yes _) → just (a , zero)
(no _) → case lookupIdent sc x of λ where
(just (a , x)) → just (a , suc x)
nothing → nothing
data Infer (Γ : Context) : Set where
inferred : (a : Ty) (t : Term Γ a) → _
failed : (err : CheckError) → _
data Check (Γ : Context) (a : Ty) : Set where
checked : (t : Term Γ a) → _
failed : (err : CheckError) → _
mutual
infer : Scope Γ → Exp → Infer Γ
infer sc (ne x es) =
case lookupIdent sc x of λ where
nothing → failed (unboundIdentifier x)
(just (a , y)) → inferSpine sc a (Term.var y) es
infer sc (abs (uBind x) e es) = failed inferUntypedLambda
infer sc (abs (tBind x a) e es) =
case infer (cons x a sc) e of λ where
(inferred b t) → inferSpine sc (a ⇒ b) (abs t) es
(failed err) → failed err
inferSpine : Scope Γ → (a : Ty) → Term Γ a → List Exp → Infer Γ
inferSpine sc a t [] = inferred a t
inferSpine sc (` α) t (e ∷ es) = failed (tooManyArguments (` α) (e ∷ es))
inferSpine sc (a ⇒ b) t (e ∷ es) =
case check sc e a of λ where
(checked u) → inferSpine sc b (app t u) es
(failed err) → failed err
check : Scope Γ → Exp → (a : Ty) → Check Γ a
check sc (lam (uBind x) e) (a ⇒ c) =
case check (cons x a sc) e c of λ where
(checked t) → checked (abs t)
(failed err) → failed err
check sc e a =
case infer sc e of λ where
(inferred b u) →
case eqType b a of λ where
(yes refl) → checked u
(no _) → failed (notSubtype b a)
(failed err) → failed err