Course Webpage for B522 Programming Language Foundations, Spring 2020, Indiana University
{-# OPTIONS --rewriting #-}
module SystemF where
open import Agda.Builtin.Equality
open import Agda.Builtin.Equality.Rewrite
open import Data.Bool using () renaming (Bool to 𝔹)
open import Data.List using (List; []; _∷_)
open import Data.Nat using (ℕ; zero; suc; _<_; _≤_; z≤n; s≤s)
open import Data.Nat.Properties using (≤-trans; ≤-step; ≤-refl; ≤-pred)
open import Data.Product using (_×_; Σ; Σ-syntax; ∃; ∃-syntax; proj₁; proj₂)
renaming (_,_ to ⟨_,_⟩)
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; _≢_; refl; sym; cong; cong₂; subst)
open Eq.≡-Reasoning using (begin_; _≡⟨⟩_; _≡⟨_⟩_; _∎)
import Syntax
The idea here is to use Agda values as primitive constants. We include natural numbers, Booleans, and Agda functions over naturals and Booleans.
The Base
and Prim
data types describe the types of constants.
data Base : Set where
B-Nat : Base
B-Bool : Base
data Prim : Set where
base : Base → Prim
_⇛_ : Base → Prim → Prim
The base-rep
and rep
functions map from the type descriptors to
the Agda types that we will use to represent the constants.
base-rep : Base → Set
base-rep B-Nat = ℕ
base-rep B-Bool = 𝔹
rep : Prim → Set
rep (base b) = base-rep b
rep (b ⇛ p) = base-rep b → rep p
We use the abstract-binding-trees library to represent terms.
data Op : Set where
op-lam : Op
op-app : Op
op-const : (p : Prim) → rep p → Op
op-abs : Op
op-tyapp : Op
sig : Op → List ℕ
sig op-lam = 1 ∷ []
sig op-app = 0 ∷ 0 ∷ []
sig (op-const p k) = []
sig op-abs = 0 ∷ []
sig op-tyapp = 0 ∷ []
open Syntax using (Rename; _•_; ↑; id; ext; ⦉_⦊; _⨟ᵣ_)
open Syntax.OpSig Op sig
using (`_; _⦅_⦆; cons; nil; bind; ast; _[_]; Subst; ⟪_⟫; ⟦_⟧; exts; rename)
renaming (ABT to Term)
infixl 7 _·_
pattern $ p k = (op-const p k) ⦅ nil ⦆
pattern ƛ N = op-lam ⦅ cons (bind (ast N)) nil ⦆
pattern _·_ L M = op-app ⦅ cons (ast L) (cons (ast M) nil) ⦆
pattern Λ N = op-abs ⦅ cons (ast N) nil ⦆
pattern _[·] N = op-tyapp ⦅ cons (ast N) nil ⦆
data TyOp : Set where
op-nat : TyOp
op-bool : TyOp
op-fun : TyOp
op-all : TyOp
tysig : TyOp → List ℕ
tysig op-nat = []
tysig op-bool = []
tysig op-fun = 0 ∷ 0 ∷ []
tysig op-all = 1 ∷ []
open Syntax.OpSig TyOp tysig
using (_⨟_;
rename-subst-commute; ext-cons-shift; compose-rename;
rename→subst; rename-subst; exts-cons-shift; commute-subst)
renaming (ABT to Type; `_ to tyvar; _⦅_⦆ to _〘_〙;
cons to tycons; nil to tynil; bind to tybind; ast to tyast;
_[_] to _⦗_⦘; Subst to TySubst; ⟪_⟫ to ⸂_⸃; ⟦_⟧ to ⧼_⧽;
exts to tyexts; rename to tyrename)
pattern Nat = op-nat 〘 tynil 〙
pattern Bool = op-bool 〘 tynil 〙
pattern _⇒_ A B = op-fun 〘 tycons (tyast A) (tycons (tyast B) tynil) 〙
pattern all A = op-all 〘 tycons (tybind (tyast A)) tynil 〙
typeof-base : Base → Type
typeof-base B-Nat = Nat
typeof-base B-Bool = Bool
typeof : Prim → Type
typeof (base b) = typeof-base b
typeof (b ⇛ p) = typeof-base b ⇒ typeof p
data Context : Set where
∅ : Context
_,_ : Context → Type → Context
infix 4 _∋_⦂_
data _∋_⦂_ : Context → ℕ → Type → Set where
Z : ∀ {Γ A}
------------------
→ Γ , A ∋ 0 ⦂ A
S : ∀ {Γ x A B}
→ Γ ∋ x ⦂ A
------------------
→ Γ , B ∋ (suc x) ⦂ A
ctx-rename : Rename → Context → Context
ctx-rename ρ ∅ = ∅
ctx-rename ρ (Γ , A) = ctx-rename ρ Γ , tyrename ρ A
ctx-subst : TySubst → Context → Context
ctx-subst σ ∅ = ∅
ctx-subst σ (Γ , A) = ctx-subst σ Γ , ⸂ σ ⸃ A
infix 4 _⊢_
data _⊢_ : ℕ → Type → Set where
⊢var : ∀{Δ α}
→ α < Δ
-----------
→ Δ ⊢ tyvar α
⊢nat : ∀{Δ}
-------
→ Δ ⊢ Nat
⊢bool : ∀{Δ}
--------
→ Δ ⊢ Bool
⊢fun : ∀{Δ A B}
→ Δ ⊢ A → Δ ⊢ B
---------------
→ Δ ⊢ A ⇒ B
⊢all : ∀{Δ A}
→ suc Δ ⊢ A
---------
→ Δ ⊢ all A
infix 4 _⨟_⊢_⦂_
data _⨟_⊢_⦂_ : ℕ → Context → Term → Type → Set where
-- Constants
⊢$ : ∀{Γ Δ p k A}
→ A ≡ typeof p
-------------
→ Δ ⨟ Γ ⊢ $ p k ⦂ A
-- Axiom
⊢` : ∀ {Γ Δ x A}
→ Γ ∋ x ⦂ A
-----------
→ Δ ⨟ Γ ⊢ ` x ⦂ A
-- ⇒-I
⊢ƛ : ∀ {Γ Δ N A B}
→ Δ ⊢ A
→ Δ ⨟ Γ , A ⊢ N ⦂ B
-------------------
→ Δ ⨟ Γ ⊢ ƛ N ⦂ A ⇒ B
-- ⇒-E
⊢· : ∀ {Γ Δ L M A B}
→ Δ ⨟ Γ ⊢ L ⦂ A ⇒ B
→ Δ ⨟ Γ ⊢ M ⦂ A
-------------
→ Δ ⨟ Γ ⊢ L · M ⦂ B
-- all-I
⊢Λ : ∀ {Γ Δ A N}
→ suc Δ ⨟ ctx-rename (↑ 1) Γ ⊢ N ⦂ A
---------------------------------
→ Δ ⨟ Γ ⊢ Λ N ⦂ all A
-- all-E
⊢[·] : ∀{Γ Δ A B N}
→ Δ ⊢ B
→ Δ ⨟ Γ ⊢ N ⦂ all A
----------------------
→ Δ ⨟ Γ ⊢ N [·] ⦂ A ⦗ B ⦘
data Value : Term → Set where
V-ƛ : ∀ {N : Term}
---------------------------
→ Value (ƛ N)
V-const : ∀ {p k}
-----------------
→ Value ($ p k)
V-Λ : ∀ {N : Term}
-----------------
→ Value (Λ N)
data Frame : Set where
□·_ : Term → Frame
_·□ : (M : Term) → (v : Value M) → Frame
□[·] : Frame
The plug
function fills a frame’s hole with a term.
plug : Term → Frame → Term
plug L (□· M) = L · M
plug M ((L ·□) v) = L · M
plug M (□[·]) = M [·]
infix 4 _—→_
data _—→_ : Term → Term → Set where
ξ : ∀ {M M′}
→ (F : Frame)
→ M —→ M′
---------------------
→ plug M F —→ plug M′ F
β-ƛ : ∀ {N V}
→ Value V
--------------------
→ (ƛ N) · V —→ N [ V ]
δ : ∀ {b p f k}
---------------------------------------------
→ ($ (b ⇛ p) f) · ($ (base b) k) —→ ($ p (f k))
β-Λ : ∀{N}
--------------
→ (Λ N) [·] —→ N
infix 2 _—↠_
infixr 2 _—→⟨_⟩_
infix 3 _■
data _—↠_ : Term → Term → Set where
_■ : ∀ M
---------
→ M —↠ M
_—→⟨_⟩_ : ∀ L {M N}
→ L —→ M
→ M —↠ N
---------
→ L —↠ N
data Function : Term → Set where
Fun-ƛ : ∀ {N} → Function (ƛ N)
Fun-prim : ∀{b p k} → Function ($ (b ⇛ p) k)
canonical-fun : ∀{V A B}
→ 0 ⨟ ∅ ⊢ V ⦂ A ⇒ B
→ Value V
----------
→ Function V
canonical-fun ⊢V V-ƛ = Fun-ƛ
canonical-fun (⊢$ {p = base B-Nat} ()) (V-const {_} {k})
canonical-fun (⊢$ {p = base B-Bool} ()) (V-const {_} {k})
canonical-fun (⊢$ {p = b ⇛ p} eq) (V-const {_} {k}) = Fun-prim
data Constant : Base → Term → Set where
base-const : ∀{b k} → Constant b ($ (base b) k)
canonical-base : ∀{b V A}
→ A ≡ typeof-base b
→ 0 ⨟ ∅ ⊢ V ⦂ A
→ Value V
------------
→ Constant b V
canonical-base {B-Nat} () (⊢ƛ wft ⊢V) V-ƛ
canonical-base {B-Bool} () (⊢ƛ wft ⊢V) V-ƛ
canonical-base {B-Nat} eq (⊢$ {p = base B-Nat} refl) V-const = base-const
canonical-base {B-Bool} eq (⊢$ {p = base B-Bool} refl) V-const = base-const
canonical-base {B-Nat} refl (⊢$ {p = b' ⇛ p} ()) V-const
canonical-base {B-Bool} refl (⊢$ {p = b' ⇛ p} ()) V-const
data Forall : Term → Set where
Forall-Λ : ∀ {N} → Forall (Λ N)
canonical-all : ∀{V A}
→ 0 ⨟ ∅ ⊢ V ⦂ all A
→ Value V
--------
→ Forall V
canonical-all {_} (⊢$ {p = base B-Nat} ()) V-const
canonical-all {_} (⊢$ {p = base B-Bool} ()) V-const
canonical-all {V} ⊢V V-Λ = Forall-Λ
data Progress (M : Term) : Set where
step : ∀ {N}
→ M —→ N
----------
→ Progress M
done :
Value M
----------
→ Progress M
progress : ∀ {M A}
→ 0 ⨟ ∅ ⊢ M ⦂ A
------------
→ Progress M
progress (⊢` ())
progress (⊢$ _) = done V-const
progress (⊢ƛ wft ⊢N) = done V-ƛ
progress (⊢· {L = L}{M}{A}{B} ⊢L ⊢M)
with progress ⊢L
... | step L—→L′ = step (ξ (□· M) L—→L′)
... | done VL
with progress ⊢M
... | step M—→M′ = step (ξ ((L ·□) VL) M—→M′)
... | done VM
with canonical-fun ⊢L VL
... | Fun-ƛ = step (β-ƛ VM)
... | Fun-prim {b}{p}{k}
with ⊢L
... | ⊢$ refl
with canonical-base refl ⊢M VM
... | base-const = step δ
progress (⊢Λ ⊢N) = done V-Λ
progress (⊢[·] wfB ⊢N)
with progress ⊢N
... | step N—→N′ = step (ξ □[·] N—→N′)
... | done VN
with canonical-all ⊢N VN
... | Forall-Λ {M} = step β-Λ
ctx-rename-pres : ∀{Γ x A ρ}
→ Γ ∋ x ⦂ A
→ ctx-rename ρ Γ ∋ x ⦂ tyrename ρ A
ctx-rename-pres Z = Z
ctx-rename-pres (S ∋x) = S (ctx-rename-pres ∋x)
ctx-rename-reflect : ∀{ρ}{Γ}{x}{A}
→ ctx-rename ρ Γ ∋ x ⦂ A
→ Σ[ B ∈ Type ] A ≡ tyrename ρ B × Γ ∋ x ⦂ B
ctx-rename-reflect {ρ} {Γ , C} {zero} Z = ⟨ C , ⟨ refl , Z ⟩ ⟩
ctx-rename-reflect {ρ} {Γ , C} {suc x} (S ∋x)
with ctx-rename-reflect {ρ} {Γ} {x} ∋x
... | ⟨ B , ⟨ refl , ∋x' ⟩ ⟩ =
⟨ B , ⟨ refl , (S ∋x') ⟩ ⟩
compose-ctx-rename : ∀{Γ}{ρ₁}{ρ₂}
→ ctx-rename ρ₂ (ctx-rename ρ₁ Γ) ≡ ctx-rename (ρ₁ ⨟ᵣ ρ₂) Γ
compose-ctx-rename {∅} {ρ₁} {ρ₂} = refl
compose-ctx-rename {Γ , A} {ρ₁} {ρ₂}
rewrite compose-rename {A} {ρ₁} {ρ₂}
| compose-ctx-rename {Γ} {ρ₁} {ρ₂} = refl
ctx-subst-pres : ∀{Γ x A σ}
→ Γ ∋ x ⦂ A
→ ctx-subst σ Γ ∋ x ⦂ ⸂ σ ⸃ A
ctx-subst-pres Z = Z
ctx-subst-pres (S ∋x) = S (ctx-subst-pres ∋x)
ctx-rename-subst : ∀ ρ Γ → ctx-rename ρ Γ ≡ ctx-subst (rename→subst ρ) Γ
ctx-rename-subst ρ ∅ = refl
ctx-rename-subst ρ (Γ , A)
rewrite rename-subst ρ A
| ctx-rename-subst ρ Γ = refl
compose-ctx-subst : ∀{Γ}{σ₁}{σ₂}
→ ctx-subst σ₂ (ctx-subst σ₁ Γ) ≡ ctx-subst (σ₁ ⨟ σ₂) Γ
compose-ctx-subst {∅} {σ₁} {σ₂} = refl
compose-ctx-subst {Γ , A} {σ₁} {σ₂}
rewrite compose-ctx-subst {Γ} {σ₁} {σ₂} = refl
WFRename : ℕ → Rename → ℕ → Set
WFRename Δ ρ Δ′ = ∀{α} → α < Δ → Δ′ ⊢ tyvar (⦉ ρ ⦊ α)
ext-pres-wf : ∀{ρ Δ Δ′}
→ WFRename Δ ρ Δ′
→ WFRename (suc Δ) (ext ρ) (suc Δ′)
ext-pres-wf {ρ} ⊢ρ {zero} α<Δ = ⊢var (s≤s z≤n)
ext-pres-wf {ρ} ⊢ρ {suc α} α<Δ
with ⊢ρ {α} (≤-pred α<Δ)
... | ⊢var lt = ⊢var (s≤s lt)
rename-pres-wf : ∀{ρ}{Δ Δ′}{A}
→ WFRename Δ ρ Δ′
→ Δ ⊢ A
→ Δ′ ⊢ tyrename ρ A
rename-pres-wf ΔσΔ′ (⊢var α) = ΔσΔ′ α
rename-pres-wf ΔσΔ′ ⊢nat = ⊢nat
rename-pres-wf ΔσΔ′ ⊢bool = ⊢bool
rename-pres-wf {σ} ΔσΔ′ (⊢fun ⊢A ⊢B) =
⊢fun (rename-pres-wf {σ} ΔσΔ′ ⊢A) (rename-pres-wf {σ} ΔσΔ′ ⊢B)
rename-pres-wf {ρ} ΔσΔ′ (⊢all ⊢A) =
let IH = rename-pres-wf {ρ = ext ρ} (ext-pres-wf ΔσΔ′) ⊢A in
⊢all IH
WTRename : Context → Rename → Context → Set
WTRename Γ ρ Γ′ = ∀ {x A} → Γ ∋ x ⦂ A → Γ′ ∋ ⦉ ρ ⦊ x ⦂ A
ctx-ren-ren : ∀{ρ}{γ}{Γ}{Γ′}
→ WTRename Γ ρ Γ′
→ WTRename (ctx-rename γ Γ) ρ (ctx-rename γ Γ′)
ctx-ren-ren {ρ}{γ}{Γ}{Γ′} ΓρΓ′ {x}{A} ∋x
with ctx-rename-reflect ∋x
... | ⟨ B , ⟨ refl , ∋x' ⟩ ⟩ =
let ∋x'' = ΓρΓ′ {x}{B} ∋x' in
ctx-rename-pres ∋x''
ext-pres : ∀ {Γ Γ′ ρ B}
→ WTRename Γ ρ Γ′
--------------------------------
→ WTRename (Γ , B) (ext ρ) (Γ′ , B)
ext-pres {ρ = ρ } ⊢ρ Z = Z
ext-pres {ρ = ρ } ⊢ρ (S {x = x} ∋x) = S (⊢ρ ∋x)
rename-pres : ∀ {Γ Γ′ Δ ρ M A}
→ WTRename Γ ρ Γ′
→ Δ ⨟ Γ ⊢ M ⦂ A
------------------
→ Δ ⨟ Γ′ ⊢ rename ρ M ⦂ A
rename-pres ⊢ρ (⊢$ eq) = ⊢$ eq
rename-pres ⊢ρ (⊢` ∋w) = ⊢` (⊢ρ ∋w)
rename-pres {ρ = ρ} ⊢ρ (⊢ƛ wf ⊢N) =
⊢ƛ wf (rename-pres {ρ = ext ρ} (ext-pres {ρ = ρ} ⊢ρ) ⊢N)
rename-pres {ρ = ρ} ⊢ρ (⊢· ⊢L ⊢M) =
⊢· (rename-pres {ρ = ρ} ⊢ρ ⊢L) (rename-pres {ρ = ρ} ⊢ρ ⊢M)
rename-pres {ρ = ρ} ⊢ρ (⊢Λ ⊢N) =
⊢Λ (rename-pres {ρ = ρ} (ctx-ren-ren {ρ} ⊢ρ) ⊢N)
rename-pres {ρ = ρ} ⊢ρ (⊢[·] wf ⊢N) = ⊢[·] wf (rename-pres {ρ = ρ} ⊢ρ ⊢N)
rename-base : ∀ ρ b
→ tyrename ρ (typeof-base b) ≡ typeof-base b
rename-base σ B-Nat = refl
rename-base σ B-Bool = refl
rename-prim : ∀ ρ p
→ tyrename ρ (typeof p) ≡ typeof p
rename-prim σ (base B-Nat) = refl
rename-prim σ (base B-Bool) = refl
rename-prim σ (b ⇛ p)
with rename-base σ b | rename-prim σ p
... | eq1 | eq2 rewrite eq1 | eq2 = refl
ty-rename : ∀{ρ : Rename}{Δ Δ′}{Γ}{N}{A}
→ WFRename Δ ρ Δ′
→ Δ ⨟ Γ ⊢ N ⦂ A
-------------------------------------
→ Δ′ ⨟ ctx-rename ρ Γ ⊢ N ⦂ tyrename ρ A
ty-rename {ρ} {Δ} {Δ'} {Γ} {_} {A} ΔρΔ′ (⊢$ {p = p} refl) = ⊢$ (rename-prim ρ p)
ty-rename {ρ} {Δ} {Δ'} {Γ} {_} {A} ΔρΔ′ (⊢` ∋x) = ⊢` (ctx-rename-pres ∋x)
ty-rename {ρ} {Δ} {Δ'} {Γ} {_} {.(_ ⇒ _)} ΔρΔ′ (⊢ƛ wf ⊢N) =
⊢ƛ (rename-pres-wf {ρ} ΔρΔ′ wf) (ty-rename ΔρΔ′ ⊢N)
ty-rename {ρ} {Δ} {Δ'} {Γ} {_} {A} ΔρΔ′ (⊢· ⊢L ⊢M) =
⊢· (ty-rename ΔρΔ′ ⊢L ) (ty-rename ΔρΔ′ ⊢M)
ty-rename {ρ} {Δ} {Δ'} {Γ} {Λ N} {.(all _)} ΔρΔ′ (⊢Λ {A = A} ⊢N)
with ty-rename {ext ρ} (ext-pres-wf ΔρΔ′) ⊢N
... | IH =
⊢Λ (subst (λ □ → suc Δ' ⨟ □ ⊢ N ⦂ tyrename (ext ρ) A) EQ IH)
where
EQ = begin
ctx-rename (ext ρ) (ctx-rename (↑ 1) Γ)
≡⟨ compose-ctx-rename ⟩
ctx-rename (↑ 1 ⨟ᵣ ext ρ) Γ
≡⟨ cong (λ □ → ctx-rename (↑ 1 ⨟ᵣ □) Γ) (ext-cons-shift ρ) ⟩
ctx-rename (↑ 1 ⨟ᵣ 0 • (ρ ⨟ᵣ ↑ 1)) Γ
≡⟨⟩
ctx-rename (ρ ⨟ᵣ ↑ 1) Γ
≡⟨ sym compose-ctx-rename ⟩
ctx-rename (↑ 1) (ctx-rename ρ Γ)
∎
ty-rename {ρ} {Δ} {Δ'} {Γ} {N [·]} {_} ΔρΔ′ (⊢[·] {A = A}{B = B} wf ⊢N) =
let IH = ty-rename {ρ} ΔρΔ′ ⊢N in
let ⊢N[·] = ⊢[·] (rename-pres-wf {ρ} ΔρΔ′ wf) IH in
subst (λ □ → Δ' ⨟ ctx-rename ρ Γ ⊢ N [·] ⦂ □) EQ ⊢N[·]
where
EQ : tyrename (ext ρ) A ⦗ tyrename ρ B ⦘ ≡ tyrename ρ (A ⦗ B ⦘)
EQ = rename-subst-commute {A}{B}{ρ}
WTSubst : Context → ℕ → Subst → Context → Set
WTSubst Γ Δ σ Γ′ = ∀ {A x} → Γ ∋ x ⦂ A → Δ ⨟ Γ′ ⊢ ⟪ σ ⟫ (` x) ⦂ A
exts-pres : ∀ {Γ Δ Γ′ σ B}
→ WTSubst Γ Δ σ Γ′
--------------------------------
→ WTSubst (Γ , B) Δ (exts σ) (Γ′ , B)
exts-pres {σ = σ} Γ⊢σ Z = ⊢` Z
exts-pres {σ = σ} Γ⊢σ (S {x = x} ∋x) = rename-pres {ρ = ↑ 1} S (Γ⊢σ ∋x)
WF↑1 : ∀{Δ} → WFRename Δ (↑ 1) (suc Δ)
WF↑1 {Δ}{α} α<Δ = ⊢var (s≤s α<Δ)
subst-pres : ∀ {Γ Γ′ σ N A Δ}
→ WTSubst Γ Δ σ Γ′
→ Δ ⨟ Γ ⊢ N ⦂ A
---------------
→ Δ ⨟ Γ′ ⊢ ⟪ σ ⟫ N ⦂ A
subst-pres Γ⊢σ (⊢$ e) = ⊢$ e
subst-pres Γ⊢σ (⊢` eq) = Γ⊢σ eq
subst-pres {σ = σ} Γ⊢σ (⊢ƛ wf ⊢N) =
⊢ƛ wf (subst-pres {σ = exts σ} (exts-pres {σ = σ} Γ⊢σ) ⊢N)
subst-pres {σ = σ} Γ⊢σ (⊢· ⊢L ⊢M) =
⊢· (subst-pres {σ = σ} Γ⊢σ ⊢L) (subst-pres {σ = σ} Γ⊢σ ⊢M)
subst-pres {Γ}{Γ′}{σ}{Δ = Δ} Γ⊢σ (⊢Λ ⊢N) = ⊢Λ (subst-pres {σ = σ} G ⊢N)
where
G : WTSubst (ctx-rename (↑ 1) Γ) (suc Δ) σ (ctx-rename (↑ 1) Γ′)
G {A}{x} ∋x
with ctx-rename-reflect {↑ 1}{Γ}{x}{A} ∋x
... | ⟨ B , ⟨ refl , ∋x' ⟩ ⟩ =
let ⊢⟦σ⟧x = Γ⊢σ {B}{x} ∋x' in
ty-rename{↑ 1}{Δ}{suc Δ} WF↑1 ⊢⟦σ⟧x
subst-pres {σ = σ} Γ⊢σ (⊢[·] wf ⊢N) = ⊢[·] wf (subst-pres {σ = σ} Γ⊢σ ⊢N)
substitution : ∀{Γ Δ A B M N}
→ Δ ⨟ Γ ⊢ M ⦂ A
→ Δ ⨟ (Γ , A) ⊢ N ⦂ B
---------------
→ Δ ⨟ Γ ⊢ N [ M ] ⦂ B
substitution {Γ}{Δ}{A}{B}{M}{N} ⊢M ⊢N = subst-pres {σ = M • ↑ 0 } G ⊢N
where
G : WTSubst (Γ , A) Δ (M • ↑ 0) Γ
G {A₁} {zero} Z = ⊢M
G {A₁} {suc x} (S ∋x) = ⊢` ∋x
WFSubst : ℕ → TySubst → ℕ → Set
WFSubst Δ σ Δ′ = ∀{α} → α < Δ → Δ′ ⊢ ⧼ σ ⧽ α
exts-pres-wf : ∀ {Δ Δ′ σ}
→ WFSubst Δ σ Δ′
-----------------------------------
→ WFSubst (suc Δ) (tyexts σ) (suc Δ′)
exts-pres-wf ΔσΔ′ {zero} α<Δ = ⊢var (s≤s z≤n)
exts-pres-wf ΔσΔ′ {suc α} α<Δ =
rename-pres-wf {ρ = ↑ 1} WF↑1 (ΔσΔ′ {α} (≤-pred α<Δ))
subst-pres-wf : ∀{σ}{Δ Δ′}{A}
→ WFSubst Δ σ Δ′
→ Δ ⊢ A
→ Δ′ ⊢ ⸂ σ ⸃ A
subst-pres-wf ΔσΔ′ (⊢var α) = ΔσΔ′ α
subst-pres-wf ΔσΔ′ ⊢nat = ⊢nat
subst-pres-wf ΔσΔ′ ⊢bool = ⊢bool
subst-pres-wf {σ} ΔσΔ′ (⊢fun ⊢A ⊢B) =
⊢fun (subst-pres-wf {σ} ΔσΔ′ ⊢A) (subst-pres-wf {σ} ΔσΔ′ ⊢B)
subst-pres-wf {σ} ΔσΔ′ (⊢all ⊢A) =
let IH = subst-pres-wf {σ = tyexts σ} (exts-pres-wf ΔσΔ′) ⊢A in
⊢all IH
subst-base : ∀ σ b
→ ⸂ σ ⸃ (typeof-base b) ≡ typeof-base b
subst-base σ B-Nat = refl
subst-base σ B-Bool = refl
subst-prim : ∀ σ p
→ ⸂ σ ⸃ (typeof p) ≡ typeof p
subst-prim σ (base B-Nat) = refl
subst-prim σ (base B-Bool) = refl
subst-prim σ (b ⇛ p)
with subst-base σ b | subst-prim σ p
... | eq1 | eq2 rewrite eq1 | eq2 = refl
ty-subst : ∀{σ : TySubst}{Δ Δ′}{Γ}{N}{A}
→ WFSubst Δ σ Δ′
→ Δ ⨟ Γ ⊢ N ⦂ A
-------------------------------
→ Δ′ ⨟ ctx-subst σ Γ ⊢ N ⦂ ⸂ σ ⸃ A
ty-subst {σ} ΔσΔ′ (⊢$ {p = p} refl) = ⊢$ (subst-prim σ p)
ty-subst {σ} ΔσΔ′ (⊢` ∋x) = ⊢` (ctx-subst-pres ∋x)
ty-subst {σ} ΔσΔ′ (⊢ƛ wf ⊢N) =
⊢ƛ (subst-pres-wf {σ} ΔσΔ′ wf) (ty-subst {σ} ΔσΔ′ ⊢N)
ty-subst {σ} ΔσΔ′ (⊢· ⊢L ⊢M) = ⊢· (ty-subst {σ} ΔσΔ′ ⊢L) (ty-subst {σ} ΔσΔ′ ⊢M)
ty-subst {σ}{Δ}{Δ′}{Γ}{Λ N}{all A} ΔσΔ′ (⊢Λ ⊢N) =
let IH = ty-subst {σ = tyexts σ} (exts-pres-wf ΔσΔ′) ⊢N in
let ⊢N = subst (λ □ → suc Δ′ ⨟ □ ⊢ N ⦂ ⸂ tyexts σ ⸃ A) GEQ IH in
⊢Λ ⊢N
where
GEQ = begin
ctx-subst (tyexts σ) (ctx-rename (↑ 1) Γ)
≡⟨ cong (λ □ → ctx-subst (tyexts σ) □) (ctx-rename-subst (↑ 1) Γ) ⟩
ctx-subst (tyexts σ) (ctx-subst (↑ 1) Γ)
≡⟨ compose-ctx-subst ⟩
ctx-subst (↑ 1 ⨟ tyexts σ) Γ
≡⟨ cong (λ □ → ctx-subst (↑ 1 ⨟ □) Γ) (exts-cons-shift σ) ⟩
ctx-subst (↑ 1 ⨟ ((tyvar 0) • (σ ⨟ ↑ 1))) Γ
≡⟨⟩
ctx-subst (σ ⨟ ↑ 1) Γ
≡⟨ sym compose-ctx-subst ⟩
ctx-subst (↑ 1) (ctx-subst σ Γ)
≡⟨ sym (ctx-rename-subst (↑ 1) (ctx-subst σ Γ)) ⟩
ctx-rename (↑ 1) (ctx-subst σ Γ)
∎
ty-subst {σ}{Δ}{Δ′}{Γ}{N [·]} ΔσΔ′ (⊢[·] {A = A}{B} wf ⊢N) =
let IH = ty-subst {σ} ΔσΔ′ ⊢N in
let ⊢N[·] = ⊢[·] (subst-pres-wf {σ} ΔσΔ′ wf) IH in
subst (λ □ → Δ′ ⨟ ctx-subst σ Γ ⊢ N [·] ⦂ □) EQ ⊢N[·]
where
EQ : ⸂ tyexts σ ⸃ A ⦗ ⸂ σ ⸃ B ⦘ ≡ ⸂ σ ⸃ (A ⦗ B ⦘)
EQ = sym (commute-subst {A}{B}{σ})
type-substitution : ∀{B}{Δ}{Γ}{N}{A}
→ Δ ⊢ B
→ suc Δ ⨟ Γ ⊢ N ⦂ A
-----------------------------------------
→ Δ ⨟ ctx-subst (B • id) Γ ⊢ N ⦂ A ⦗ B ⦘
type-substitution {B}{Δ} wfB ⊢N = ty-subst {σ = B • id} G ⊢N
where
G : WFSubst (suc Δ) (B • id) Δ
G {zero} α<Δ = wfB
G {suc α} α<Δ = ⊢var (≤-pred α<Δ)
plug-inversion : ∀{M F A}
→ 0 ⨟ ∅ ⊢ plug M F ⦂ A
--------------------------------------------------
→ Σ[ B ∈ Type ]
0 ⨟ ∅ ⊢ M ⦂ B
× (∀ M' → 0 ⨟ ∅ ⊢ M' ⦂ B → 0 ⨟ ∅ ⊢ plug M' F ⦂ A)
plug-inversion {M} {□· N} {A} (⊢· {A = A'} ⊢M ⊢N) =
⟨ A' ⇒ A , ⟨ ⊢M , (λ M' z → ⊢· z ⊢N) ⟩ ⟩
plug-inversion {M} {(L ·□) v} {A} (⊢· {A = A'} ⊢L ⊢M) =
⟨ A' , ⟨ ⊢M , (λ M' → ⊢· ⊢L) ⟩ ⟩
plug-inversion {M} {□[·]} {A} (⊢[·] {A = A'} wf ⊢N) =
⟨ all A' , ⟨ ⊢N , (λ N' ⊢N' → ⊢[·] wf ⊢N') ⟩ ⟩
preserve : ∀ {M N A}
→ 0 ⨟ ∅ ⊢ M ⦂ A
→ M —→ N
----------
→ 0 ⨟ ∅ ⊢ N ⦂ A
preserve ⊢M (ξ {M}{M′} F M—→M′)
with plug-inversion ⊢M
... | ⟨ B , ⟨ ⊢M' , plug-wt ⟩ ⟩ = plug-wt M′ (preserve ⊢M' M—→M′)
preserve (⊢· (⊢ƛ wf ⊢N) ⊢M) (β-ƛ vV) = substitution ⊢M ⊢N
preserve (⊢· (⊢$ refl) (⊢$ refl)) δ = ⊢$ refl
preserve (⊢[·] {B = B} wf (⊢Λ ⊢N)) β-Λ = type-substitution wf ⊢N