Agda-2.3.2.2: examples/vfl/Typechecker.agda
module Typechecker where
data Nat : Set where
zero : Nat
suc : Nat -> Nat
{-# BUILTIN NATURAL Nat #-}
{-# BUILTIN ZERO zero #-}
{-# BUILTIN SUC suc #-}
_+_ : Nat -> Nat -> Nat
zero + m = m
suc n + m = suc (n + m)
data Fin : Nat -> Set where
f0 : {n : Nat} -> Fin (suc n)
fs : {n : Nat} -> Fin n -> Fin (suc n)
infixl 30 _::_ _++_
data Vect (A : Set) : Nat -> Set where
ε : Vect A zero
_::_ : {n : Nat} -> Vect A n -> A -> Vect A (suc n)
fs^ : {n : Nat}(m : Nat) -> Fin n -> Fin (m + n)
fs^ zero i = i
fs^ (suc m) i = fs (fs^ m i)
_++_ : {A : Set}{n m : Nat} -> Vect A n -> Vect A m -> Vect A (m + n)
xs ++ ε = xs
xs ++ (ys :: y) = (xs ++ ys) :: y
data Chop {A : Set} : {n : Nat} -> Vect A n -> Fin n -> Set where
chopGlue : {m n : Nat}(xs : Vect A n)(x : A)(ys : Vect A m) ->
Chop (xs :: x ++ ys) (fs^ m f0)
chop : {A : Set}{n : Nat}(xs : Vect A n)(i : Fin n) -> Chop xs i
chop ε ()
chop (xs :: x) f0 = chopGlue xs x ε
chop (xs :: y) (fs i) with chop xs i
chop (.(xs :: x ++ ys) :: y) (fs .(fs^ m f0))
| chopGlue {m} xs x ys = chopGlue xs x (ys :: y)
infixr 40 _⊃_
data Simp : Set where
o : Simp
_⊃_ : Simp -> Simp -> Simp
infix 20 Simp-_
data Simp-_ : Simp -> Set where
neqo : Simp -> Simp -> Simp- o
neq⊃ : {S T : Simp} -> Simp- (S ⊃ T)
neqT : {S T : Simp}(T' : Simp- T) -> Simp- (S ⊃ T)
neqS : {S : Simp}{T₁ : Simp}(S' : Simp- S)(T₂ : Simp) -> Simp- (S ⊃ T₁)
infixl 60 _∖_
_∖_ : (S : Simp) -> Simp- S -> Simp
.o ∖ neqo S T = S ⊃ T
.(_ ⊃ _) ∖ neq⊃ = o
.(S ⊃ T) ∖ neqT {S}{T} T' = S ⊃ T ∖ T'
.(S ⊃ _) ∖ neqS {S} S' T₂ = S ∖ S' ⊃ T₂
data SimpEq? (S : Simp) : Simp -> Set where
simpSame : SimpEq? S S
simpDiff : (T : Simp- S) -> SimpEq? S (S ∖ T)
simpEq? : (S T : Simp) -> SimpEq? S T
simpEq? o o = simpSame
simpEq? o (S ⊃ T) = simpDiff (neqo S T)
simpEq? (S ⊃ T) o = simpDiff neq⊃
simpEq? (S₁ ⊃ T₁) (S₂ ⊃ T₂) with simpEq? S₁ S₂
simpEq? (S ⊃ T₁) (.S ⊃ T₂) | simpSame with simpEq? T₁ T₂
simpEq? (S ⊃ T) (.S ⊃ .T) | simpSame | simpSame = simpSame
simpEq? (S ⊃ T) (.S ⊃ .(T ∖ T')) | simpSame | simpDiff T' = simpDiff (neqT T')
simpEq? (S ⊃ T₁) (.(S ∖ S') ⊃ T₂) | simpDiff S' = simpDiff (neqS S' T₂)
data Term : Nat -> Set where
var : {n : Nat} -> Fin n -> Term n
app : {n : Nat} -> Term n -> Term n -> Term n
lam : {n : Nat} -> Simp -> Term (suc n) -> Term n
data Good : {n : Nat} -> Vect Simp n -> Simp -> Set where
gVar : {n m : Nat}(Γ : Vect Simp n)(T : Simp)(Δ : Vect Simp m) ->
Good (Γ :: T ++ Δ) T
gApp : {n : Nat}{Γ : Vect Simp n}{S T : Simp} ->
Good Γ (S ⊃ T) -> Good Γ S -> Good Γ T
gLam : {n : Nat}{Γ : Vect Simp n}(S : Simp){T : Simp} ->
Good (Γ :: S) T -> Good Γ (S ⊃ T)
g : {n : Nat}{Γ : Vect Simp n}(T : Simp) -> Good Γ T -> Term n
g T (gVar{n}{m} Γ .T Δ) = var (fs^ m f0)
g T (gApp f s) = app (g _ f) (g _ s)
g .(S ⊃ _) (gLam S t) = lam S (g _ t)
data Bad {n : Nat}(Γ : Vect Simp n) : Set where
bNonFun : Good Γ o -> Term n -> Bad Γ
bMismatch : {S T : Simp}(S' : Simp- S) ->
Good Γ (S ⊃ T) -> Good Γ (S ∖ S') -> Bad Γ
bArg : {S T : Simp} -> Good Γ (S ⊃ T) -> Bad Γ -> Bad Γ
bFun : Bad Γ -> Term n -> Bad Γ
bLam : (S : Simp) -> Bad (Γ :: S) -> Bad Γ
b : {n : Nat}{Γ : Vect Simp n} -> Bad Γ -> Term n
b (bNonFun f s) = app (g o f) s
b (bMismatch _ f s) = app (g _ f) (g _ s)
b (bArg f s) = app (g _ f) (b s)
b (bFun f s) = app (b f) s
b (bLam S t) = lam S (b t)
data TypeCheck? {n : Nat}(Γ : Vect Simp n) : Term n -> Set where
good : (T : Simp)(t : Good Γ T) -> TypeCheck? Γ (g T t)
bad : (t : Bad Γ) -> TypeCheck? Γ (b t)
typeCheck? : {n : Nat}(Γ : Vect Simp n)(t : Term n) -> TypeCheck? Γ t
typeCheck? Γ (var i) with chop Γ i
typeCheck? .(Γ :: T ++ Δ) (var ._) | chopGlue Γ T Δ = good T (gVar Γ T Δ)
typeCheck? Γ (app f s) with typeCheck? Γ f
typeCheck? Γ (app .(g (S ⊃ T) f) s) | good (S ⊃ T) f with typeCheck? Γ s
typeCheck? Γ (app .(g (S ⊃ T) f) .(g S' s))
| good (S ⊃ T) f | good S' s with simpEq? S S'
typeCheck? Γ (app .(g (S ⊃ T) f) .(g S s))
| good (S ⊃ T) f | good .S s | simpSame = good T (gApp f s)
typeCheck? Γ (app .(g (S ⊃ T) f) .(g (S ∖ S') s))
| good (S ⊃ T) f | good .(S ∖ S') s | simpDiff S' = bad (bMismatch S' f s)
typeCheck? Γ (app .(g (S ⊃ T) f) .(b s))
| good (S ⊃ T) f | bad s = bad (bArg f s)
typeCheck? Γ (app .(g o f) s) | good o f = bad (bNonFun f s)
typeCheck? Γ (app .(b f) s) | bad f = bad (bFun f s)
typeCheck? Γ (lam S t) with typeCheck? (Γ :: S) t
typeCheck? Γ (lam S .(g T t)) | good T t = good (S ⊃ T) (gLam S t)
typeCheck? Γ (lam S .(b t)) | bad t = bad (bLam S t)