{-# OPTIONS --rewriting #-}
module lecture-notes-More where
import Syntax
open import Data.Bool renaming (Bool to 𝔹)
open import Data.List using (List; []; _∷_)
open import Data.Nat using (ℕ; zero; suc)
open import Data.Product using (_×_; Σ; Σ-syntax; ∃; ∃-syntax; proj₁; proj₂)
renaming (_,_ to ⟨_,_⟩)
open import Relation.Binary.PropositionalEquality
using (_≡_; _≢_; refl; sym; cong; cong₂)
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-rec : Op
op-const : (p : Prim) → rep p → Op
op-let : Op
op-insert : Op
op-empty : Op
op-index : Op
op-error : Op
sig : Op → List ℕ
sig op-lam = 1 ∷ []
sig op-app = 0 ∷ 0 ∷ []
sig op-rec = 1 ∷ []
sig (op-const p k) = []
sig op-let = 0 ∷ 1 ∷ []
sig op-insert = 0 ∷ 0 ∷ []
sig op-empty = []
sig op-index = 0 ∷ 0 ∷ []
sig op-error = []
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 μ N = op-rec ⦅ cons (bind (ast N)) nil ⦆
pattern _·_ L M = op-app ⦅ cons (ast L) (cons (ast M) nil) ⦆
pattern `let L M = op-let ⦅ cons (ast L) (cons (bind (ast M)) nil) ⦆
pattern _⦂⦂_ L M = op-insert ⦅ cons (ast L) (cons (ast M) nil) ⦆
pattern 〈〉 = op-empty ⦅ nil ⦆
pattern _!_ L M = op-index ⦅ cons (ast L) (cons (ast M) nil) ⦆
pattern error = op-error ⦅ nil ⦆
sub-lam : ∀ (N : Term) (σ : Subst) → ⟪ σ ⟫ (ƛ N) ≡ ƛ (⟪ exts σ ⟫ N)
sub-lam N σ = refl
sub-app : ∀ (L M : Term) (σ : Subst) → ⟪ σ ⟫ (L · M) ≡ (⟪ σ ⟫ L) · (⟪ σ ⟫ M)
sub-app L M σ = refl
data Type : Set where
Nat : Type
Bool : Type
_⇒_ : Type → Type → Type
Array _ : Type → Type
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
infix 4 _⊢_⦂_
data _⊢_⦂_ : Context → Term → Type → Set where
-- Axiom
⊢` : ∀ {Γ x A}
→ Γ ∋ x ⦂ A
-----------
→ Γ ⊢ ` x ⦂ A
-- ⇒-I
⊢ƛ : ∀ {Γ N A B}
→ Γ , A ⊢ N ⦂ B
-------------------
→ Γ ⊢ ƛ N ⦂ A ⇒ B
-- ⇒-E
⊢· : ∀ {Γ L M A B}
→ Γ ⊢ L ⦂ A ⇒ B
→ Γ ⊢ M ⦂ A
-------------
→ Γ ⊢ L · M ⦂ B
⊢μ : ∀ {Γ M A}
→ Γ , A ⊢ M ⦂ A
-----------------
→ Γ ⊢ μ M ⦂ A
⊢$ : ∀{Γ A}{p : Prim}{k : rep p}
→ A ≡ typeof p
-------------
→ Γ ⊢ $ p k ⦂ A
⊢let : ∀{Γ A B M N}
→ Γ ⊢ M ⦂ A
→ Γ , A ⊢ N ⦂ B
-----------------
→ Γ ⊢ `let M N ⦂ B
⊢empty : ∀{Γ A}
------------------
→ Γ ⊢ 〈〉 ⦂ Array A
⊢insert : ∀{Γ A M Ms}
→ Γ ⊢ M ⦂ A
→ Γ ⊢ Ms ⦂ Array A
----------------------
→ Γ ⊢ (M ⦂⦂ Ms) ⦂ Array A
⊢! : ∀{Γ A Ms N}
→ Γ ⊢ Ms ⦂ Array A
→ Γ ⊢ N ⦂ Nat
----------------
→ Γ ⊢ Ms ! N ⦂ A
⊢error : ∀ {Γ A}
-------------
→ Γ ⊢ error ⦂ A
data Value : Term → Set where
V-ƛ : ∀ {N : Term}
---------------------------
→ Value (ƛ N)
V-const : ∀ {p k}
-----------------
→ Value ($ p k)
V-〈〉 : Value 〈〉
V-⦂⦂ : ∀ {V Vs : Term}
→ Value V
→ Value Vs
-----------------
→ Value (V ⦂⦂ Vs)
With the addition of errors, one would need to add many more rules for
propagating an error to the top of the program. We instead collapse
these rules, and the ξ rules, into just two rules by abstracting over
the notion of a frame, which controls how reduction can occur inside
of each term constructor. Think of the □ symbol is a hole in the term.
data Frame : Set where
□·_ : Term → Frame
_·□ : (M : Term) → (v : Value M) → Frame
□⦂⦂_ : Term → Frame
_⦂⦂□ : (M : Term) → (v : Value M) → Frame
□!_ : Term → Frame
_!□ : Term → Frame
let□ : Term → 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 (□⦂⦂ N) = M ⦂⦂ N
plug N ((M ⦂⦂□) v) = M ⦂⦂ N
plug M (□! N) = M ! N
plug N (M !□) = M ! N
plug M (let□ N) = `let M N
infix 4 _—→_
data _—→_ : Term → Term → Set where
ξ : ∀ {M M′}
→ (F : Frame)
→ M —→ M′
---------------------
→ plug M F —→ plug M′ F
lift-error :
(F : Frame)
→ plug error F —→ error
β-ƛ : ∀ {N V}
→ Value V
--------------------
→ (ƛ N) · V —→ N [ V ]
β-μ : ∀ {M}
----------------
→ μ M —→ M [ μ M ]
δ : ∀ {b p f k}
---------------------------------------------
→ ($ (b ⇒ p) f) · ($ (base b) k) —→ ($ p (f k))
β-index-0 : ∀ {V Vs}
→ Value (V ⦂⦂ Vs)
-------------------------
→ (V ⦂⦂ Vs) ! ($ _ 0) —→ V
β-index-suc : ∀ {V Vs i}
→ Value (V ⦂⦂ Vs)
------------------------------------------
→ (V ⦂⦂ Vs) ! ($ _ (suc i)) —→ Vs ! ($ _ i)
β-index-error : ∀ {V}
→ Value V
-----------------
→ 〈〉 ! V —→ error
β-let : ∀{V N}
→ Value V
-------------------
→ `let V N —→ N [ V ]
infix 2 _—↠_
infix 1 begin_
infixr 2 _—→⟨_⟩_
infix 3 _∎
data _—↠_ : Term → Term → Set where
_∎ : ∀ M
---------
→ M —↠ M
_—→⟨_⟩_ : ∀ L {M N}
→ L —→ M
→ M —↠ N
---------
→ L —↠ N
begin_ : ∀ {M N}
→ M —↠ N
------
→ M —↠ N
begin M—↠N = M—↠N
data Function : Term → Set where
Fun-ƛ : ∀ {N} → Function (ƛ N)
Fun-prim : ∀{b p k} → Function ($ (b ⇒ p) k)
Fun-error : Function error
canonical-fun : ∀{V A B}
→ ∅ ⊢ 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
→ ∅ ⊢ V ⦂ A
→ Value V
------------
→ Constant b V
canonical-base {B-Nat} () (⊢ƛ ⊢V) V-ƛ
canonical-base {B-Bool} () (⊢ƛ ⊢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
canonical-base {B-Nat} () (⊢insert ⊢V ⊢V₁) (V-⦂⦂ vV vV₁)
canonical-base {B-Bool} () (⊢insert ⊢V ⊢V₁) (V-⦂⦂ vV vV₁)
data IsArray : Term → Set where
array-empty : IsArray 〈〉
array-insert : ∀{V Vs} → IsArray Vs → IsArray (V ⦂⦂ Vs)
canonical-array : ∀ {Ms A}
→ ∅ ⊢ Ms ⦂ Array A
→ Value Ms
→ IsArray Ms
canonical-array (⊢$ {p = base B-Nat} ()) V-const
canonical-array (⊢$ {p = base B-Bool} ()) V-const
canonical-array ⊢empty V-〈〉 = array-empty
canonical-array (⊢insert ⊢M ⊢Ms) (V-⦂⦂ VM VMs) =
array-insert (canonical-array ⊢Ms VMs)
data Error : Term → Set where
is-error : Error error
data Progress (M : Term) : Set where
step : ∀ {N}
→ M —→ N
----------
→ Progress M
done :
Value M
----------
→ Progress M
trapped-error :
Error M
----------
→ Progress M
progress : ∀ {M A}
→ ∅ ⊢ M ⦂ A
----------
→ Progress M
progress (⊢` ())
progress (⊢$ _) = done V-const
progress (⊢ƛ ⊢N) = done V-ƛ
progress (⊢· {L = L}{M}{A}{B} ⊢L ⊢M)
with progress ⊢L
... | step L—→L′ = step (ξ (□· M) L—→L′)
... | trapped-error is-error = step (lift-error (□· M))
... | done VL
with progress ⊢M
... | step M—→M′ = step (ξ ((L ·□) VL) M—→M′)
... | trapped-error is-error = step (lift-error ((L ·□) VL))
... | 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 (⊢μ ⊢M) = step β-μ
progress (⊢let {N = N} ⊢L ⊢N)
with progress ⊢L
... | step L—→L′ = step (ξ (let□ N) L—→L′)
... | trapped-error is-error = step (lift-error (let□ N))
... | done VL = step (β-let VL)
progress ⊢empty = done V-〈〉
progress (⊢insert {M = M}{Ms} ⊢M ⊢Ms)
with progress ⊢M
... | step M—→M′ = step (ξ (□⦂⦂ Ms) M—→M′)
... | trapped-error is-error = step (lift-error (□⦂⦂ Ms))
... | done VM
with progress ⊢Ms
... | step Ms—→Ms′ = step (ξ ((M ⦂⦂□) VM) Ms—→Ms′)
... | trapped-error is-error = step (lift-error ((M ⦂⦂□) VM))
... | done VMs = done (V-⦂⦂ VM VMs)
progress (⊢! {Ms = M}{N} ⊢M ⊢N)
with progress ⊢M
... | step M—→M′ = step (ξ (□! N) M—→M′)
... | trapped-error is-error = step (lift-error (□! N))
... | done VMs
with progress ⊢N
... | step N—→N′ = step (ξ (M !□) N—→N′)
... | trapped-error is-error = step (lift-error (M !□))
... | done VN
with canonical-array ⊢M VMs
... | array-empty = step β-index-error
... | array-insert aVs
with canonical-base refl ⊢N VN
... | base-const {b}{0} = step (β-index-0 VMs)
... | base-const {b}{suc i} = step (β-index-suc VMs)
progress ⊢error = trapped-error is-error
WTRename : Context → Rename → Context → Set
WTRename Γ ρ Δ = ∀ {x A} → Γ ∋ x ⦂ A → Δ ∋ ⦉ ρ ⦊ x ⦂ A
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 ⊢ρ (⊢` ∋w) = ⊢` (⊢ρ ∋w)
rename-pres {ρ = ρ} ⊢ρ (⊢ƛ ⊢N) = ⊢ƛ (rename-pres {ρ = ext ρ} (ext-pres {ρ = ρ} ⊢ρ) ⊢N)
rename-pres {ρ = ρ} ⊢ρ (⊢· ⊢L ⊢M) = ⊢· (rename-pres {ρ = ρ} ⊢ρ ⊢L) (rename-pres {ρ = ρ} ⊢ρ ⊢M)
rename-pres {ρ = ρ} ⊢ρ (⊢μ ⊢M) = ⊢μ (rename-pres {ρ = ext ρ} (ext-pres {ρ = ρ} ⊢ρ) ⊢M)
rename-pres ⊢ρ (⊢$ eq) = ⊢$ eq
rename-pres {ρ = ρ} ⊢ρ (⊢let ⊢M ⊢N) =
⊢let (rename-pres {ρ = ρ} ⊢ρ ⊢M) (rename-pres {ρ = ext ρ} (ext-pres {ρ = ρ} ⊢ρ) ⊢N)
rename-pres ⊢ρ ⊢empty = ⊢empty
rename-pres {ρ = ρ} ⊢ρ (⊢insert ⊢M ⊢Ms) =
⊢insert (rename-pres {ρ = ρ} ⊢ρ ⊢M) (rename-pres {ρ = ρ} ⊢ρ ⊢Ms)
rename-pres {ρ = ρ} ⊢ρ (⊢! ⊢Ms ⊢N) = ⊢! (rename-pres {ρ = ρ} ⊢ρ ⊢Ms) (rename-pres {ρ = ρ} ⊢ρ ⊢N)
rename-pres ⊢ρ ⊢error = ⊢error
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)
subst : ∀ {Γ Δ σ N A}
→ WTSubst Γ σ Δ
→ Γ ⊢ N ⦂ A
---------------
→ Δ ⊢ ⟪ σ ⟫ N ⦂ A
subst Γ⊢σ (⊢` eq) = Γ⊢σ eq
subst {σ = σ} Γ⊢σ (⊢ƛ ⊢N) = ⊢ƛ (subst {σ = exts σ} (exts-pres {σ = σ} Γ⊢σ) ⊢N)
subst {σ = σ} Γ⊢σ (⊢· ⊢L ⊢M) = ⊢· (subst {σ = σ} Γ⊢σ ⊢L) (subst {σ = σ} Γ⊢σ ⊢M)
subst {σ = σ} Γ⊢σ (⊢μ ⊢M) = ⊢μ (subst {σ = exts σ} (exts-pres {σ = σ} Γ⊢σ) ⊢M)
subst Γ⊢σ (⊢$ e) = ⊢$ e
subst {σ = σ} Γ⊢σ (⊢let ⊢M ⊢N) =
⊢let (subst {σ = σ} Γ⊢σ ⊢M) (subst {σ = exts σ} (exts-pres {σ = σ} Γ⊢σ) ⊢N)
subst Γ⊢σ ⊢empty = ⊢empty
subst {σ = σ} Γ⊢σ (⊢insert ⊢M ⊢Ms)= ⊢insert (subst {σ = σ} Γ⊢σ ⊢M) (subst {σ = σ} Γ⊢σ ⊢Ms)
subst {σ = σ} Γ⊢σ (⊢! ⊢M ⊢N) = ⊢! (subst {σ = σ} Γ⊢σ ⊢M) (subst {σ = σ} Γ⊢σ ⊢N)
subst Γ⊢σ ⊢error = ⊢error
substitution : ∀{Γ A B M N}
→ Γ ⊢ M ⦂ A
→ (Γ , A) ⊢ N ⦂ B
---------------
→ Γ ⊢ N [ M ] ⦂ B
substitution {Γ}{A}{B}{M}{N} ⊢M ⊢N = subst {σ = M • ↑ 0 } G ⊢N
where
G : ∀ {A₁ : Type} {x : ℕ}
→ (Γ , A) ∋ x ⦂ A₁ → Γ ⊢ ⟪ M • ↑ 0 ⟫ (` x) ⦂ A₁
G {A₁} {zero} Z = ⊢M
G {A₁} {suc x} (S ∋x) = ⊢` ∋x
plug-inversion : ∀{M F A}
→ ∅ ⊢ plug M F ⦂ A
----------------------------------------------------------------
→ Σ[ B ∈ Type ] ∅ ⊢ M ⦂ B × (∀ M' → ∅ ⊢ M' ⦂ B → ∅ ⊢ 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} {□⦂⦂ Ms} {.(Array _)} (⊢insert {A = A} ⊢M ⊢Ms) =
⟨ A , ⟨ ⊢M , (λ M' z → ⊢insert z ⊢Ms) ⟩ ⟩
plug-inversion {M} {(N ⦂⦂□) v} {.(Array _)} (⊢insert {A = A} ⊢N ⊢M) =
⟨ Array A , ⟨ ⊢M , (λ M' → ⊢insert ⊢N) ⟩ ⟩
plug-inversion {M} {□! i} {A} (⊢! ⊢M ⊢N) =
⟨ (Array A) , ⟨ ⊢M , (λ M' z → ⊢! z ⊢N) ⟩ ⟩
plug-inversion {M} {Ms !□} {A} (⊢! ⊢M ⊢N) =
⟨ Nat , ⟨ ⊢N , (λ M' → ⊢! ⊢M) ⟩ ⟩
plug-inversion {M} {let□ N} {A} (⊢let {A = A'} ⊢M ⊢N) =
⟨ A' , ⟨ ⊢M , (λ M' z → ⊢let z ⊢N) ⟩ ⟩
preserve : ∀ {M N A}
→ ∅ ⊢ M ⦂ A
→ M —→ N
----------
→ ∅ ⊢ 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 ⊢M (lift-error F) = ⊢error
preserve (⊢· (⊢ƛ ⊢N) ⊢M) (β-ƛ vV) = substitution ⊢M ⊢N
preserve (⊢μ ⊢M) β-μ = substitution (⊢μ ⊢M) ⊢M
preserve (⊢· (⊢$ refl) (⊢$ refl)) δ = ⊢$ refl
preserve (⊢! (⊢insert ⊢M ⊢Ms) ⊢N) (β-index-0 vMMs) = ⊢M
preserve (⊢! (⊢insert ⊢M ⊢Ms) ⊢N) (β-index-suc vVVs) = ⊢! ⊢Ms (⊢$ refl)
preserve ⊢M β-index-error = ⊢error
preserve (⊢let ⊢M ⊢N) (β-let vV) = substitution ⊢M ⊢N