More: Additional constructs of simply-typed lambda calculus
module plfa.part2.More whereSo far, we have focussed on a relatively minimal language, based on Plotkin's PCF, which supports functions, naturals, and fixpoints. In this chapter we extend our calculus to support the following:
primitive numbers
let bindings
products
an alternative formulation of products
sums
unit type
an alternative formulation of unit type
empty type
lists
All of the data types should be familiar from Part I of this textbook. For let and the alternative formulations we show how they translate to other constructs in the calculus. Most of the description will be informal. We show how to formalise the first four constructs and leave the rest as an exercise for the reader.
Our informal descriptions will be in the style of Chapter Lambda, using extrinsically-typed terms, while our formalisation will be in the style of Chapter DeBruijn, using intrinsically-typed terms.
By now, explaining with symbols should be more concise, more precise, and easier to follow than explaining in prose. For each construct, we give syntax, typing, reductions, and an example. We also give translations where relevant; formally establishing the correctness of translations will be the subject of the next chapter.
Primitive numbers
We define a Nat type equivalent to the built-in natural number type with multiplication as a primitive operation on numbers:
Syntax
A, B, C ::= ... Types Nat primitive natural numbersL, M, N ::= ... Terms con c constant L `* M multiplicationV, W ::= ... Values con c constantTyping
The hypothesis of the con rule is unusual, in that it refers to a typing judgment of Agda rather than a typing judgment of the defined calculus:
c : ℕ--------------- conΓ ⊢ con c : NatΓ ⊢ L : NatΓ ⊢ M : Nat---------------- _`*_Γ ⊢ L `* M : NatReduction
A rule that defines a primitive directly, such as the last rule below, is called a δ rule. Here the δ rule defines multiplication of primitive numbers in terms of multiplication of naturals as given by the Agda standard prelude:
L —→ L′----------------- ξ-*₁L `* M —→ L′ `* MM —→ M′----------------- ξ-*₂V `* M —→ V `* M′----------------------------- δ-*con c `* con d —→ con (c * d)Example
Here is a function to cube a primitive number:
cube : ∅ ⊢ Nat ⇒ Natcube = ƛ x ⇒ x `* x `* xLet bindings
Let bindings affect only the syntax of terms; they introduce no new types or values:
Syntax
L, M, N ::= ... Terms `let x `= M `in N letTyping
Γ ⊢ M ⦂ AΓ , x ⦂ A ⊢ N ⦂ B------------------------- `letΓ ⊢ `let x `= M `in N ⦂ BReduction
M —→ M′--------------------------------------- ξ-let`let x `= M `in N —→ `let x `= M′ `in N--------------------------------- β-let`let x `= V `in N —→ N [ x := V ]Example
Here is a function to raise a primitive number to the tenth power:
exp10 : ∅ ⊢ Nat ⇒ Natexp10 = ƛ x ⇒ `let x2 `= x `* x `in `let x4 `= x2 `* x2 `in `let x5 `= x4 `* x `in x5 `* x5Translation
We can translate each let term into an application of an abstraction:
(`let x `= M `in N) † = (ƛ x ⇒ (N †)) · (M †)Here M † is the translation of term M from a calculus with the construct to a calculus without the construct.
Products {#products}
Syntax
A, B, C ::= ... Types A `× B product typeL, M, N ::= ... Terms `⟨ M , N ⟩ pair `proj₁ L project first component `proj₂ L project second componentV, W ::= ... Values `⟨ V , W ⟩ pairTyping
Γ ⊢ M ⦂ AΓ ⊢ N ⦂ B----------------------- `⟨_,_⟩ or `×-IΓ ⊢ `⟨ M , N ⟩ ⦂ A `× BΓ ⊢ L ⦂ A `× B---------------- `proj₁ or `×-E₁Γ ⊢ `proj₁ L ⦂ AΓ ⊢ L ⦂ A `× B---------------- `proj₂ or `×-E₂Γ ⊢ `proj₂ L ⦂ BReduction
M —→ M′------------------------- ξ-⟨,⟩₁`⟨ M , N ⟩ —→ `⟨ M′ , N ⟩N —→ N′------------------------- ξ-⟨,⟩₂`⟨ V , N ⟩ —→ `⟨ V , N′ ⟩L —→ L′--------------------- ξ-proj₁`proj₁ L —→ `proj₁ L′L —→ L′--------------------- ξ-proj₂`proj₂ L —→ `proj₂ L′---------------------- β-proj₁`proj₁ `⟨ V , W ⟩ —→ V---------------------- β-proj₂`proj₂ `⟨ V , W ⟩ —→ WExample
Here is a function to swap the components of a pair:
swap× : ∅ ⊢ A `× B ⇒ B `× Aswap× = ƛ z ⇒ `⟨ proj₂ z , proj₁ z ⟩Alternative formulation of products
There is an alternative formulation of products, where in place of two ways to eliminate the type we have a case term that binds two variables. We repeat the syntax in full, but only give the new type and reduction rules:
Syntax
A, B, C ::= ... Types A `× B product typeL, M, N ::= ... Terms `⟨ M , N ⟩ pair case× L [⟨ x , y ⟩⇒ M ] caseV, W ::= Values `⟨ V , W ⟩ pairTyping
Γ ⊢ L ⦂ A `× BΓ , x ⦂ A , y ⦂ B ⊢ N ⦂ C------------------------------- case× or ×-EΓ ⊢ case× L [⟨ x , y ⟩⇒ N ] ⦂ CReduction
L —→ L′--------------------------------------------------- ξ-case×case× L [⟨ x , y ⟩⇒ N ] —→ case× L′ [⟨ x , y ⟩⇒ N ]--------------------------------------------------------- β-case×case× `⟨ V , W ⟩ [⟨ x , y ⟩⇒ N ] —→ N [ x := V ][ y := W ]Example
Here is a function to swap the components of a pair rewritten in the new notation:
swap×-case : ∅ ⊢ A `× B ⇒ B `× Aswap×-case = ƛ z ⇒ case× z [⟨ x , y ⟩⇒ `⟨ y , x ⟩ ]Translation
We can translate the alternative formulation into the one with projections:
(case× L [⟨ x , y ⟩⇒ N ]) †= `let z `= (L †) `in `let x `= `proj₁ z `in `let y `= `proj₂ z `in (N †)Here z is a variable that does not appear free in N. We refer to such a variable as fresh.
One might think that we could instead use a more compact translation:
-- WRONG (case× L [⟨ x , y ⟩⇒ N ]) †= (N †) [ x := proj₁ (L †) ][ y := proj₂ (L †) ]But this behaves differently. The first term always reduces L before N, and it computes proj₁ and proj₂ exactly once. The second term does not reduce L to a value before reducing N, and depending on how many times and where x and y appear in N, it may reduce L many times or not at all, and it may compute proj₁ and proj₂ many times or not at all.
We can also translate back the other way:
(`proj₁ L) ‡ = case× (L ‡) [⟨ x , y ⟩⇒ x ](`proj₂ L) ‡ = case× (L ‡) [⟨ x , y ⟩⇒ y ]Sums {#sums}
Syntax
A, B, C ::= ... Types A `⊎ B sum typeL, M, N ::= ... Terms `inj₁ M inject first component `inj₂ N inject second component case⊎ L [inj₁ x ⇒ M |inj₂ y ⇒ N ] caseV, W ::= ... Values `inj₁ V inject first component `inj₂ W inject second componentTyping
Γ ⊢ M ⦂ A-------------------- `inj₁ or ⊎-I₁Γ ⊢ `inj₁ M ⦂ A `⊎ BΓ ⊢ N ⦂ B-------------------- `inj₂ or ⊎-I₂Γ ⊢ `inj₂ N ⦂ A `⊎ BΓ ⊢ L ⦂ A `⊎ BΓ , x ⦂ A ⊢ M ⦂ CΓ , y ⦂ B ⊢ N ⦂ C----------------------------------------- case⊎ or ⊎-EΓ ⊢ case⊎ L [inj₁ x ⇒ M |inj₂ y ⇒ N ] ⦂ CReduction
M —→ M′------------------- ξ-inj₁`inj₁ M —→ `inj₁ M′N —→ N′------------------- ξ-inj₂`inj₂ N —→ `inj₂ N′L —→ L′---------------------------------------------------------------------- ξ-case⊎case⊎ L [inj₁ x ⇒ M |inj₂ y ⇒ N ] —→ case⊎ L′ [inj₁ x ⇒ M |inj₂ y ⇒ N ]--------------------------------------------------------- β-inj₁case⊎ (`inj₁ V) [inj₁ x ⇒ M |inj₂ y ⇒ N ] —→ M [ x := V ]--------------------------------------------------------- β-inj₂case⊎ (`inj₂ W) [inj₁ x ⇒ M |inj₂ y ⇒ N ] —→ N [ y := W ]Example
Here is a function to swap the components of a sum:
swap⊎ : ∅ ⊢ A `⊎ B ⇒ B `⊎ Aswap⊎ = ƛ z ⇒ case⊎ z [inj₁ x ⇒ `inj₂ x |inj₂ y ⇒ `inj₁ y ]Unit type
For the unit type, there is a way to introduce values of the type but no way to eliminate values of the type. There are no reduction rules.
Syntax
A, B, C ::= ... Types `⊤ unit typeL, M, N ::= ... Terms `tt unit valueV, W ::= ... Values `tt unit valueTyping
------------ `tt or ⊤-IΓ ⊢ `tt ⦂ `⊤Reduction
(none)
Example
Here is the isomorphism between A and A `× `⊤:
to×⊤ : ∅ ⊢ A ⇒ A `× `⊤to×⊤ = ƛ x ⇒ `⟨ x , `tt ⟩from×⊤ : ∅ ⊢ A `× `⊤ ⇒ Afrom×⊤ = ƛ z ⇒ proj₁ zAlternative formulation of unit type
There is an alternative formulation of the unit type, where in place of no way to eliminate the type we have a case term that binds zero variables. We repeat the syntax in full, but only give the new type and reduction rules:
Syntax
A, B, C ::= ... Types `⊤ unit typeL, M, N ::= ... Terms `tt unit value `case⊤ L [tt⇒ N ] caseV, W ::= ... Values `tt unit valueTyping
Γ ⊢ L ⦂ `⊤Γ ⊢ M ⦂ A------------------------ case⊤ or ⊤-EΓ ⊢ case⊤ L [tt⇒ M ] ⦂ AReduction
L —→ L′------------------------------------- ξ-case⊤case⊤ L [tt⇒ M ] —→ case⊤ L′ [tt⇒ M ]----------------------- β-case⊤case⊤ `tt [tt⇒ M ] —→ MExample
Here is half the isomorphism between A and A `× `⊤ rewritten in the new notation:
from×⊤-case : ∅ ⊢ A `× `⊤ ⇒ Afrom×⊤-case = ƛ z ⇒ case× z [⟨ x , y ⟩⇒ case⊤ y [tt⇒ x ] ]Translation
We can translate the alternative formulation into one without case:
(case⊤ L [tt⇒ M ]) † = `let z `= (L †) `in (M †)Here z is a variable that does not appear free in M.
Empty type
For the empty type, there is a way to eliminate values of the type but no way to introduce values of the type. There are no values of the type and no β rule, but there is a ξ rule. The case⊥ construct plays a role similar to ⊥-elim in Agda:
Syntax
A, B, C ::= ... Types `⊥ empty typeL, M, N ::= ... Terms case⊥ L [] caseTyping
Γ ⊢ L ⦂ `⊥------------------ case⊥ or ⊥-EΓ ⊢ case⊥ L [] ⦂ AReduction
L —→ L′------------------------- ξ-case⊥case⊥ L [] —→ case⊥ L′ []Example
Here is the isomorphism between A and A `⊎ `⊥:
to⊎⊥ : ∅ ⊢ A ⇒ A `⊎ `⊥to⊎⊥ = ƛ x ⇒ `inj₁ xfrom⊎⊥ : ∅ ⊢ A `⊎ `⊥ ⇒ Afrom⊎⊥ = ƛ z ⇒ case⊎ z [inj₁ x ⇒ x |inj₂ y ⇒ case⊥ y [] ]Lists
Syntax
A, B, C ::= ... Types `List A list typeL, M, N ::= ... Terms `[] nil M `∷ N cons caseL L [[]⇒ M | x ∷ y ⇒ N ] caseV, W ::= ... Values `[] nil V `∷ W consTyping
----------------- `[] or List-I₁Γ ⊢ `[] ⦂ `List AΓ ⊢ M ⦂ AΓ ⊢ N ⦂ `List A-------------------- _`∷_ or List-I₂Γ ⊢ M `∷ N ⦂ `List AΓ ⊢ L ⦂ `List AΓ ⊢ M ⦂ BΓ , x ⦂ A , xs ⦂ `List A ⊢ N ⦂ B-------------------------------------- caseL or List-EΓ ⊢ caseL L [[]⇒ M | x ∷ xs ⇒ N ] ⦂ BReduction
M —→ M′----------------- ξ-∷₁M `∷ N —→ M′ `∷ NN —→ N′----------------- ξ-∷₂V `∷ N —→ V `∷ N′L —→ L′--------------------------------------------------------------- ξ-caseLcaseL L [[]⇒ M | x ∷ xs ⇒ N ] —→ caseL L′ [[]⇒ M | x ∷ xs ⇒ N ]------------------------------------ β-[]caseL `[] [[]⇒ M | x ∷ xs ⇒ N ] —→ M--------------------------------------------------------------- β-∷caseL (V `∷ W) [[]⇒ M | x ∷ xs ⇒ N ] —→ N [ x := V ][ xs := W ]Example
Here is the map function for lists:
mapL : ∅ ⊢ (A ⇒ B) ⇒ `List A ⇒ `List BmapL = μ mL ⇒ ƛ f ⇒ ƛ xs ⇒ caseL xs [[]⇒ `[] | x ∷ xs ⇒ f · x `∷ mL · f · xs ]Formalisation
We now show how to formalise
primitive numbers
let bindings
products
an alternative formulation of products
and leave formalisation of the remaining constructs as an exercise.
Imports
import Relation.Binary.PropositionalEquality as Eqopen Eq using (_≡_; refl)open import Data.Empty using (⊥; ⊥-elim)open import Data.Nat using (ℕ; zero; suc; _*_)open import Relation.Nullary using (¬_)Syntax
infix 4 _⊢_infix 4 _∋_infixl 5 _,_infixr 7 _⇒_infixr 9 _`×_infix 5 ƛ_infix 5 μ_infixl 7 _·_infixl 8 _`*_infix 8 `suc_infix 9 `_infix 9 S_infix 9 #_Types
data Type : Set where `ℕ : Type _⇒_ : Type → Type → Type Nat : Type _`×_ : Type → Type → TypeContexts
data Context : Set where ∅ : Context _,_ : Context → Type → ContextVariables and the lookup judgment
data _∋_ : Context → Type → Set where Z : ∀ {Γ A} --------- → Γ , A ∋ A S_ : ∀ {Γ A B} → Γ ∋ B --------- → Γ , A ∋ BTerms and the typing judgment
data _⊢_ : Context → Type → Set where -- variables `_ : ∀ {Γ A} → Γ ∋ A ----- → Γ ⊢ A -- functions ƛ_ : ∀ {Γ A B} → Γ , A ⊢ B --------- → Γ ⊢ A ⇒ B _·_ : ∀ {Γ A B} → Γ ⊢ A ⇒ B → Γ ⊢ A --------- → Γ ⊢ B -- naturals `zero : ∀ {Γ} ------ → Γ ⊢ `ℕ `suc_ : ∀ {Γ} → Γ ⊢ `ℕ ------ → Γ ⊢ `ℕ case : ∀ {Γ A} → Γ ⊢ `ℕ → Γ ⊢ A → Γ , `ℕ ⊢ A ----- → Γ ⊢ A -- fixpoint μ_ : ∀ {Γ A} → Γ , A ⊢ A ---------- → Γ ⊢ A -- primitive numbers con : ∀ {Γ} → ℕ ------- → Γ ⊢ Nat _`*_ : ∀ {Γ} → Γ ⊢ Nat → Γ ⊢ Nat ------- → Γ ⊢ Nat -- let `let : ∀ {Γ A B} → Γ ⊢ A → Γ , A ⊢ B ---------- → Γ ⊢ B -- products `⟨_,_⟩ : ∀ {Γ A B} → Γ ⊢ A → Γ ⊢ B ----------- → Γ ⊢ A `× B `proj₁ : ∀ {Γ A B} → Γ ⊢ A `× B ----------- → Γ ⊢ A `proj₂ : ∀ {Γ A B} → Γ ⊢ A `× B ----------- → Γ ⊢ B -- alternative formulation of products case× : ∀ {Γ A B C} → Γ ⊢ A `× B → Γ , A , B ⊢ C -------------- → Γ ⊢ CAbbreviating de Bruijn indices
lookup : Context → ℕ → Typelookup (Γ , A) zero = Alookup (Γ , _) (suc n) = lookup Γ nlookup ∅ _ = ⊥-elim impossible where postulate impossible : ⊥count : ∀ {Γ} → (n : ℕ) → Γ ∋ lookup Γ ncount {Γ , _} zero = Zcount {Γ , _} (suc n) = S (count n)count {∅} _ = ⊥-elim impossible where postulate impossible : ⊥#_ : ∀ {Γ} → (n : ℕ) → Γ ⊢ lookup Γ n# n = ` count nRenaming
ext : ∀ {Γ Δ} → (∀ {A} → Γ ∋ A → Δ ∋ A) → (∀ {A B} → Γ , A ∋ B → Δ , A ∋ B)ext ρ Z = Zext ρ (S x) = S (ρ x)rename : ∀ {Γ Δ} → (∀ {A} → Γ ∋ A → Δ ∋ A) → (∀ {A} → Γ ⊢ A → Δ ⊢ A)rename ρ (` x) = ` (ρ x)rename ρ (ƛ N) = ƛ (rename (ext ρ) N)rename ρ (L · M) = (rename ρ L) · (rename ρ M)rename ρ (`zero) = `zerorename ρ (`suc M) = `suc (rename ρ M)rename ρ (case L M N) = case (rename ρ L) (rename ρ M) (rename (ext ρ) N)rename ρ (μ N) = μ (rename (ext ρ) N)rename ρ (con n) = con nrename ρ (M `* N) = rename ρ M `* rename ρ Nrename ρ (`let M N) = `let (rename ρ M) (rename (ext ρ) N)rename ρ `⟨ M , N ⟩ = `⟨ rename ρ M , rename ρ N ⟩rename ρ (`proj₁ L) = `proj₁ (rename ρ L)rename ρ (`proj₂ L) = `proj₂ (rename ρ L)rename ρ (case× L M) = case× (rename ρ L) (rename (ext (ext ρ)) M)Simultaneous Substitution
exts : ∀ {Γ Δ} → (∀ {A} → Γ ∋ A → Δ ⊢ A) → (∀ {A B} → Γ , A ∋ B → Δ , A ⊢ B)exts σ Z = ` Zexts σ (S x) = rename S_ (σ x)subst : ∀ {Γ Δ} → (∀ {C} → Γ ∋ C → Δ ⊢ C) → (∀ {C} → Γ ⊢ C → Δ ⊢ C)subst σ (` k) = σ ksubst σ (ƛ N) = ƛ (subst (exts σ) N)subst σ (L · M) = (subst σ L) · (subst σ M)subst σ (`zero) = `zerosubst σ (`suc M) = `suc (subst σ M)subst σ (case L M N) = case (subst σ L) (subst σ M) (subst (exts σ) N)subst σ (μ N) = μ (subst (exts σ) N)subst σ (con n) = con nsubst σ (M `* N) = subst σ M `* subst σ Nsubst σ (`let M N) = `let (subst σ M) (subst (exts σ) N)subst σ `⟨ M , N ⟩ = `⟨ subst σ M , subst σ N ⟩subst σ (`proj₁ L) = `proj₁ (subst σ L)subst σ (`proj₂ L) = `proj₂ (subst σ L)subst σ (case× L M) = case× (subst σ L) (subst (exts (exts σ)) M)Single and double substitution
_[_] : ∀ {Γ A B} → Γ , A ⊢ B → Γ ⊢ A --------- → Γ ⊢ B_[_] {Γ} {A} N V = subst {Γ , A} {Γ} σ N where σ : ∀ {B} → Γ , A ∋ B → Γ ⊢ B σ Z = V σ (S x) = ` x_[_][_] : ∀ {Γ A B C} → Γ , A , B ⊢ C → Γ ⊢ A → Γ ⊢ B ------------- → Γ ⊢ C_[_][_] {Γ} {A} {B} N V W = subst {Γ , A , B} {Γ} σ N where σ : ∀ {C} → Γ , A , B ∋ C → Γ ⊢ C σ Z = W σ (S Z) = V σ (S (S x)) = ` xValues
data Value : ∀ {Γ A} → Γ ⊢ A → Set where -- functions V-ƛ : ∀ {Γ A B} {N : Γ , A ⊢ B} --------------------------- → Value (ƛ N) -- naturals V-zero : ∀ {Γ} ----------------- → Value (`zero {Γ}) V-suc_ : ∀ {Γ} {V : Γ ⊢ `ℕ} → Value V -------------- → Value (`suc V) -- primitives V-con : ∀ {Γ n} ----------------- → Value (con {Γ} n) -- products V-⟨_,_⟩ : ∀ {Γ A B} {V : Γ ⊢ A} {W : Γ ⊢ B} → Value V → Value W ---------------- → Value `⟨ V , W ⟩Implicit arguments need to be supplied when they are not fixed by the given arguments.
Reduction
infix 2 _—→_data _—→_ : ∀ {Γ A} → (Γ ⊢ A) → (Γ ⊢ A) → Set where -- functions ξ-·₁ : ∀ {Γ A B} {L L′ : Γ ⊢ A ⇒ B} {M : Γ ⊢ A} → L —→ L′ --------------- → L · M —→ L′ · M ξ-·₂ : ∀ {Γ A B} {V : Γ ⊢ A ⇒ B} {M M′ : Γ ⊢ A} → Value V → M —→ M′ --------------- → V · M —→ V · M′ β-ƛ : ∀ {Γ A B} {N : Γ , A ⊢ B} {V : Γ ⊢ A} → Value V -------------------- → (ƛ N) · V —→ N [ V ] -- naturals ξ-suc : ∀ {Γ} {M M′ : Γ ⊢ `ℕ} → M —→ M′ ----------------- → `suc M —→ `suc M′ ξ-case : ∀ {Γ A} {L L′ : Γ ⊢ `ℕ} {M : Γ ⊢ A} {N : Γ , `ℕ ⊢ A} → L —→ L′ ------------------------- → case L M N —→ case L′ M N β-zero : ∀ {Γ A} {M : Γ ⊢ A} {N : Γ , `ℕ ⊢ A} ------------------- → case `zero M N —→ M β-suc : ∀ {Γ A} {V : Γ ⊢ `ℕ} {M : Γ ⊢ A} {N : Γ , `ℕ ⊢ A} → Value V ---------------------------- → case (`suc V) M N —→ N [ V ] -- fixpoint β-μ : ∀ {Γ A} {N : Γ , A ⊢ A} ---------------- → μ N —→ N [ μ N ] -- primitive numbers ξ-*₁ : ∀ {Γ} {L L′ M : Γ ⊢ Nat} → L —→ L′ ----------------- → L `* M —→ L′ `* M ξ-*₂ : ∀ {Γ} {V M M′ : Γ ⊢ Nat} → Value V → M —→ M′ ----------------- → V `* M —→ V `* M′ δ-* : ∀ {Γ c d} --------------------------------- → con {Γ} c `* con d —→ con (c * d) -- let ξ-let : ∀ {Γ A B} {M M′ : Γ ⊢ A} {N : Γ , A ⊢ B} → M —→ M′ --------------------- → `let M N —→ `let M′ N β-let : ∀ {Γ A B} {V : Γ ⊢ A} {N : Γ , A ⊢ B} → Value V ------------------- → `let V N —→ N [ V ] -- products ξ-⟨,⟩₁ : ∀ {Γ A B} {M M′ : Γ ⊢ A} {N : Γ ⊢ B} → M —→ M′ ------------------------- → `⟨ M , N ⟩ —→ `⟨ M′ , N ⟩ ξ-⟨,⟩₂ : ∀ {Γ A B} {V : Γ ⊢ A} {N N′ : Γ ⊢ B} → Value V → N —→ N′ ------------------------- → `⟨ V , N ⟩ —→ `⟨ V , N′ ⟩ ξ-proj₁ : ∀ {Γ A B} {L L′ : Γ ⊢ A `× B} → L —→ L′ --------------------- → `proj₁ L —→ `proj₁ L′ ξ-proj₂ : ∀ {Γ A B} {L L′ : Γ ⊢ A `× B} → L —→ L′ --------------------- → `proj₂ L —→ `proj₂ L′ β-proj₁ : ∀ {Γ A B} {V : Γ ⊢ A} {W : Γ ⊢ B} → Value V → Value W ---------------------- → `proj₁ `⟨ V , W ⟩ —→ V β-proj₂ : ∀ {Γ A B} {V : Γ ⊢ A} {W : Γ ⊢ B} → Value V → Value W ---------------------- → `proj₂ `⟨ V , W ⟩ —→ W -- alternative formulation of products ξ-case× : ∀ {Γ A B C} {L L′ : Γ ⊢ A `× B} {M : Γ , A , B ⊢ C} → L —→ L′ ----------------------- → case× L M —→ case× L′ M β-case× : ∀ {Γ A B C} {V : Γ ⊢ A} {W : Γ ⊢ B} {M : Γ , A , B ⊢ C} → Value V → Value W ---------------------------------- → case× `⟨ V , W ⟩ M —→ M [ V ][ W ]Reflexive and transitive closure
infix 2 _—↠_infix 1 begin_infixr 2 _—→⟨_⟩_infix 3 _∎data _—↠_ : ∀ {Γ A} → (Γ ⊢ A) → (Γ ⊢ A) → Set where _∎ : ∀ {Γ A} (M : Γ ⊢ A) ------ → M —↠ M _—→⟨_⟩_ : ∀ {Γ A} (L : Γ ⊢ A) {M N : Γ ⊢ A} → L —→ M → M —↠ N ------ → L —↠ Nbegin_ : ∀ {Γ A} {M N : Γ ⊢ A} → M —↠ N ------ → M —↠ Nbegin M—↠N = M—↠NValues do not reduce
V¬—→ : ∀ {Γ A} {M N : Γ ⊢ A} → Value M ---------- → ¬ (M —→ N)V¬—→ V-ƛ ()V¬—→ V-zero ()V¬—→ (V-suc VM) (ξ-suc M—→M′) = V¬—→ VM M—→M′V¬—→ V-con ()V¬—→ V-⟨ VM , _ ⟩ (ξ-⟨,⟩₁ M—→M′) = V¬—→ VM M—→M′V¬—→ V-⟨ _ , VN ⟩ (ξ-⟨,⟩₂ _ N—→N′) = V¬—→ VN N—→N′Progress
data Progress {A} (M : ∅ ⊢ A) : Set where step : ∀ {N : ∅ ⊢ A} → M —→ N ---------- → Progress M done : Value M ---------- → Progress Mprogress : ∀ {A} → (M : ∅ ⊢ A) ----------- → Progress Mprogress (` ())progress (ƛ N) = done V-ƛprogress (L · M) with progress L... | step L—→L′ = step (ξ-·₁ L—→L′)... | done V-ƛ with progress M... | step M—→M′ = step (ξ-·₂ V-ƛ M—→M′)... | done VM = step (β-ƛ VM)progress (`zero) = done V-zeroprogress (`suc M) with progress M... | step M—→M′ = step (ξ-suc M—→M′)... | done VM = done (V-suc VM)progress (case L M N) with progress L... | step L—→L′ = step (ξ-case L—→L′)... | done V-zero = step β-zero... | done (V-suc VL) = step (β-suc VL)progress (μ N) = step β-μprogress (con n) = done V-conprogress (L `* M) with progress L... | step L—→L′ = step (ξ-*₁ L—→L′)... | done V-con with progress M... | step M—→M′ = step (ξ-*₂ V-con M—→M′)... | done V-con = step δ-*progress (`let M N) with progress M... | step M—→M′ = step (ξ-let M—→M′)... | done VM = step (β-let VM)progress `⟨ M , N ⟩ with progress M... | step M—→M′ = step (ξ-⟨,⟩₁ M—→M′)... | done VM with progress N... | step N—→N′ = step (ξ-⟨,⟩₂ VM N—→N′)... | done VN = done (V-⟨ VM , VN ⟩)progress (`proj₁ L) with progress L... | step L—→L′ = step (ξ-proj₁ L—→L′)... | done (V-⟨ VM , VN ⟩) = step (β-proj₁ VM VN)progress (`proj₂ L) with progress L... | step L—→L′ = step (ξ-proj₂ L—→L′)... | done (V-⟨ VM , VN ⟩) = step (β-proj₂ VM VN)progress (case× L M) with progress L... | step L—→L′ = step (ξ-case× L—→L′)... | done (V-⟨ VM , VN ⟩) = step (β-case× VM VN)Evaluation
data Gas : Set where gas : ℕ → Gasdata Finished {Γ A} (N : Γ ⊢ A) : Set where done : Value N ---------- → Finished N out-of-gas : ---------- Finished Ndata Steps : ∀ {A} → ∅ ⊢ A → Set where steps : ∀ {A} {L N : ∅ ⊢ A} → L —↠ N → Finished N ---------- → Steps Leval : ∀ {A} → Gas → (L : ∅ ⊢ A) ----------- → Steps Leval (gas zero) L = steps (L ∎) out-of-gaseval (gas (suc m)) L with progress L... | done VL = steps (L ∎) (done VL)... | step {M} L—→M with eval (gas m) M... | steps M—↠N fin = steps (L —→⟨ L—→M ⟩ M—↠N) finExamples
cube : ∅ ⊢ Nat ⇒ Natcube = ƛ (# 0 `* # 0 `* # 0)_ : cube · con 2 —↠ con 8_ = begin cube · con 2 —→⟨ β-ƛ V-con ⟩ con 2 `* con 2 `* con 2 —→⟨ ξ-*₁ δ-* ⟩ con 4 `* con 2 —→⟨ δ-* ⟩ con 8 ∎exp10 : ∅ ⊢ Nat ⇒ Natexp10 = ƛ (`let (# 0 `* # 0) (`let (# 0 `* # 0) (`let (# 0 `* # 2) (# 0 `* # 0))))_ : exp10 · con 2 —↠ con 1024_ = begin exp10 · con 2 —→⟨ β-ƛ V-con ⟩ `let (con 2 `* con 2) (`let (# 0 `* # 0) (`let (# 0 `* con 2) (# 0 `* # 0))) —→⟨ ξ-let δ-* ⟩ `let (con 4) (`let (# 0 `* # 0) (`let (# 0 `* con 2) (# 0 `* # 0))) —→⟨ β-let V-con ⟩ `let (con 4 `* con 4) (`let (# 0 `* con 2) (# 0 `* # 0)) —→⟨ ξ-let δ-* ⟩ `let (con 16) (`let (# 0 `* con 2) (# 0 `* # 0)) —→⟨ β-let V-con ⟩ `let (con 16 `* con 2) (# 0 `* # 0) —→⟨ ξ-let δ-* ⟩ `let (con 32) (# 0 `* # 0) —→⟨ β-let V-con ⟩ con 32 `* con 32 —→⟨ δ-* ⟩ con 1024 ∎swap× : ∀ {A B} → ∅ ⊢ A `× B ⇒ B `× Aswap× = ƛ `⟨ `proj₂ (# 0) , `proj₁ (# 0) ⟩_ : swap× · `⟨ con 42 , `zero ⟩ —↠ `⟨ `zero , con 42 ⟩_ = begin swap× · `⟨ con 42 , `zero ⟩ —→⟨ β-ƛ V-⟨ V-con , V-zero ⟩ ⟩ `⟨ `proj₂ `⟨ con 42 , `zero ⟩ , `proj₁ `⟨ con 42 , `zero ⟩ ⟩ —→⟨ ξ-⟨,⟩₁ (β-proj₂ V-con V-zero) ⟩ `⟨ `zero , `proj₁ `⟨ con 42 , `zero ⟩ ⟩ —→⟨ ξ-⟨,⟩₂ V-zero (β-proj₁ V-con V-zero) ⟩ `⟨ `zero , con 42 ⟩ ∎swap×-case : ∀ {A B} → ∅ ⊢ A `× B ⇒ B `× Aswap×-case = ƛ case× (# 0) `⟨ # 0 , # 1 ⟩_ : swap×-case · `⟨ con 42 , `zero ⟩ —↠ `⟨ `zero , con 42 ⟩_ = begin swap×-case · `⟨ con 42 , `zero ⟩ —→⟨ β-ƛ V-⟨ V-con , V-zero ⟩ ⟩ case× `⟨ con 42 , `zero ⟩ `⟨ # 0 , # 1 ⟩ —→⟨ β-case× V-con V-zero ⟩ `⟨ `zero , con 42 ⟩ ∎Exercise More (recommended and practice)
Formalise the remaining constructs defined in this chapter. Make your changes in this file. Evaluate each example, applied to data as needed, to confirm it returns the expected answer:
sums (recommended)
unit type (practice)
an alternative formulation of unit type (practice)
empty type (recommended)
lists (practice)
Please delimit any code you add as follows:
-- begin-- endExercise double-subst (stretch)
Show that a double substitution is equivalent to two single substitutions.
postulate double-subst : ∀ {Γ A B C} {V : Γ ⊢ A} {W : Γ ⊢ B} {N : Γ , A , B ⊢ C} → N [ V ][ W ] ≡ (N [ rename S_ W ]) [ V ]Note the arguments need to be swapped and W needs to have its context adjusted via renaming in order for the right-hand side to be well typed.
Test examples
We repeat the test examples from Chapter DeBruijn, in order to make sure we have not broken anything in the process of extending our base calculus.
two : ∀ {Γ} → Γ ⊢ `ℕtwo = `suc `suc `zeroplus : ∀ {Γ} → Γ ⊢ `ℕ ⇒ `ℕ ⇒ `ℕplus = μ ƛ ƛ (case (# 1) (# 0) (`suc (# 3 · # 0 · # 1)))2+2 : ∀ {Γ} → Γ ⊢ `ℕ2+2 = plus · two · twoCh : Type → TypeCh A = (A ⇒ A) ⇒ A ⇒ Atwoᶜ : ∀ {Γ A} → Γ ⊢ Ch Atwoᶜ = ƛ ƛ (# 1 · (# 1 · # 0))plusᶜ : ∀ {Γ A} → Γ ⊢ Ch A ⇒ Ch A ⇒ Ch Aplusᶜ = ƛ ƛ ƛ ƛ (# 3 · # 1 · (# 2 · # 1 · # 0))sucᶜ : ∀ {Γ} → Γ ⊢ `ℕ ⇒ `ℕsucᶜ = ƛ `suc (# 0)2+2ᶜ : ∀ {Γ} → Γ ⊢ `ℕ2+2ᶜ = plusᶜ · twoᶜ · twoᶜ · sucᶜ · `zeroUnicode
This chapter uses the following unicode:
σ U+03C3 GREEK SMALL LETTER SIGMA (\Gs or \sigma)† U+2020 DAGGER (\dag)‡ U+2021 DOUBLE DAGGER (\ddag)This work is licensed under a Creative Commons Attribution 4.0 International License. Some changes were made to the original version in order to adapt its contents to nextjournal.