added line to explain defn of multiplication

This commit is contained in:
Philip Wadler 2019-01-08 12:12:26 +00:00
parent 9d5e96a76b
commit 6f6d02eed4
106 changed files with 2 additions and 33241 deletions

View file

@ -1,55 +0,0 @@
---
title : "Inherent"
layout : page
permalink : /Inherent/
---
\begin{code}
module plfa.Inherent where
infix 4 _⊢_
infix 4 _∋_
infixl 5 _,_
\end{code}
## WTF
\begin{code}
data Type : Set where
_⇒_ : Type → Type → Type
` : Type
data Context : Set where
∅ : Context
_,_ : Context → Type → Context
data _∋_ : Context → Type → Set where
Z : ∀ {Γ A}
----------
→ Γ , A ∋ A
S_ : ∀ {Γ A B}
→ Γ ∋ A
---------
→ Γ , B ∋ A
data _⊢_ : Context → Type → Set where
`_ : ∀ {Γ} {A}
→ Γ ∋ A
------
→ Γ ⊢ A
ƛ_ : ∀ {Γ} {A B}
→ Γ , A ⊢ B
----------
→ Γ ⊢ A ⇒ B
_·_ : ∀ {Γ} {A B}
→ Γ ⊢ A ⇒ B
→ Γ ⊢ A
----------
→ Γ ⊢ B
\end{code}

View file

@ -1,652 +0,0 @@
---
title : "Pure: Pure Type Systems"
layout : page
permalink : /Pure/
---
Barendregt, H. (1991). Introduction to generalized type
systems. Journal of Functional Programming, 1(2),
125-154. doi:10.1017/S0956796800020025
Fri 8 June
Tried to add weakening directly as a rule. Doing so broke the
definition of renaming, and I could not figure out how to fix it.
Also, need to have variables as a separate construct in order to
define substitution a la Conor. Tried to prove weakening as a derived
rule, but it is tricky. In
Π[_]_⇒_ : ∀ {n} {Γ : Context n} {A : Term n} {B : Term (suc n)} {s t : Sort}
→ Permitted s t
→ Γ ⊢ A ⦂ ⟪ s ⟫
→ Γ , A ⊢ B ⦂ ⟪ t ⟫
-------------------
→ Γ ⊢ Π A ⇒ B ⦂ ⟪ t ⟫
weakening on the middle hypothesis take Γ to Γ , C but weakening on
the last hypothesis takes Γ , A to Γ , C , A, so permutation is required
before one can apply the induction hypothesis. I presume this could
be done similarly to LambdaProp.
## Imports
\begin{code}
module Pure where
\end{code}
\begin{code}
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.Nat using (; zero; suc; _+_; _∸_)
open import Data.Product using (_×_; Σ; Σ-syntax; proj₁; proj₂)
renaming (_,_ to ⟨_,_⟩)
open import Data.Unit using (; tt)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Function using (_∘_)
open import Function.Equivalence using (_⇔_; equivalence)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Decidable using (map)
open import Relation.Nullary.Negation using (contraposition)
open import Relation.Nullary.Product using (_×-dec_)
\end{code}
## Syntax
Scoped, but not inherently typed.
\begin{code}
infix 6 ƛ_⇒_
infix 7 Π_⇒_
infixr 8 _⇒_
infixl 9 _·_
data Sort : Set where
* : Sort
▢ : Sort
data Var : → Set where
Z : ∀ {n}
-----------
→ Var (suc n)
S_ : ∀ {n}
→ Var n
-----------
→ Var (suc n)
data Term : → Set where
⟪_⟫ : ∀ {n}
→ Sort
------
→ Term n
⌊_⌋ : ∀ {n}
→ Var n
------
→ Term n
Π_⇒_ : ∀ {n}
→ Term n
→ Term (suc n)
------------
→ Term n
ƛ_⇒_ : ∀ {n}
→ Term n
→ Term (suc n)
------------
→ Term n
_·_ : ∀ {n}
→ Term n
→ Term n
------
→ Term n
\end{code}
## Renaming
\begin{code}
extr : ∀ {m n} → (Var m → Var n) → (Var (suc m) → Var (suc n))
extr ρ Z = Z
extr ρ (S k) = S (ρ k)
rename : ∀ {m n} → (Var m → Var n) → (Term m → Term n)
rename ρ ⟪ s ⟫ = ⟪ s ⟫
rename ρ ⌊ k ⌋ = ⌊ ρ k ⌋
rename ρ (Π A ⇒ B) = Π rename ρ A ⇒ rename (extr ρ) B
rename ρ (ƛ A ⇒ N) = ƛ rename ρ A ⇒ rename (extr ρ) N
rename ρ (L · M) = rename ρ L · rename ρ M
\end{code}
## Substitution
\begin{code}
exts : ∀ {m n} → (Var m → Term n) → (Var (suc m) → Term (suc n))
exts ρ Z = ⌊ Z ⌋
exts ρ (S k) = rename S_ (ρ k)
subst : ∀ {m n} → (Var m → Term n) → (Term m → Term n)
subst σ ⟪ s ⟫ = ⟪ s ⟫
subst σ ⌊ k ⌋ = σ k
subst σ (Π A ⇒ B) = Π subst σ A ⇒ subst (exts σ) B
subst σ (ƛ A ⇒ N) = ƛ subst σ A ⇒ subst (exts σ) N
subst σ (L · M) = subst σ L · subst σ M
_[_] : ∀ {n} → Term (suc n) → Term n → Term n
_[_] {n} N M = subst {suc n} {n} σ N
where
σ : Var (suc n) → Term n
σ Z = M
σ (S k) = ⌊ k ⌋
\end{code}
## Functions
\begin{code}
_⇒_ : ∀ {n} → Term n → Term n → Term n
A ⇒ B = Π A ⇒ rename S_ B
\end{code}
## Writing variables as numerals
\begin{code}
var : ∀ n → → Var n
var zero _ = ⊥-elim impossible
where postulate impossible : ⊥
var (suc n) 0 = Z
var (suc n) (suc m) = S (var n m)
infix 10 #_
#_ : ∀ {n} → → Term n
#_ {n} m = ⌊ var n m ⌋
\end{code}
## Test examples
\begin{code}
Ch : ∀ {n} → Term n
Ch = Π ⟪ * ⟫ ⇒ ((# 0 ⇒ # 0) ⇒ # 0 ⇒ # 0)
-- Ch = Π X ⦂ * ⇒ (X ⇒ X) ⇒ X ⇒ X
two : ∀ {n} → Term n
two = ƛ ⟪ * ⟫ ⇒ ƛ (# 0 ⇒ # 0) ⇒ ƛ # 1 ⇒ # 1 · (# 1 · # 0)
-- two = ƛ X ⦂ * ⇒ ƛ s ⦂ (X ⇒ X) ⇒ ƛ z ⦂ X ⇒ s · (s · z)
four : ∀ {n} → Term n
four = ƛ ⟪ * ⟫ ⇒ ƛ (# 0 ⇒ # 0) ⇒ ƛ # 1 ⇒ # 1 · (# 1 · (# 1 · (# 1 · # 0)))
-- four = ƛ X ⦂ * ⇒ ƛ s ⦂ (X ⇒ X) ⇒ ƛ z ⦂ X ⇒ s · (s · (s · (s · z)))
plus : ∀ {n} → Term n
plus = ƛ Ch ⇒ ƛ Ch ⇒ ƛ ⟪ * ⟫ ⇒ ƛ (# 0 ⇒ # 0) ⇒ ƛ # 1 ⇒
(# 4 · # 2 · # 1 · (# 3 · # 2 · # 1 · # 0))
-- plus = ƛ m ⦂ Ch ⇒ ƛ n ⦂ Ch ⇒ ƛ X ⦂ * ⇒ ƛ s ⦂ (X ⇒ X) ⇒ ƛ z ⦂ X ⇒
-- m X s (n X s z)
\end{code}
## Normal
\begin{code}
data Normal : ∀ {n} → Term n → Set
data Neutral : ∀ {n} → Term n → Set
data Normal where
⟪_⟫ : ∀ {n} {s : Sort}
----------------
→ Normal {n} ⟪ s ⟫
Π_⇒_ : ∀ {n} {A : Term n} {B : Term (suc n)}
→ Normal A
→ Normal B
----------------
→ Normal (Π A ⇒ B)
ƛ_⇒_ : ∀ {n} {A : Term n} {N : Term (suc n)}
→ Normal A
→ Normal N
----------------
→ Normal (ƛ A ⇒ N)
⌈_⌉ : ∀ {n} {M : Term n}
→ Neutral M
---------
→ Normal M
data Neutral where
⌊_⌋ : ∀ {n}
→ (k : Var n)
-------------
→ Neutral ⌊ k ⌋
_·_ : ∀ {n} {L : Term n} {M : Term n}
→ Neutral L
→ Normal M
---------------
→ Neutral (L · M)
\end{code}
Convenient shorthand for neutral variables.
\begin{code}
infix 10 #ᵘ_
#ᵘ_ : ∀ {n} (m : ) → Neutral ⌊ var n m ⌋
#ᵘ_ {n} m = ⌊ var n m ⌋
\end{code}
## Reduction step
\begin{code}
infix 2 _⟶_
Application : ∀ {n} → Term n → Set
Application ⟪ _ ⟫ = ⊥
Application ⌊ _ ⌋ = ⊥
Application (Π _ ⇒ _) = ⊥
Application (ƛ _ ⇒ _) = ⊥
Application (_ · _) =
data _⟶_ : ∀ {n} → Term n → Term n → Set where
ξ₁ : ∀ {n} {L L M : Term n}
→ Application L
→ L ⟶ L
----------------
→ L · M ⟶ L · M
ξ₂ : ∀ {n} {L M M : Term n}
→ Neutral L
→ M ⟶ M
----------------
→ L · M ⟶ L · M
β : ∀ {n} {A : Term n} {N : Term (suc n)} {M : Term n}
--------------------------------------------------
→ (ƛ A ⇒ N) · M ⟶ N [ M ]
ζΠ₁ : ∀ {n} {A A : Term n} {B : Term (suc n)}
→ A ⟶ A
--------------------
→ Π A ⇒ B ⟶ Π A ⇒ B
ζΠ₂ : ∀ {n} {A : Term n} {B B : Term (suc n)}
→ B ⟶ B
--------------------
→ Π A ⇒ B ⟶ Π A ⇒ B
ζƛ₁ : ∀ {n} {A A : Term n} {B : Term (suc n)}
→ A ⟶ A
--------------------
→ ƛ A ⇒ B ⟶ ƛ A ⇒ B
ζƛ₂ : ∀ {n} {A : Term n} {B B : Term (suc n)}
→ B ⟶ B
--------------------
→ ƛ A ⇒ B ⟶ ƛ A ⇒ B
\end{code}
## Reflexive and transitive closure
\begin{code}
infix 2 _⟶*_
infix 1 begin_
infixr 2 _⟶⟨_⟩_
infix 3 _∎
data _⟶*_ : ∀ {n} → Term n → Term n → Set where
_∎ : ∀ {n} (M : Term n)
---------------------
→ M ⟶* M
_⟶⟨_⟩_ : ∀ {n} (L : Term n) {M N : Term n}
→ L ⟶ M
→ M ⟶* N
---------
→ L ⟶* N
begin_ : ∀ {n} {M N : Term n}
→ M ⟶* N
--------
→ M ⟶* N
\end{code}
## Reflexive, symmetric, and transitive closure
\begin{code}
data _=β_ : ∀ {n} → Term n → Term n → Set where
_∎ : ∀ {n} (M : Term n)
-------------------
→ M =β M
_⟶⟨_⟩_ : ∀ {n} (L : Term n) {M N : Term n}
→ L ⟶ M
→ M =β N
---------
→ L =β N
_⟵⟨_⟩_ : ∀ {n} (L : Term n) {M N : Term n}
→ M ⟶ L
→ M =β N
---------
→ L =β N
begin_ : ∀ {n} {M N : Term n}
→ M =β N
--------
→ M =β N
\end{code}
## Example reduction sequences
\begin{code}
Id : Term zero
Id = Π ⟪ * ⟫ ⇒ (# 0 ⇒ # 0)
-- Id = Π X ⦂ ⟪ * ⟫ ⇒ (X ⇒ X)
id : Term zero
id = ƛ ⟪ * ⟫ ⇒ ƛ # 0 ⇒ # 0
-- id = ƛ X ⦂ ⟪ * ⟫ ⇒ ƛ x ⦂ X ⇒ x
_ : id · Id · id ⟶* id
_ =
begin
id · Id · id
⟶⟨ ξ₁ tt β ⟩
(ƛ Id ⇒ # 0) · id
⟶⟨ β ⟩
id
_ : plus {zero} · two · two ⟶* four
_ =
begin
plus · two · two
⟶⟨ ξ₁ tt β ⟩
(ƛ Ch ⇒ ƛ ⟪ * ⟫ ⇒ ƛ (# 0 ⇒ # 0) ⇒ ƛ # 1 ⇒
two · # 2 · # 1 · (# 3 · # 2 · # 1 · # 0)) · two
⟶⟨ β ⟩
ƛ ⟪ * ⟫ ⇒ ƛ (# 0 ⇒ # 0) ⇒ ƛ # 1 ⇒ two · # 2 · # 1 · (two · # 2 · # 1 · # 0)
⟶⟨ ζƛ₂ (ζƛ₂ (ζƛ₂ (ξ₁ tt (ξ₁ tt β)))) ⟩
ƛ ⟪ * ⟫ ⇒ ƛ (# 0 ⇒ # 0) ⇒ ƛ # 1 ⇒
(ƛ (# 2 ⇒ # 2) ⇒ ƛ # 3 ⇒ # 1 · (# 1 · # 0)) · # 1 · (two · # 2 · # 1 · # 0)
⟶⟨ ζƛ₂ (ζƛ₂ (ζƛ₂ (ξ₁ tt β))) ⟩
ƛ ⟪ * ⟫ ⇒ ƛ (# 0 ⇒ # 0) ⇒ ƛ # 1 ⇒
(ƛ # 2 ⇒ # 2 · (# 2 · # 0)) · (two · # 2 · # 1 · # 0)
⟶⟨ ζƛ₂ (ζƛ₂ (ζƛ₂ β)) ⟩
ƛ ⟪ * ⟫ ⇒ ƛ (# 0 ⇒ # 0) ⇒ ƛ # 1 ⇒ # 1 · (# 1 · (two · # 2 · # 1 · # 0))
⟶⟨ ζƛ₂ (ζƛ₂ (ζƛ₂ (ξ₂ (#ᵘ 1) (ξ₂ (#ᵘ 1) (ξ₁ tt (ξ₁ tt β)))))) ⟩
ƛ ⟪ * ⟫ ⇒ ƛ (# 0 ⇒ # 0) ⇒ ƛ # 1 ⇒ # 1 · (# 1 ·
((ƛ (# 2 ⇒ # 2) ⇒ ƛ # 3 ⇒ # 1 · (# 1 · # 0)) · # 1 · # 0))
⟶⟨ ζƛ₂ (ζƛ₂ (ζƛ₂ (ξ₂ (#ᵘ 1) (ξ₂ (#ᵘ 1) (ξ₁ tt β))))) ⟩
ƛ ⟪ * ⟫ ⇒ ƛ (# 0 ⇒ # 0) ⇒ ƛ # 1 ⇒ # 1 · (# 1 ·
((ƛ # 2 ⇒ # 2 · (# 2 · # 0)) · # 0))
⟶⟨ ζƛ₂ (ζƛ₂ (ζƛ₂ (ξ₂ (#ᵘ 1) (ξ₂ (#ᵘ 1) β)))) ⟩
ƛ ⟪ * ⟫ ⇒ ƛ (# 0 ⇒ # 0) ⇒ ƛ # 1 ⇒ # 1 · (# 1 · (# 1 · (# 1 · # 0)))
\end{code}
## Type rules
\begin{code}
data Permitted : Sort → Sort → Set where
** : Permitted * *
*▢ : Permitted * ▢
▢* : Permitted ▢ *
▢▢ : Permitted ▢ ▢
infix 4 _⊢_⦂_
infix 4 _∋_⦂_
infixl 5 _,_
data Context : → Set where
∅ : Context zero
_,_ : ∀ {n} → Context n → Term n → Context (suc n)
data _∋_⦂_ : ∀ {n} → Context n → Var n → Term n → Set
data _⊢_⦂_ : ∀ {n} → Context n → Term n → Term n → Set
data _∋_⦂_ where
Z[_] : ∀ {n} {Γ : Context n} {A : Term n} {s : Sort}
→ Γ ⊢ A ⦂ ⟪ s ⟫
-----------------------
→ Γ , A ∋ Z ⦂ rename S_ A
S[_]_ : ∀ {n} {Γ : Context n} {x : Var n} {A B : Term n} {s : Sort}
→ Γ ⊢ A ⦂ ⟪ s ⟫
→ Γ ∋ x ⦂ B
-------------------------
→ Γ , A ∋ S x ⦂ rename S_ B
data _⊢_⦂_ where
⟪*⟫ : ∀ {n} {Γ : Context n}
-----------------
→ Γ ⊢ ⟪ * ⟫ ⦂ ⟪ ▢ ⟫
⌊_⌋ : ∀ {n} {Γ : Context n} {x : Var n} {A : Term n}
→ Γ ∋ x ⦂ A
-------------
→ Γ ⊢ ⌊ x ⌋ ⦂ A
Π[_]_⇒_ : ∀ {n} {Γ : Context n} {A : Term n} {B : Term (suc n)} {s t : Sort}
→ Permitted s t
→ Γ ⊢ A ⦂ ⟪ s ⟫
→ Γ , A ⊢ B ⦂ ⟪ t ⟫
-------------------
→ Γ ⊢ Π A ⇒ B ⦂ ⟪ t ⟫
ƛ[_]_⇒_⦂_ : ∀ {n} {Γ : Context n} {A : Term n} {N B : Term (suc n)} {s t : Sort}
→ Permitted s t
→ Γ ⊢ A ⦂ ⟪ s ⟫
→ Γ , A ⊢ N ⦂ B
→ Γ , A ⊢ B ⦂ ⟪ t ⟫
---------------------
→ Γ ⊢ ƛ A ⇒ N ⦂ Π A ⇒ B
_·_ : ∀ {n} {Γ : Context n} {L M A : Term n} {B : Term (suc n)}
→ Γ ⊢ L ⦂ Π A ⇒ B
→ Γ ⊢ M ⦂ A
-------------------
→ Γ ⊢ L · M ⦂ B [ M ]
Eq : ∀ {n} {Γ : Context n} {M A B : Term n}
→ Γ ⊢ M ⦂ A
→ A =β B
---------
→ Γ ⊢ M ⦂ B
\end{code}
## Rename
\begin{code}
⊢extr : ∀ {m n} {Γ : Context m} {Δ : Context n}
→ (ρ : Var m → Var n)
→ (∀ {w : Var m} {B : Term m} → Γ ∋ w ⦂ B → Δ ∋ ρ w ⦂ rename ρ B)
---------------------------------------------------------------
→ (∀ {w : Var (suc m)} {A : Term m} {B : Term (suc m)}
→ Γ , A ∋ w ⦂ B → Δ , rename ρ A ∋ extr ρ w ⦂ rename (extr ρ) B)
⊢rename : ∀ {m n} {Γ : Context m} {Δ : Context n}
→ (ρ : Var m → Var n)
→ (∀ {w : Var m} {B : Term m} → Γ ∋ w ⦂ B → Δ ∋ ρ w ⦂ rename ρ B)
------------------------------------------------------
→ (∀ {w : Var m} {M A : Term m}
→ Γ ⊢ M ⦂ A → Δ ⊢ rename ρ M ⦂ rename ρ A)
⊢extr ρ ⊢ρ Z[ ⊢A ] = Z[ ⊢rename ρ ⊢ρ ⊢A ]
⊢extr ρ ⊢ρ (S[ ⊢A ] ∋w) = S[ ⊢rename ρ ⊢ρ ⊢A ] (ρ ∋w)
⊢rename = {!!}
{-
⊢rename σ (Ax ∋w) = Ax (σ ∋w)
⊢rename σ (⇒-I ⊢N) = ⇒-I (⊢rename (⊢extr σ) ⊢N)
⊢rename σ (⇒-E ⊢L ⊢M) = ⇒-E (⊢rename σ ⊢L) (⊢rename σ ⊢M)
⊢rename σ -I₁ = -I₁
⊢rename σ (-I₂ ⊢M) = -I₂ (⊢rename σ ⊢M)
⊢rename σ (-E ⊢L ⊢M ⊢N) = -E (⊢rename σ ⊢L) (⊢rename σ ⊢M) (⊢rename (⊢extr σ) ⊢N)
⊢rename σ (Fix ⊢M) = Fix (⊢rename (⊢extr σ) ⊢M)
-}
\end{code}
## Weakening
\begin{code}
{-
weak : ∀ {n} {Γ : Context n} {M : Term n} {A B : Term n} {s : Sort}
→ Γ ⊢ A ⦂ ⟪ s ⟫
→ Γ ⊢ M ⦂ B
---------------------------------
→ Γ , A ⊢ rename S_ M ⦂ rename S_ B
weak ⊢C ⟪*⟫ = ⟪*⟫
weak ⊢C ⌊ ∋x ⌋ = ⌊ S[ ⊢C ] ∋x ⌋
weak ⊢C (Π[ st ] ⊢A ⇒ ⊢B) = {! Π[ st ] weak ⊢A ⇒ weak ⊢B!}
weak ⊢C (ƛ[ x ] ⊢M ⇒ ⊢M₁ ⦂ ⊢M₂) = {!!}
weak ⊢C (⊢M · ⊢M₁) = {!!}
weak ⊢C (Eq ⊢M x) = {!!}
-}
\end{code}
## Substitution in type derivations
\begin{code}
{-
exts : ∀ {m n} → (Var m → Term n) → (Var (suc m) → Term (suc n))
exts ρ Z = ⌊ Z ⌋
exts ρ (S k) = rename S_ (ρ k)
subst : ∀ {m n} → (Var m → Term n) → (Term m → Term n)
subst σ ⟪ s ⟫ = ⟪ s ⟫
subst σ ⌊ k ⌋ = σ k
subst σ (Π A ⇒ B) = Π subst σ A ⇒ subst (exts σ) B
subst σ (ƛ A ⇒ N) = ƛ subst σ A ⇒ subst (exts σ) N
subst σ (L · M) = subst σ L · subst σ M
_[_] : ∀ {n} → Term (suc n) → Term n → Term n
_[_] {n} N M = subst {suc n} {n} σ N
where
σ : Var (suc n) → Term n
σ Z = M
σ (S k) = ⌊ k ⌋
-}
\end{code}
## Test examples are well-typed
\begin{code}
{-
_⊢⇒_ : ∀ {n} {Γ : Context n} {A B : Term n}
→ Γ ⊢ A ⦂ ⟪ * ⟫ → Γ ⊢ B ⦂ ⟪ * ⟫ → Γ ⊢ A ⇒ B ⦂ ⟪ * ⟫
⊢A ⊢⇒ ⊢B = Π[ ** ] ⊢A ⇒ rename S_ ⊢B
-}
-- ⊢Ch : ∅ ⊢ Ch ⦂ ⟪ * ⟫
-- ⊢Ch = Π[ ** ] ⟪ * ⟫ ⇒ Π[ ** ] ⌊ Z ⌋
-- Ch = Π ⟪ * ⟫ ⇒ ((# 0 ⇒ # 0) ⇒ # 0 ⇒ # 0)
-- Ch = Π X ⦂ * ⇒ (X ⇒ X) ⇒ X ⇒ X
{-
two : ∀ {n} → Term n
two = ƛ ⟪ * ⟫ ⇒ ƛ (# 0 ⇒ # 0) ⇒ ƛ # 1 ⇒ # 1 · (# 1 · # 0)
-- two = ƛ X ⦂ * ⇒ ƛ s ⦂ (X ⇒ X) ⇒ ƛ z ⦂ X ⇒ s · (s · z)
four : ∀ {n} → Term n
four = ƛ ⟪ * ⟫ ⇒ ƛ (# 0 ⇒ # 0) ⇒ ƛ # 1 ⇒ # 1 · (# 1 · (# 1 · (# 1 · # 0)))
-- four = ƛ X ⦂ * ⇒ ƛ s ⦂ (X ⇒ X) ⇒ ƛ z ⦂ X ⇒ s · (s · (s · (s · z)))
plus : ∀ {n} → Term n
plus = ƛ Ch ⇒ ƛ Ch ⇒ ƛ ⟪ * ⟫ ⇒ ƛ (# 0 ⇒ # 0) ⇒ ƛ # 1 ⇒
(# 4 · # 2 · # 1 · (# 3 · # 2 · # 1 · # 0))
-- plus = ƛ m ⦂ Ch ⇒ ƛ n ⦂ Ch ⇒ ƛ X ⦂ * ⇒ ƛ s ⦂ (X ⇒ X) ⇒ ƛ z ⦂ X ⇒
-- m X s (n X s z)
-}
\end{code}
## Progress
\begin{code}
{-
data Progress {n} (M : Term n) : Set where
step : ∀ {N : Term n}
→ M ⟶ N
----------
→ Progress M
done :
Normal M
----------
→ Progress M
progress : ∀ {n} → (M : Term n) → Progress M
progress ⌊ x ⌋ = done ⌈ ⌊ x ⌋ ⌉
progress (ƛ N) with progress N
... | step N⟶N = step (ζ N⟶N)
... | done Nⁿ = done (ƛ Nⁿ)
progress (⌊ x ⌋ · M) with progress M
... | step M⟶M = step (ξ₂ ⌊ x ⌋ M⟶M)
... | done Mⁿ = done ⌈ ⌊ x ⌋ · Mⁿ ⌉
progress ((ƛ N) · M) = step β
progress (L@(_ · _) · M) with progress L
... | step L⟶L = step (ξ₁ tt L⟶L)
... | done ⌈ Lᵘ ⌉ with progress M
... | step M⟶M = step (ξ₂ Lᵘ M⟶M)
... | done Mⁿ = done ⌈ Lᵘ · Mⁿ ⌉
-}
\end{code}
## Normalise
\begin{code}
{-
Gas : Set
Gas =
data Normalise {n} (M : Term n) : Set where
out-of-gas : ∀ {N : Term n}
→ M ⟶* N
-------------
→ Normalise M
normal : ∀ {N : Term n}
→ Gas
→ M ⟶* N
→ Normal N
--------------
→ Normalise M
normalise : ∀ {n}
→ Gas
→ ∀ (M : Term n)
-------------
→ Normalise M
normalise zero L = out-of-gas (L ∎)
normalise (suc g) L with progress L
... | done Lⁿ = normal (suc g) (L ∎) Lⁿ
... | step {M} L⟶M with normalise g M
... | out-of-gas M⟶*N = out-of-gas (L ⟶⟨ L⟶M ⟩ M⟶*N)
... | normal g M⟶*N Nⁿ = normal g (L ⟶⟨ L⟶M ⟩ M⟶*N) Nⁿ
-}
\end{code}

View file

@ -1,312 +0,0 @@
---
title : "Pure: Pure Type Systems"
layout : page
permalink : /Pure/
---
Barendregt, H. (1991). Introduction to generalized type
systems. Journal of Functional Programming, 1(2),
125-154. doi:10.1017/S0956796800020025
Attempt to create inherently typed terms with Connor.
Phil and Conor's work on 24 Aug:
Tried to define thinning, Γ ⊆ Δ, and got our knickers in a twist.
Tried to define Wk directly on terms, as in Barendregt
We need to push weaking through Π, but this requires weaking
the slot one from the top, rather than the top slot
Next idea: try weaking at arbitrary position n
Also, make type weakened on explicit, to catch more errors
## Imports
\begin{code}
module PureConor where
\end{code}
\begin{code}
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.Nat using (; zero; suc; _+_; _∸_)
open import Data.Product using (_×_; Σ; Σ-syntax; proj₁; proj₂)
renaming (_,_ to ⟨_,_⟩)
open import Data.Unit using (; tt)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Function using (_∘_)
open import Function.Equivalence using (_⇔_; equivalence)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Decidable using (map)
open import Relation.Nullary.Negation using (contraposition)
open import Relation.Nullary.Product using (_×-dec_)
\end{code}
## Syntax
\begin{code}
infix 4 _⊢_
infix 4 _∋_
infix 4 _⊆_
infixl 5 _,_
infixl 6 _/_ _∋/_ _⊢/_ _[_] _⟨_⟩
infix 6 ƛ_⇒_
infix 7 Π_⇒_
-- infixr 8 _⇒_
infixl 9 _·_
infix 20 _W _S
data Sort : Set where
* : Sort
▢ : Sort
ok2 : Sort → Sort → Set
ok2 * ▢ =
ok2 _ _ = ⊥
ok3 : Sort → Sort → Sort → Set
ok3 * * ▢ =
ok3 * ▢ ▢ =
ok3 ▢ * * =
ok3 ▢ ▢ ▢ =
ok3 _ _ _ = ⊥
data Ctx : Set
data Tp : ∀ (Γ : Ctx) → Set
data _⊢_ : ∀ (Γ : Ctx) → Tp Γ → Set
data _—→_ {Γ : Ctx} {A : Tp Γ} : Γ ⊢ A → Γ ⊢ A → Set
data _=β_ {Γ : Ctx} {A : Tp Γ} : Γ ⊢ A → Γ ⊢ A → Set
data Ctx where
∅ :
---
Ctx
_,_ :
(Γ : Ctx)
→ (A : Tp Γ)
-----------
→ Ctx
data Tp where
⟪_⟫ : ∀ {Γ : Ctx}
→ Sort
----
→ Tp Γ
⌈_⌉ : ∀ {Γ : Ctx} {s : Sort}
→ Γ ⊢ ⟪ s ⟫
----------
→ Tp Γ
wk : ∀ {Γ : Ctx} {A : Tp Γ}
→ Tp Γ
-----------
→ Tp (Γ , A)
_[_] : ∀ {Γ : Ctx} {A : Tp Γ}
→ (B : Tp (Γ , A))
→ (M : Γ ⊢ A)
----------------
→ Tp Γ
_⟨_⟩ : ∀ {Γ : Ctx} {A : Tp Γ} {B : Tp (Γ , A)}
→ (N : Γ , A ⊢ B)
→ (M : Γ ⊢ A)
---------------
→ Γ ⊢ B [ M ]
data _⊢_ where
⟪_⟫ : ∀ {Γ : Ctx} {t : Sort}
→ (s : Sort)
→ {st : ok2 s t}
-------------
→ Γ ⊢ ⟪ t ⟫
St : ∀ {Γ : Ctx} {A : Tp Γ}
------------
→ Γ , A ⊢ wk A
Wk : ∀ {Γ : Ctx} {A B : Tp Γ}
→ Γ ⊢ A
------------
→ Γ , B ⊢ wk A
Π_⇒_ : ∀ {Γ : Ctx} {s t u : Sort} {stu : ok3 s t u}
→ (A : Γ ⊢ ⟪ s ⟫)
→ Γ , ⌈ A ⌉ ⊢ ⟪ t ⟫
------------------
→ Γ ⊢ ⟪ u ⟫
ƛ_⇒_ : ∀ {Γ : Ctx} {s t u : Sort} {stu : ok3 s t u}
→ (A : Γ ⊢ ⟪ s ⟫)
→ {B : Γ , ⌈ A ⌉ ⊢ ⟪ t ⟫}
→ Γ , ⌈ A ⌉ ⊢ ⌈ B ⌉
-------------------------------------
→ Γ ⊢ ⌈ Π_⇒_ {u = u} {stu = stu} A B ⌉
_·_ : ∀ {Γ : Ctx} {s t u : Sort} {stu : ok3 s t u}
→ {A : Γ ⊢ ⟪ s ⟫}
→ {B : Γ , ⌈ A ⌉ ⊢ ⟪ t ⟫}
→ (L : Γ ⊢ ⌈ Π_⇒_ {u = u} {stu = stu} A B ⌉)
→ (M : Γ ⊢ ⌈ A ⌉)
------------------------------------------
→ Γ ⊢ ⌈ B ⌉ [ M ]
Cnv : ∀ {Γ : Ctx} {s : Sort} {A B : Γ ⊢ ⟪ s ⟫}
→ Γ ⊢ ⌈ A ⌉
→ A =β B
---------
→ Γ ⊢ ⌈ B ⌉
wk ⟪ s ⟫ = ⟪ s ⟫
wk ⌈ A ⌉ = ⌈ Wk A ⌉
_[_] = {!!}
_⟨_⟩ = {!!}
data _—→_ where
-- this is bollocks! It weakens on A, not on an arbitrary type
Wk-Π : ∀ {Γ : Ctx} {s t u : Sort} {stu : ok3 s t u}
→ (A : Γ ⊢ ⟪ s ⟫)
→ (B : Γ , ⌈ A ⌉ ⊢ ⟪ t ⟫)
-----------------------------------------------------------
→ Wk (Π_⇒_ {stu = stu} A B) —→ Π_⇒_ {stu = stu} (Wk A) (Wk B)
data _=β_ where
refl : ∀ {Γ : Ctx} {A : Tp Γ} {M : Γ ⊢ A}
→ M =β M
tran : ∀ {Γ : Ctx} {A : Tp Γ} {L M N : Γ ⊢ A}
→ L =β M
→ M =β N
------
→ L =β N
symm : ∀ {Γ : Ctx} {A : Tp Γ} {L M : Γ ⊢ A}
→ L =β M
------
→ M =β L
step : ∀ {Γ : Ctx} {A : Tp Γ} {L M : Γ ⊢ A}
→ L —→ M
------
→ L =β M
{-
data _⊆_ : Ctx → Ctx → Set
_/_ : ∀ {Γ Δ : Ctx} → Tp Γ → Γ ⊆ Δ → Tp Δ
_∋/_ : ∀ {Γ Δ : Ctx} {A : Tp Γ} → Γ ∋ A → (θ : Γ ⊆ Δ) → Δ ∋ A / θ
_⊢/_ : ∀ {Γ Δ : Ctx} {A : Tp Γ} → Γ ⊢ A → (θ : Γ ⊆ Δ) → Δ ⊢ A / θ
data _∋_ where
Z : ∀ {Γ : Ctx} {A : Tp Γ}
----------------------
→ Γ , A ∋ A / I W
_S : ∀ {Γ : Ctx} {A B : Tp Γ}
→ Γ ∋ A
----------------
→ Γ , B ∋ A / I W
data _⊆_ where
I : ∀ {Γ : Ctx}
-----
→ Γ ⊆ Γ
_W : ∀ {Γ Δ : Ctx} {A : Tp Δ}
→ Γ ⊆ Δ
-----------
→ Γ ⊆ (Δ , A)
_S : ∀ {Γ Δ : Ctx} {B : Tp Γ}
→ (θ : Γ ⊆ Δ)
-----------------------
→ (Γ , B) ⊆ (Δ , (B / θ))
_-_ : ∀ {Γ Δ Θ : Ctx} → Γ ⊆ Δ → Δ ⊆ Θ → Γ ⊆ Θ
lemma : ∀ {Γ Δ Θ : Ctx} (A : Tp Γ)
→ (θ : Γ ⊆ Δ)
→ (φ : Δ ⊆ Θ)
-----------------------
→ A / θ / φ ≡ A / (θ - φ)
θ - I = θ
θ - (φ W) = (θ - φ) W
I - (φ S) = φ S
(θ W) - (φ S) = (θ - φ) W
_S {B = B} θ - (φ S) rewrite lemma B θ φ = (θ - φ) S
lemma = {!!}
-- lemma A θ I = refl
-- lemma A θ (φ W) = {!!}
-- lemma A θ (φ S) = {!!}
wk : ∀ {Γ : Ctx} (B : Tp Γ) → Γ ⊆ Γ , B
wk B = I W
⟪ s ⟫ / θ = ⟪ s ⟫
⌈ A ⌉ / θ = ⌈ A ⊢/ θ ⌉
-- lemma : ∀ {Γ Δ : Ctx} (θ : Γ ⊆ Δ) (A B : Tp Γ)
-- → A / wk B / θ S ≡ A / θ / wk (B / θ)
-- lemma = {!!}
x ∋/ I = {!!}
x ∋/ θ W = {! x ∋/ θ!}
x ∋/ θ S = {!!}
thin-· : ∀ {Γ Δ : Ctx} {A : Tp Γ} (B : Tp (Γ , A)) (M : Γ ⊢ A) (θ : Γ ⊆ Δ)
→ B [ M ] / θ ≡ B / θ S [ M ⊢/ θ ]
⟪ s ⟫ {st} ⊢/ θ = ⟪ s ⟫ {st}
⌊ x ⌋ ⊢/ θ = ⌊ x ∋/ θ ⌋
Π_⇒_ {stu = stu} A B ⊢/ θ = Π_⇒_ {stu = stu} (A ⊢/ θ) (B ⊢/ θ S)
ƛ_⇒_ {stu = stu} A N ⊢/ θ = ƛ_⇒_ {stu = stu} (A ⊢/ θ) (N ⊢/ θ S)
_·_ {stu = stu} {B = B} L M ⊢/ θ rewrite thin-· ⌈ B ⌉ M θ
= _·_ {stu = stu} (L ⊢/ θ) (M ⊢/ θ)
thin-· = {!!}
_[_] = {!!}
_⟨_⟩ = {!!}
-}
{-
A / I = {!!} -- A
⟪ s ⟫ / θ S = ⟪ s ⟫
⟪ s ⟫ / θ W = ⟪ s ⟫
⌈ A ⌉ / θ S = ⌈ A ⊢/ (θ S) ⌉
⌈ A ⌉ / θ W = ⌈ A ⊢/ (θ W) ⌉
-}
{-
I /∋ x = x
θ W /∋ x = {! θ /∋ x!}
_S {B = B} θ /∋ Z rewrite lemma θ B B = Z
θ S /∋ x S = {!!}
∅ /∋ Z = Z
W θ /∋ x = {!S (θ / x)!}
S θ /∋ (S x) = {!S (θ / x)!}
-}
\end{code}

View file

@ -1,67 +0,0 @@
---
title : "Raw"
layout : page
permalink : /Raw/
---
\begin{code}
module plfa.Raw where
open import Relation.Binary.PropositionalEquality using (_≢_)
open import Data.String using (String)
infix 4 _⊢_⦂_
infix 4 _∋_⦂_
infixl 5 _,_⦂_
\end{code}
## WTF
\begin{code}
Id : Set
Id = String
data Term : Set where
`_ : Id → Term
ƛ_⇒_ : Id → Term → Term
_·_ : Term → Term → Term
data Type : Set where
_⇒_ : Type → Type → Type
` : Type
data Context : Set where
∅ : Context
_,_⦂_ : Context → Id → Type → Context
data _∋_⦂_ : Context → Id → Type → Set where
Z : ∀ {Γ x A}
------------------
→ Γ , x ⦂ A ∋ x ⦂ A
S : ∀ {Γ x y A B}
→ x ≢ y
→ Γ ∋ x ⦂ A
------------------
→ Γ , y ⦂ B ∋ x ⦂ A
data _⊢_⦂_ : Context → Term → Type → Set where
⊢` : ∀ {Γ x A}
→ Γ ∋ x ⦂ A
-------------
→ Γ ⊢ ` x ⦂ A
⊢ƛ : ∀ {Γ x N A B}
→ Γ , x ⦂ A ⊢ N ⦂ B
-------------------
→ Γ ⊢ ƛ x ⇒ N ⦂ A ⇒ B
_·_ : ∀ {Γ L M A B}
→ Γ ⊢ L ⦂ A ⇒ B
→ Γ ⊢ M ⦂ A
-------------
→ Γ ⊢ L · M ⦂ B
\end{code}

View file

@ -1,19 +0,0 @@
## Our first corollary: rearranging
We can apply associativity to rearrange parentheses however we like.
Here is an example.
\begin{code}
+-rearrange : ∀ (m n p q : ) → (m + n) + (p + q) ≡ m + ((n + p) + q)
+-rearrange m n p q =
begin
(m + n) + (p + q)
≡⟨ +-assoc m n (p + q) ⟩
m + (n + (p + q))
≡⟨ cong (m +_) (sym (+-assoc n p q)) ⟩
m + ((n + p) + q)
≡⟨ sym (+-assoc m (n + p) q) ⟩
(m + (n + p)) + q
\end{code}

View file

@ -1,27 +0,0 @@
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; cong)
open Eq.≡-Reasoning using (begin_; _≡⟨⟩_; _≡⟨_⟩_; _∎)
open import Data.Nat using (; zero; suc)
_+_ :
zero + n = n
suc m + n = suc (m + n)
+-assoc : m n p (m + n) + p m + (n + p)
+-assoc zero n p = refl
+-assoc (suc m) n p rewrite +-assoc m n p = refl
{-
Goal:
————————————————————————————————————————————————————————————
n :
-}
{-
Goal:
————————————————————————————————————————————————————————————
n :
m :
-}

View file

@ -1,137 +0,0 @@
---
title : "Basics: Functional Programming in Agda"
layout : page
permalink : /Basics
---
\begin{code}
open import Relation.Binary.PropositionalEquality using (_≡_; refl)
\end{code}
The functional programming style brings programming closer to
simple, everyday mathematics: If a procedure or method has no side
effects, then (ignoring efficiency) all we need to understand
about it is how it maps inputs to outputs -- that is, we can think
of it as just a concrete method for computing a mathematical
function. This is one sense of the word "functional" in
"functional programming." The direct connection between programs
and simple mathematical objects supports both formal correctness
proofs and sound informal reasoning about program behavior.
The other sense in which functional programming is "functional" is
that it emphasizes the use of functions (or methods) as
_first-class_ values -- i.e., values that can be passed as
arguments to other functions, returned as results, included in
data structures, etc. The recognition that functions can be
treated as data in this way enables a host of useful and powerful
idioms.
Other common features of functional languages include _algebraic
data types_ and _pattern matching_, which make it easy to
construct and manipulate rich data structures, and sophisticated
_polymorphic type systems_ supporting abstraction and code reuse.
Agda shares all of these features.
This chapter introduces the most essential elements of Agda.
## Enumerated Types
One unusual aspect of Agda is that its set of built-in
features is _extremely_ small. For example, instead of providing
the usual palette of atomic data types (booleans, integers,
strings, etc.), Agda offers a powerful mechanism for defining new
data types from scratch, from which all these familiar types arise
as instances.
Naturally, the Agda distribution comes with an extensive standard
library providing definitions of booleans, numbers, and many
common data structures like lists and hash tables. But there is
nothing magic or primitive about these library definitions. To
illustrate this, we will explicitly recapitulate all the
definitions we need in this course, rather than just getting them
implicitly from the library.
To see how this definition mechanism works, let's start with a
very simple example.
### Days of the Week
The following declaration tells Agda that we are defining
a new set of data values -- a _type_.
\begin{code}
data Day : Set where
monday : Day
tuesday : Day
wednesday : Day
thursday : Day
friday : Day
saturday : Day
sunday : Day
\end{code}
The type is called `day`, and its members are `monday`,
`tuesday`, etc. The second and following lines of the definition
can be read "`monday` is a `day`, `tuesday` is a `day`, etc."
Having defined `day`, we can write functions that operate on
days.
\begin{code}
nextWeekday : Day -> Day
nextWeekday monday = tuesday
nextWeekday tuesday = wednesday
nextWeekday wednesday = thursday
nextWeekday thursday = friday
nextWeekday friday = monday
nextWeekday saturday = monday
nextWeekday sunday = monday
\end{code}
One thing to note is that the argument and return types of
this function are explicitly declared. Like most functional
programming languages, Agda can often figure out these types for
itself when they are not given explicitly -- i.e., it performs
_type inference_ -- but we'll include them to make reading
easier.
Having defined a function, we should check that it works on
some examples. There are actually three different ways to do this
in Agda.
First, we can use the Emacs command `C-c C-n` to evaluate a
compound expression involving `nextWeekday`. For instance, `nextWeekday
friday` should evaluate to `monday`. If you have a computer handy, this
would be an excellent moment to fire up Agda and try this for yourself.
Load this file, `Basics.lagda`, load it using `C-c C-l`, submit the
above example to Agda, and observe the result.
Second, we can record what we _expect_ the result to be in the
form of an Agda type:
\begin{code}
test-nextWeekday : nextWeekday (nextWeekday saturday) ≡ tuesday
\end{code}
This declaration does two things: it makes an assertion (that the second
weekday after `saturday` is `tuesday`), and it gives the assertion a name
that can be used to refer to it later.
Having made the assertion, we must also verify it. We do this by giving
a term of the above type:
\begin{code}
test-nextWeekday = refl
\end{code}
There is no essential difference between the definition for
`test-nextWeekday` here and the definition for `nextWeekday` above,
except for the new symbol for equality `≡` and the constructor `refl`.
The details of these are not important for now (we'll come back to them in
a bit), but essentially `refl` can be read as "The assertion we've made
can be proved by observing that both sides of the equality evaluate to the
same thing, after some simplification."
Third, we can ask Agda to _compile_ some program involving our definition,
This facility is very interesting, since it gives us a way to construct
_fully certified_ programs. We'll come back to this topic in later chapters.

View file

@ -1,99 +0,0 @@
---
title : "Basics: Functional Programming in Agda"
layout : page
permalink : /Basics
---
\begin{code}
open import Data.Empty using (⊥; ⊥-elim)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Binary.PropositionalEquality
using (_≡_; refl; _≢_; trans; sym)
\end{code}
# Natural numbers
\begin{code}
data : Set where
zero :
suc :
{-# BUILTIN NATURAL #-}
\end{code}
\begin{code}
congruent : ∀ {m n} → m ≡ n → suc m ≡ suc n
congruent refl = refl
injective : ∀ {m n} → suc m ≡ suc n → m ≡ n
injective refl = refl
distinct : ∀ {m} → zero ≢ suc m
distinct ()
\end{code}
\begin{code}
_≟_ : ∀ (m n : ) → Dec (m ≡ n)
zero ≟ zero = yes refl
zero ≟ suc n = no (λ())
suc m ≟ zero = no (λ())
suc m ≟ suc n with m ≟ n
... | yes refl = yes refl
... | no p = no (λ r → p (injective r))
\end{code}
# Addition and its properties
\begin{code}
_+_ :
zero + n = n
suc m + n = suc (m + n)
\end{code}
\begin{code}
+-assoc : ∀ m n p → (m + n) + p ≡ m + (n + p)
+-assoc zero n p = refl
+-assoc (suc m) n p rewrite +-assoc m n p = refl
+-zero : ∀ m → m + zero ≡ m
+-zero zero = refl
+-zero (suc m) rewrite +-zero m = refl
+-suc : ∀ m n → m + (suc n) ≡ suc (m + n)
+-suc zero n = refl
+-suc (suc m) n rewrite +-suc m n = refl
+-comm : ∀ m n → m + n ≡ n + m
+-comm m zero = +-zero m
+-comm m (suc n) rewrite +-suc m n | +-comm m n = refl
\end{code}
# Equality and decidable equality for naturals
# Showing `double` injective
\begin{code}
double :
double zero = zero
double (suc n) = suc (suc (double n))
\end{code}
\begin{code}
double-injective : ∀ m n → double m ≡ double n → m ≡ n
double-injective zero zero refl = refl
double-injective zero (suc n) ()
double-injective (suc m) zero ()
double-injective (suc m) (suc n) r =
congruent (double-injective m n (injective (injective r)))
\end{code}
In Coq, the inductive proof for `double-injective`
is sensitive to how one inducts on `m` and `n`. In Agda, that aspect
is straightforward. However, Agda requires helper functions for
injection and congruence which are not required in Coq.
I can remove the use of `congruent` by rewriting with its argument.
Is there an easy way to remove the two uses of `injective`?

View file

@ -1,122 +0,0 @@
\begin{code}
module CPP where
open import Data.List hiding ([_])
open import Function
data Type : Set where
base : Type
arr : Type → Type → Type
Cx' = List Type
Model' = Type → Cx' → Set
infixr 8 _⇒_
_⇒_ : (Cx' → Set) → (Cx' → Set) → Cx' → Set
(f ⇒ g) Γ = f Γ → g Γ
[_]' : (Cx' → Set) → Set
[ P ]' = ∀ {x} → P x
infix 9 _⊢_
_⊢_ : Type → (Cx' → Set) → Cx' → Set
(σ ⊢ T) Γ = T (σ ∷ Γ)
data Var : Model' where
ze : ∀ {σ} → [ σ ⊢ Var σ ]'
su : ∀ {σ τ} → [ Var σ ⇒ τ ⊢ Var σ ]'
□ : (Cx' → Set) → (Cx' → Set)
□ P Γ = ∀ {Δ} → (∀ {σ} → Var σ Γ → Var σ Δ) → P Δ
data Tm : Model' where
`var : ∀ {σ} → [ Var σ ⇒ Tm σ ]'
_`$_ : ∀ {σ τ} → [ Tm (arr σ τ) ⇒ Tm σ ⇒ Tm τ ]'
`λ : ∀ {σ τ} → [ σ ⊢ Tm τ ⇒ Tm (arr σ τ) ]'
\end{code}
%<*ren>
\begin{code}
ren : {Γ Δ : List Type} → (∀ {σ} → Var σ Γ → Var σ Δ) → (∀ {σ} → Tm σ Γ → Tm σ Δ)
ren ρ (`var v) = `var (ρ v)
ren ρ (f `$ t) = ren ρ f `$ ren ρ t
ren ρ (`λ b) = `λ (ren ((su ∘ ρ) -, ze) b)
\end{code}
%</ren>
\begin{code}
where
_-,_ : ∀ {Γ σ Δ} → (∀ {τ} → Var τ Γ → Var τ Δ) → Var σ Δ → ∀ {τ} → Var τ (σ ∷ Γ) → Var τ Δ
(ρ -, v) ze = v
(ρ -, v) (su k) = ρ k
\end{code}
%<*sub>
\begin{code}
sub : {Γ Δ : List Type} → (∀ {σ} → Var σ Γ → Tm σ Δ) → (∀ {σ} → Tm σ Γ → Tm σ Δ)
sub ρ (`var v) = ρ v
sub ρ (f `$ t) = sub ρ f `$ sub ρ t
sub ρ (`λ b) = `λ (sub ((ren su ∘ ρ) -, `var ze) b)
\end{code}
%</sub>
\begin{code}
where
_-,_ : ∀ {Γ σ Δ} → (∀ {τ} → Var τ Γ → Tm τ Δ) → Tm σ Δ → ∀ {τ} → Var τ (σ ∷ Γ) → Tm τ Δ
(ρ -, v) ze = v
(ρ -, v) (su k) = ρ k
record Kit (◆ : Model') : Set where
field
var : ∀ {σ} → [ ◆ σ ⇒ Tm σ ]'
zro : ∀ {σ} → [ σ ⊢ ◆ σ ]'
wkn : ∀ {σ τ} → [ ◆ τ ⇒ σ ⊢ ◆ τ ]'
module kitkit {◆ : Model'} (κ : Kit ◆) where
\end{code}
%<*kit>
\begin{code}
kit : {Γ Δ : List Type} → (∀ {σ} → Var σ Γ → ◆ σ Δ) → (∀ {σ} → Tm σ Γ → Tm σ Δ)
kit ρ (`var v) = Kit.var κ (ρ v)
kit ρ (f `$ t) = kit ρ f `$ kit ρ t
kit ρ (`λ b) = `λ (kit ((Kit.wkn κ ∘ ρ) -, Kit.zro κ) b)
\end{code}
%</kit>
\begin{code}
where
_-,_ : ∀ {Γ σ Δ} → (∀ {τ} → Var τ Γ → ◆ τ Δ) → ◆ σ Δ → ∀ {τ} → Var τ (σ ∷ Γ) → ◆ τ Δ
(ρ -, v) ze = v
(ρ -, v) (su k) = ρ k
Val : Model'
Val base Γ = Tm base Γ
Val (arr σ τ) Γ = ∀ {Δ} → (∀ {ν} → Var ν Γ → Var ν Δ) → Val σ Δ → Val τ Δ
wk : ∀ {Γ Δ} → (∀ {σ} → Var σ Γ → Var σ Δ) → ∀ {σ} → Val σ Γ → Val σ Δ
wk ρ {base} v = ren ρ v
wk ρ {arr σ τ} v = λ ρ → v (ρρ)
APP : ∀ {σ τ Γ} → Val (arr σ τ) Γ → Val σ Γ → Val τ Γ
APP f t = f id t
LAM : ∀ {Γ σ τ} → Val (arr σ τ) Γ → Val (arr σ τ) Γ
LAM = id
\end{code}
%<*nbe>
\begin{code}
nbe : {Γ Δ : List Type} → (∀ {σ} → Var σ Γ → Val σ Δ) → (∀ {σ} → Tm σ Γ → Val σ Δ)
nbe ρ (`var v) = ρ v
nbe ρ (f `$ t) = APP (nbe ρ f) (nbe ρ t)
nbe ρ (`λ t) = LAM (λ re v → nbe ((wk re ∘ ρ) -, v) t)
\end{code}
%</nbe>
\begin{code}
where
_-,_ : ∀ {Γ σ Δ} → (∀ {τ} → Var τ Γ → Val τ Δ) → Val σ Δ → ∀ {τ} → Var τ (σ ∷ Γ) → Val τ Δ
(ρ -, v) ze = v
(ρ -, v) (su k) = ρ k
\end{code}

View file

@ -1,76 +0,0 @@
The reflexive and transitive closure `↠` of an arbitrary relation `↦`
is the smallest relation that includes `↦` and is also reflexive
and transitive. We could define this directly, as follows.
\begin{code}
module Closure (A : Set) (_↦_ : A → A → Set) where
data _↠_ : A → A → Set where
refl : ∀ {M}
--------
→ M ↠ M
trans : ∀ {L M N}
→ L ↠ M
→ M ↠ N
--------
→ L ↠ N
inc : ∀ {M N}
→ M ↦ N
--------
→ M ↠ N
\end{code}
Here we use a module to define the reflexive and transitive
closure of an arbitrary relation.
The three clauses specify that `↠` is reflexive and transitive,
and that `↦` implies `↠`.
However, it will prove more convenient to define the transitive
closure as a sequence of zero or more steps of the underlying
relation, along lines similar to that for reasoning about
chains of equalities
Chapter [Equality]({{ site.baseurl }}{% link out/plta/Equality.md %}).
\begin{code}
module Chain (A : Set) (_↦_ : A → A → Set) where
infix 2 _↠_
infix 1 begin_
infixr 2 _↦⟨_⟩_
infix 3 _∎
data _↠_ : A → A → 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
\end{code}
We can read this as follows.
* From term `M`, we can take no steps,
giving a step of type `M ↠ M`.
It is written `M ∎`.
* From term `L` we can take a single of type `L ↦ M`
followed by zero or more steps of type `M ↠ N`,
giving a step of type `L ↠ N`,
It is written `L ⟨ L↦M ⟩ M↠N`,
where `L↦M` and `M↠N` are steps of the appropriate type.
The notation is chosen to allow us to lay
out example reductions in an appealing way,
as we will see in the next section.
We then instantiate the second module to our specific notion
of reduction step.
\begin{code}
open Chain (Term) (_↦_)
\end{code}

View file

@ -1,186 +0,0 @@
---
title : "Collections: Representing collections as lists"
layout : page
permalink : /Collections
---
This chapter presents operations on collections and a number of
useful operations on them.
## Imports
\begin{code}
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; _≢_; refl; sym; trans; cong)
open Eq.≡-Reasoning
open import Data.Nat using (; zero; suc; _+_; _*_; _∸_; _≤_; s≤s; z≤n)
-- open import Data.Nat.Properties using
-- (+-assoc; +-identityˡ; +-identityʳ; *-assoc; *-identityˡ; *-identityʳ)
open import Relation.Nullary using (¬_)
open import Data.Product using (_×_; proj₁; proj₂) renaming (_,_ to ⟨_,_⟩)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Data.Empty using (⊥; ⊥-elim)
open import Isomorphism using (_≃_)
open import Function using (_∘_)
open import Level using (Level)
open import Data.List using (List; []; _∷_; _++_; map; foldr; filter)
open import Data.List.All using (All; []; _∷_)
open import Data.List.Any using (Any; here; there)
open import Data.Maybe using (Maybe; just; nothing)
-- open import Data.List.Any.Membership.Propositional using (_∈_)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Negation using (contraposition; ¬?)
open import Relation.Nullary.Product using (_×-dec_)
-- open import Relation.Binary using (IsEquivalence)
\end{code}
## Collections
\begin{code}
infix 0 _↔_
_↔_ : Set → Set → Set
A ↔ B = (A → B) × (B → A)
module CollectionDec (A : Set) (_≟_ : ∀ (x y : A) → Dec (x ≡ y)) where
Coll : Set → Set
Coll A = List A
[_] : A → Coll A
[ x ] = x ∷ []
infix 4 _∈_
infix 4 _⊆_
infixl 5 __
infixl 5 _\\_
data _∈_ : A → Coll A → Set where
here : ∀ {x xs} →
----------
x ∈ x ∷ xs
there : ∀ {w x xs} →
w ∈ xs →
----------
w ∈ x ∷ xs
_⊆_ : Coll A → Coll A → Set
xs ⊆ ys = ∀ {w} → w ∈ xs → w ∈ ys
__ : Coll A → Coll A → Coll A
__ = _++_
_\\_ : Coll A → A → Coll A
xs \\ x = filter (¬? ∘ (_≟ x)) xs
refl-⊆ : ∀ {xs} → xs ⊆ xs
refl-⊆ ∈xs = ∈xs
trans-⊆ : ∀ {xs ys zs} → xs ⊆ ys → ys ⊆ zs → xs ⊆ zs
trans-⊆ xs⊆ ys⊆ = ys⊆ ∘ xs⊆
lemma-[_] : ∀ {w xs} → w ∈ xs ↔ [ w ] ⊆ xs
lemma-[_] = ⟨ forward , backward ⟩
where
forward : ∀ {w xs} → w ∈ xs → [ w ] ⊆ xs
forward ∈xs here = ∈xs
forward ∈xs (there ())
backward : ∀ {w xs} → [ w ] ⊆ xs → w ∈ xs
backward ⊆xs = ⊆xs here
lemma-\\-∈-≢ : ∀ {w x xs} → w ∈ xs \\ x ↔ w ∈ xs × w ≢ x
lemma-\\-∈-≢ = ⟨ forward , backward ⟩
where
next : ∀ {w x y xs} → w ∈ xs × w ≢ x → w ∈ y ∷ xs × w ≢ x
next ⟨ w∈ , w≢ ⟩ = ⟨ there w∈ , w≢ ⟩
forward : ∀ {w x xs} → w ∈ xs \\ x → w ∈ xs × w ≢ x
forward {_} {x} {[]} ()
forward {_} {x} {y ∷ _} w∈ with y ≟ x
forward {_} {x} {y ∷ _} w∈ | yes refl = next (forward w∈)
forward {_} {x} {y ∷ _} here | no y≢ = ⟨ here , (λ y≡ → y≢ y≡) ⟩
forward {_} {x} {y ∷ _} (there w∈) | no _ = next (forward w∈)
backward : ∀ {w x xs} → w ∈ xs × w ≢ x → w ∈ xs \\ x
backward {_} {x} {y ∷ _} ⟨ here , w≢ ⟩
with y ≟ x
... | yes refl = ⊥-elim (w≢ refl)
... | no _ = here
backward {_} {x} {y ∷ _} ⟨ there w∈ , w≢ ⟩
with y ≟ x
... | yes refl = backward ⟨ w∈ , w≢ ⟩
... | no _ = there (backward ⟨ w∈ , w≢ ⟩)
lemma-\\-∷ : ∀ {x xs ys} → xs \\ x ⊆ ys ↔ xs ⊆ x ∷ ys
lemma-\\-∷ = ⟨ forward , backward ⟩
where
forward : ∀ {x xs ys} → xs \\ x ⊆ ys → xs ⊆ x ∷ ys
forward {x} ⊆ys {w} ∈xs
with w ≟ x
... | yes refl = here
... | no ≢x = there (⊆ys (proj₂ lemma-\\-∈-≢ ⟨ ∈xs , ≢x ⟩))
backward : ∀ {x xs ys} → xs ⊆ x ∷ ys → xs \\ x ⊆ ys
backward {x} xs⊆ {w} w∈
with proj₁ lemma-\\-∈-≢ w∈
... | ⟨ ∈xs , ≢x ⟩ with w ≟ x
... | yes refl = ⊥-elim (≢x refl)
... | no w≢ with (xs⊆ ∈xs)
... | here = ⊥-elim (≢x refl)
... | there ∈ys = ∈ys
lemma-∪₁ : ∀ {xs ys} → xs ⊆ xs ys
lemma-∪₁ here = here
lemma-∪₁ (there ∈xs) = there (lemma-∪₁ ∈xs)
lemma-∪₂ : ∀ {xs ys} → ys ⊆ xs ys
lemma-∪₂ {[]} ∈ys = ∈ys
lemma-∪₂ {x ∷ xs} ∈ys = there (lemma-∪₂ {xs} ∈ys)
lemma-⊎- : ∀ {w xs ys} → w ∈ xs ⊎ w ∈ ys ↔ w ∈ xs ys
lemma-⊎- = ⟨ forward , backward ⟩
where
forward : ∀ {w xs ys} → w ∈ xs ⊎ w ∈ ys → w ∈ xs ys
forward (inj₁ ∈xs) = lemma-∪₁ ∈xs
forward (inj₂ ∈ys) = lemma-∪₂ ∈ys
backward : ∀ {xs ys w} → w ∈ xs ys → w ∈ xs ⊎ w ∈ ys
backward {[]} ∈ys = inj₂ ∈ys
backward {x ∷ xs} here = inj₁ here
backward {x ∷ xs} (there w∈) with backward {xs} w∈
... | inj₁ ∈xs = inj₁ (there ∈xs)
... | inj₂ ∈ys = inj₂ ∈ys
\end{code}
## Standard Library
Definitions similar to those in this chapter can be found in the standard library.
\begin{code}
-- EDIT
\end{code}
The standard library version of `IsMonoid` differs from the
one given here, in that it is also parameterised on an equivalence relation.
## Unicode
This chapter uses the following unicode.
EDIT
∷ U+2237 PROPORTION (\::)
⊗ U+2297 CIRCLED TIMES (\otimes)
∈ U+2208 ELEMENT OF (\in)
∉ U+2209 NOT AN ELEMENT OF (\inn)

View file

@ -1,162 +0,0 @@
---
title : "Collections: Collections represented as Lists"
layout : page
permalink : /Collections
---
This chapter presents operations on collections and a number of
useful operations on them.
## Imports
\begin{code}
-- import Relation.Binary.PropositionalEquality as Eq
-- open Eq using (_≡_; refl; sym; trans; cong)
-- open Eq.≡-Reasoning
open import Data.Nat using (; zero; suc; _+_; _*_; _∸_; _≤_; s≤s; z≤n)
-- open import Data.Nat.Properties using
-- (+-assoc; +-identityˡ; +-identityʳ; *-assoc; *-identityˡ; *-identityʳ)
open import Relation.Nullary using (¬_)
open import Data.Product using (_×_) renaming (_,_ to ⟨_,_⟩)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Isomorphism using (_≃_)
open import Function using (_∘_)
open import Level using (Level)
open import Data.List using (List; []; _∷_; _++_; map; foldr; filter)
open import Data.List.All using (All; []; _∷_)
open import Data.List.Any using (Any; here; there)
open import Data.Maybe using (Maybe; just; nothing)
-- open import Data.List.Any.Membership.Propositional using (_∈_)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Negation using (contraposition; ¬?)
open import Relation.Nullary.Product using (_×-dec_)
open import Relation.Binary using (IsEquivalence)
\end{code}
## Collections
\begin{code}
infix 0 _↔_
_↔_ : Set → Set → Set
A ↔ B = (A → B) × (B → A)
module Collection
(A : Set)
(_≈_ : A → A → Set)
(isEquivalence : IsEquivalence _≈_)
where
open IsEquivalence isEquivalence
abstract
Coll : Set → Set
Coll A = List A
\end{code}
Collections support the same abbreviations as lists for writing
collections with a small number of elements.
\begin{code}
[_] : A → Coll A
[ x ] = x ∷ []
\end{code}
\begin{code}
infix 4 _∈_
infix 4 _⊆_
infix 5 __
_∈_ : A → Coll A → Set
w ∈ xs = Any (w ≈_) xs
_⊆_ : Coll A → Coll A → Set
xs ⊆ ys = ∀ {w} → w ∈ xs → w ∈ ys
__ : Coll A → Coll A → Coll A
__ = _++_
preserves : ∀ {u v xs} → u ≈ v → u ∈ xs → v ∈ xs
preserves u≈v (here u≈) = here (trans (sym u≈v) u≈)
preserves u≈v (there u∈) = there (preserves u≈v u∈)
⊆-refl : ∀ {xs} → xs ⊆ xs
⊆-refl ∈xs = ∈xs
⊆-trans : ∀ {xs ys zs} → xs ⊆ ys → ys ⊆ zs → xs ⊆ zs
⊆-trans xs⊆ ys⊆ = ys⊆ ∘ xs⊆
lemma₁ : ∀ {w xs} → w ∈ xs ↔ [ w ] ⊆ xs
lemma₁ = ⟨ forward , backward ⟩
where
forward : ∀ {w xs} → w ∈ xs → [ w ] ⊆ xs
forward ∈xs (here w≈) = preserves (sym w≈) ∈xs -- ∈xs
forward ∈xs (there ())
backward : ∀ {w xs} → [ w ] ⊆ xs → w ∈ xs
backward ⊆xs = ⊆xs (here refl)
lemma₂ : ∀ {xs ys} → xs ⊆ xs ys
lemma₂ (here w≈) = here w≈
lemma₂ (there ∈xs) = there (lemma₂ ∈xs)
lemma₃ : ∀ {xs ys} → ys ⊆ xs ys
lemma₃ {[]} ∈ys = ∈ys
lemma₃ {x ∷ xs} ∈ys = there (lemma₃ {xs} ∈ys)
lemma₄ : ∀ {w xs ys} → w ∈ xs ⊎ w ∈ ys ↔ w ∈ xs ys
lemma₄ = ⟨ forward , backward ⟩
where
forward : ∀ {w xs ys} → w ∈ xs ⊎ w ∈ ys → w ∈ xs ys
forward (inj₁ ∈xs) = lemma₂ ∈xs
forward (inj₂ ∈ys) = lemma₃ ∈ys
backward : ∀ {xs ys w} → w ∈ xs ys → w ∈ xs ⊎ w ∈ ys
backward {[]} ∈ys = inj₂ ∈ys
backward {x ∷ xs} (here w≈) = inj₁ (here w≈)
backward {x ∷ xs} (there w∈) with backward {xs} w∈
... | inj₁ ∈xs = inj₁ (there ∈xs)
... | inj₂ ∈ys = inj₂ ∈ys
\end{code}
# Operations with decidable equivalence
\begin{code}
module DecCollection (_≟_ : ∀ (x y : A) → Dec (x ≈ y)) where
abstract
infix 5 _\\_
_\\_ : Coll A → A → Coll A
xs \\ x = filter (¬? ∘ (x ≟_)) xs
\end{code}
## Standard Library
Definitions similar to those in this chapter can be found in the standard library.
\begin{code}
-- EDIT
\end{code}
The standard library version of `IsMonoid` differs from the
one given here, in that it is also parameterised on an equivalence relation.
## Unicode
This chapter uses the following unicode.
EDIT
∷ U+2237 PROPORTION (\::)
⊗ U+2297 CIRCLED TIMES (\otimes)
∈ U+2208 ELEMENT OF (\in)
∉ U+2209 NOT AN ELEMENT OF (\inn)

View file

@ -1,215 +0,0 @@
-- Author: David Darais
--
-- This is a dependent de Bruijn encoding of STLC with proofs for
-- progress and preservation. This file has zero dependencies and is
-- 100% self-contained.
--
-- Because there is only a notion of well-typed terms (non-well-typed
-- terms do not exist), preservation is merely by observation that
-- substitution (i.e., cut) can be defined.
--
-- A small-step evaluation semantics is defined after the definition of cut.
--
-- Progress is proved w.r.t. the evaluation semantics.
--
-- Some ideas for extensions or homeworks are given at the end.
--
-- A few helper definitions are required.
-- * Basic Agda constructions (like booleans, products, dependent sums,
-- and lists) are defined first in a Prelude module which is
-- immediately opened.
-- * Binders (x : τ ∈ Γ) are proofs that the element τ is contained in
-- the list of types Γ. Helper functions for weakening and
-- introducing variables into contexts which are reusable are
-- defined in the Prelude. Helpers for weakening terms are defined
-- below. Some of the non-general helpers (like cut[∈]) could be
-- defined in a generic way to be reusable, but I decided against
-- this to keep things simple.
module Darais where
open import Agda.Primitive using (_⊔_)
module Prelude where
infixr 3 ∃𝑠𝑡
infixl 5 __
infix 10 _∈_
infixl 15 _⧺_
infixl 15 _⊟_
infixl 15 _∾_
infixr 20 _∷_
data 𝔹 : Set where
T : 𝔹
F : 𝔹
data __ {ℓ₁ ℓ₂} (A : Set ℓ₁) (B : Set ℓ₂) : Set (ℓ₁ ℓ₂) where
Inl : A A B
Inr : B A B
syntax ∃𝑠𝑡 A (λ x B) = x A 𝑠𝑡 B
data ∃𝑠𝑡 {ℓ₁ ℓ₂} (A : Set ℓ₁) (B : A Set ℓ₂) : Set (ℓ₁ ℓ₂) where
⟨∃_,_⟩ : (x : A) B x x A 𝑠𝑡 B x
data ⟬_⟭ {} (A : Set ) : Set where
[] : A
_∷_ : A A A
_⧺_ : {} {A : Set } A A A
[] ys = ys
x xs ys = x (xs ys)
_∾_ : {} {A : Set } A A A
[] ys = ys
(x xs) ys = xs x ys
data _∈_ {} {A : Set } (x : A) : (xs : A ) Set where
Z : {xs} x x xs
S : {x xs} x xs x x xs
_⊟_ : {} {A : Set } (xs : A ) {x} x xs A
x xs Z = xs
x xs S ε = x (xs ε)
wk[∈] : {} {A : Set } {xs : A } {x : A} xs x xs x xs xs
wk[∈] [] x = x
wk[∈] (x xs) x = wk[∈] xs (S x)
i[∈][_] : {} {A : Set } {xs : A } {x x : A} (ε′ : x xs) x xs ε′ x xs
i[∈][ Z ] x = S x
i[∈][ S ε′ ] Z = Z
i[∈][ S ε′ ] (S x) = S (i[∈][ ε′ ] x)
open Prelude
-- ============================ --
-- Simply Typed Lambda Calculus --
-- ============================ --
-- A dependent de Bruijn encoding
-- Or, the dynamic semantics of natural deduction as seen through Curry-Howard
-- types --
data type : Set where
⟨𝔹⟩ : type
_⟨→⟩_ : type type type
-- terms --
infix 10 _⊢_
data _⊢_ : (Γ : type ) (τ : type) Set where
⟨𝔹⟩ : {Γ}
(b : 𝔹)
Γ ⟨𝔹⟩
⟨if⟩___ : {Γ τ}
(e₁ : Γ ⟨𝔹⟩)
(e₂ : Γ τ)
(e₃ : Γ τ)
Γ τ
Var : {Γ τ}
(x : τ Γ)
Γ τ
⟨λ⟩ : {Γ τ₁ τ₂}
(e : τ₁ Γ τ₂)
Γ τ₁ ⟨→⟩ τ₂
_⟨⋅⟩_ : {Γ τ₁ τ₂}
(e₁ : Γ τ₁ ⟨→⟩ τ₂)
(e₂ : Γ τ₁)
Γ τ₂
-- introducing a new variable to the context --
i[⊢][_] : {Γ τ τ′} (x : τ′ Γ) Γ x τ Γ τ
i[⊢][ x ] (⟨𝔹⟩ b) = ⟨𝔹⟩ b
i[⊢][ x ] ⟨if⟩ e₁ e₂ e₃ = ⟨if⟩ i[⊢][ x ] e₁ i[⊢][ x ] e₂ i[⊢][ x ] e₃
i[⊢][ x ] (Var x) = Var (i[∈][ x ] x)
i[⊢][ x ] (⟨λ⟩ e) = ⟨λ⟩ (i[⊢][ S x ] e)
i[⊢][ x ] (e₁ ⟨⋅⟩ e₂) = i[⊢][ x ] e₁ ⟨⋅⟩ i[⊢][ x ] e₂
i[⊢] : {Γ τ τ′} Γ τ τ′ Γ τ
i[⊢] = i[⊢][ Z ]
-- substitution for variables --
cut[∈]<_>[_] : {Γ τ₁ τ₂} (x : τ₁ Γ) Γ′ Γ′ (Γ x) τ₁ τ₂ Γ Γ′ (Γ x) τ₂
cut[∈]< Z >[ Γ′ ] e Z = e
cut[∈]< Z >[ Γ′ ] e (S y) = Var (wk[∈] Γ′ y)
cut[∈]< S x >[ Γ′ ] e Z = Var (wk[∈] Γ′ Z)
cut[∈]< S x >[ Γ′ ] e (S x) = cut[∈]< x >[ _ Γ′ ] e x
cut[∈]<_> : {Γ τ₁ τ₂} (x : τ₁ Γ) Γ x τ₁ τ₂ Γ Γ x τ₂
cut[∈]< x > = cut[∈]< x >[ [] ]
-- substitution for terms --
cut[⊢][_] : {Γ τ₁ τ₂} (x : τ₁ Γ) Γ x τ₁ Γ τ₂ Γ x τ₂
cut[⊢][ x ] e (⟨𝔹⟩ b) = ⟨𝔹⟩ b
cut[⊢][ x ] e ⟨if⟩ e₁ e₂ e₃ = ⟨if⟩ cut[⊢][ x ] e e₁ cut[⊢][ x ] e e₂ cut[⊢][ x ] e e₃
cut[⊢][ x ] e (Var x) = cut[∈]< x > e x
cut[⊢][ x ] e (⟨λ⟩ e) = ⟨λ⟩ (cut[⊢][ S x ] (i[⊢] e) e)
cut[⊢][ x ] e (e₁ ⟨⋅⟩ e₂) = cut[⊢][ x ] e e₁ ⟨⋅⟩ cut[⊢][ x ] e e₂
cut[⊢] : {Γ τ₁ τ₂} Γ τ₁ τ₁ Γ τ₂ Γ τ₂
cut[⊢] = cut[⊢][ Z ]
-- values --
data value {Γ} : {τ} Γ τ Set where
⟨𝔹⟩ : b value (⟨𝔹⟩ b)
⟨λ⟩ : {τ τ′} (e : τ′ Γ τ) value (⟨λ⟩ e)
-- CBV evaluation for terms --
-- (borrowing some notation and style from Wadler: https://wenkokke.github.io/sf/Stlc)
infix 10 _↝_
data _↝_ {Γ τ} : Γ τ Γ τ Set where
ξ⋅₁ : {τ′} {e₁ e₁ : Γ τ′ ⟨→⟩ τ} {e₂ : Γ τ′}
e₁ e₁
e₁ ⟨⋅⟩ e₂ e₁ ⟨⋅⟩ e₂
ξ⋅₂ : {τ′} {e₁ : Γ τ′ ⟨→⟩ τ} {e₂ e₂ : Γ τ′}
value e₁
e₂ e₂
e₁ ⟨⋅⟩ e₂ e₁ ⟨⋅⟩ e₂
βλ : {τ′} {e₁ : τ′ Γ τ} {e₂ : Γ τ′}
value e₂
⟨λ⟩ e₁ ⟨⋅⟩ e₂ cut[⊢] e₂ e₁
ξif : {e₁ e₁ : Γ ⟨𝔹⟩} {e₂ e₃ : Γ τ}
e₁ e₁
⟨if⟩ e₁ e₂ e₃ ⟨if⟩ e₁ e₂ e₃
ξif-T : {e₂ e₃ : Γ τ}
⟨if⟩ ⟨𝔹⟩ T e₂ e₃ e₂
ξif-F : {e₂ e₃ : Γ τ}
⟨if⟩ ⟨𝔹⟩ F e₂ e₃ e₃
-- progress --
progress : {τ} (e : [] τ) value e ( e [] τ 𝑠𝑡 e e)
progress (⟨𝔹⟩ b) = Inl (⟨𝔹⟩ b)
progress ⟨if⟩ e e₁ e₂ with progress e
| Inl (⟨𝔹⟩ T) = Inr ⟨∃ e₁ , ξif-T
| Inl (⟨𝔹⟩ F) = Inr ⟨∃ e₂ , ξif-F
| Inr ⟨∃ e , ε = Inr ⟨∃ ⟨if⟩ e e₁ e₂ , ξif ε
progress (Var ())
progress (⟨λ⟩ e) = Inl (⟨λ⟩ e)
progress (e₁ ⟨⋅⟩ e₂) with progress e₁
| Inr ⟨∃ e₁ , ε = Inr ⟨∃ e₁ ⟨⋅⟩ e₂ , ξ⋅₁ ε
| Inl (⟨λ⟩ e) with progress e₂
| Inl x = Inr ⟨∃ cut[⊢] e₂ e , βλ x
| Inr ⟨∃ e₂ , ε = Inr ⟨∃ e₁ ⟨⋅⟩ e₂ , ξ⋅₂ (⟨λ⟩ e) ε
-- Some ideas for possible extensions or homework assignments
-- 1. A. Write a conversion from the dependent de Bruijn encoding (e : Γ ⊢ τ)
-- to the untyped lambda calculus (e : term).
-- B. Prove that the image of this conversion is well typed.
-- C. Write a conversion from well-typed untyped lambda calculus
-- terms ([e : term] and [ε : (Γ ⊢ e ⦂ τ)] into the dependent de
-- Bruijn encoding (e : Γ ⊢ τ)
-- 2. A. Write a predicate analogous to 'value' for strongly reduced
-- terms (reduction under lambda)
-- B. Prove "strong" progress: A term is either fully beta-reduced
-- (including under lambda) or it can take a step
-- 3. Relate this semantics to a big-step semantics.
-- 4. Prove strong normalization.
-- 5. Relate this semantics to a definitional interpreter into Agda's Set.

View file

@ -1,90 +0,0 @@
module DaraisPhoas where
open import Agda.Primitive using (_⊔_)
module Prelude where
infixr 3 ∃𝑠𝑡
infixl 5 __
infixr 20 _∷_
data 𝔹 : Set where
T : 𝔹
F : 𝔹
data __ {ℓ₁ ℓ₂} (A : Set ℓ₁) (B : Set ℓ₂) : Set (ℓ₁ ℓ₂) where
Inl : A A B
Inr : B A B
syntax ∃𝑠𝑡 A (λ x B) = x A 𝑠𝑡 B
data ∃𝑠𝑡 {ℓ₁ ℓ₂} (A : Set ℓ₁) (B : A Set ℓ₂) : Set (ℓ₁ ℓ₂) where
⟨∃_,_⟩ : (x : A) B x x A 𝑠𝑡 B x
data ⟬_⟭ {} (A : Set ) : Set where
[] : A
_∷_ : A A A
open Prelude
infixr 15 _⟨→⟩_
data type : Set where
⟨ℕ⟩ : type
_⟨→⟩_ : type type type
infixl 15 _⟨∙⟩_
data exp-phoas (var : type type Set) : (Γ : type ) (τ : type) Set where
Var : {Γ τ}
(x : var τ Γ)
exp-phoas var Γ τ
⟨λ⟩ : {Γ τ₁ τ₂}
(e : var τ₁ (τ₁ Γ) exp-phoas var (τ₁ Γ) τ₂)
exp-phoas var Γ (τ₁ ⟨→⟩ τ₂)
_⟨∙⟩_ : {Γ τ₁ τ₂}
(e₁ : exp-phoas var Γ (τ₁ ⟨→⟩ τ₂))
(e₂ : exp-phoas var Γ τ₁)
exp-phoas var Γ τ₂
infix 10 _∈_
data _∈_ {} {A : Set } (x : A) : (xs : A ) Set where
Z : {xs} x x xs
S : {x xs} x xs x x xs
infix 10 _⊢_
data _⊢_ : (Γ : type ) (τ : type) Set where
Var : {Γ τ}
(x : τ Γ)
Γ τ
⟨λ⟩ : {Γ τ₁ τ₂}
(e : τ₁ Γ τ₂)
Γ τ₁ ⟨→⟩ τ₂
_⟨∙⟩_ : {Γ τ₁ τ₂}
(e₁ : Γ τ₁ ⟨→⟩ τ₂)
(e₂ : Γ τ₁)
Γ τ₂
⟦_⟧₁ : {Γ τ} (e : exp-phoas _∈_ Γ τ) Γ τ
Var x ⟧₁ = Var x
⟨λ⟩ e ⟧₁ = ⟨λ⟩ e Z ⟧₁
e₁ ⟨∙⟩ e₂ ⟧₁ = e₁ ⟧₁ ⟨∙⟩ e₂ ⟧₁
⟦_⟧₂ : {Γ τ} (e : Γ τ) exp-phoas _∈_ Γ τ
Var x ⟧₂ = Var x
⟨λ⟩ e ⟧₂ = ⟨λ⟩ (λ _ e ⟧₂)
e₁ ⟨∙⟩ e₂ ⟧₂ = e₁ ⟧₂ ⟨∙⟩ e₂ ⟧₂
Ch : type
Ch = (⟨ℕ⟩ ⟨→⟩ ⟨ℕ⟩) ⟨→⟩ ⟨ℕ⟩ ⟨→⟩ ⟨ℕ⟩
twoDB : [] Ch
twoDB = ⟨λ⟩ (⟨λ⟩ (Var (S Z) ⟨∙⟩ (Var (S Z) ⟨∙⟩ Var Z)))
twoPH : exp-phoas _∈_ [] Ch
twoPH = ⟨λ⟩ (λ f ⟨λ⟩ (λ x Var f ⟨∙⟩ (Var f ⟨∙⟩ Var x)))
{-
/Users/wadler/sf/src/extra/DaraisPhoas.agda:82,9-60
⟨ℕ⟩ ⟨→⟩ ⟨ℕ⟩ != ⟨ℕ⟩ of type type
when checking that the expression
⟨λ⟩ (λ f ⟨λ⟩ (λ x Var f ⟨∙⟩ (Var f ⟨∙⟩ Var x))) has type
exp-phoas _∈_ [] Ch
-}

View file

@ -1,177 +0,0 @@
Many thanks to Nils and Roman.
Attached find an implementation along the lines sketched by Roman;
I found it after I sent my request and before Roman sent his helpful
reply.
One thing I note, in both Roman's code and mine, is that the code to
decide whether two contexts are equal is lengthy (_≟T_ and _≟_,
below). Is there a better way to do it? Does Agda offer an
equivalent of Haskell's derivable for equality?
Cheers, -- P
## Imports
\begin{code}
open import Relation.Binary.PropositionalEquality using (_≡_; refl)
open import Data.Nat using (; zero; suc; _+_; _∸_)
open import Data.Product using (_×_; proj₁; proj₂; ∃; ∃-syntax) renaming (_,_ to ⟨_,_⟩)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Decidable using (map)
open import Relation.Nullary.Negation using (contraposition)
open import Relation.Nullary.Product using (_×-dec_)
open import Data.Unit using (; tt)
open import Data.Empty using (⊥; ⊥-elim)
open import Function using (_∘_)
open import Function.Equivalence using (_⇔_; equivalence)
\end{code}
## Typed DeBruijn
\begin{code}
infixr 5 _⇒_
data Type : Set where
o : Type
_⇒_ : Type → Type → Type
data Env : Set where
ε : Env
_,_ : Env → Type → Env
data Var : Env → Type → Set where
Z : ∀ {Γ : Env} {A : Type} → Var (Γ , A) A
S : ∀ {Γ : Env} {A B : Type} → Var Γ B → Var (Γ , A) B
data Exp : Env → Type → Set where
var : ∀ {Γ : Env} {A : Type} → Var Γ A → Exp Γ A
abs : ∀ {Γ : Env} {A B : Type} → Exp (Γ , A) B → Exp Γ (A ⇒ B)
app : ∀ {Γ : Env} {A B : Type} → Exp Γ (A ⇒ B) → Exp Γ A → Exp Γ B
\end{code}
## Untyped DeBruijn
\begin{code}
data DB : Set where
var : → DB
abs : DB → DB
app : DB → DB → DB
\end{code}
# PHOAS
\begin{code}
data PH (X : Type → Set) : Type → Set where
var : ∀ {A : Type} → X A → PH X A
abs : ∀ {A B : Type} → (X A → PH X B) → PH X (A ⇒ B)
app : ∀ {A B : Type} → PH X (A ⇒ B) → PH X A → PH X B
\end{code}
# Convert PHOAS to DB
\begin{code}
PH→DB : ∀ {A} → (∀ {X} → PH X A) → DB
PH→DB M = h M 0
where
K : Type → Set
K A =
h : ∀ {A} → PH K A → → DB
h (var k) j = var (j ∸ (k + 1))
h (abs N) j = abs (h (N j) (j + 1))
h (app L M) j = app (h L j) (h M j)
\end{code}
# Test examples
\begin{code}
Church : Type
Church = (o ⇒ o) ⇒ o ⇒ o
twoExp : Exp ε Church
twoExp = (abs (abs (app (var (S Z)) (app (var (S Z)) (var Z)))))
twoPH : ∀ {X} → PH X Church
twoPH = (abs (λ f → (abs (λ x → (app (var f) (app (var f) (var x)))))))
twoDB : DB
twoDB = (abs (abs (app (var 1) (app (var 1) (var 0)))))
ex : PH→DB twoPH ≡ twoDB
ex = refl
\end{code}
## Decide whether environments and types are equal
\begin{code}
_≟T_ : ∀ (A B : Type) → Dec (A ≡ B)
o ≟T o = yes refl
o ≟T (A ⇒ B) = no (λ())
(A ⇒ B) ≟T o = no (λ())
(A ⇒ B) ≟T (A ⇒ B) = map (equivalence obv1 obv2) ((A ≟T A) ×-dec (B ≟T B))
where
obv1 : ∀ {A B A B : Type} → (A ≡ A) × (B ≡ B) → A ⇒ B ≡ A ⇒ B
obv1 ⟨ refl , refl ⟩ = refl
obv2 : ∀ {A B A B : Type} → A ⇒ B ≡ A ⇒ B → (A ≡ A) × (B ≡ B)
obv2 refl = ⟨ refl , refl ⟩
_≟_ : ∀ (Γ Δ : Env) → Dec (Γ ≡ Δ)
ε ≟ ε = yes refl
ε ≟ (Γ , A) = no (λ())
(Γ , A) ≟ ε = no (λ())
(Γ , A) ≟ (Δ , B) = map (equivalence obv1 obv2) ((Γ ≟ Δ) ×-dec (A ≟T B))
where
obv1 : ∀ {Γ Δ A B} → (Γ ≡ Δ) × (A ≡ B) → (Γ , A) ≡ (Δ , B)
obv1 ⟨ refl , refl ⟩ = refl
obv2 : ∀ {Γ Δ A B} → (Γ , A) ≡ (Δ , B) → (Γ ≡ Δ) × (A ≡ B)
obv2 refl = ⟨ refl , refl ⟩
\end{code}
## Convert Phoas to Exp
\begin{code}
compare : ∀ (A : Type) (Γ Δ : Env) → Var Δ A
compare A Γ Δ with (Γ , A) ≟ Δ
compare A Γ Δ | yes refl = Z
compare A Γ (Δ , B) | no _ = S (compare A Γ Δ)
compare A Γ ε | no _ = impossible
where
postulate
impossible : ∀ {A : Set} → A
PH→Exp : ∀ {A : Type} → (∀ {X} → PH X A) → Exp ε A
PH→Exp M = h M ε
where
K : Type → Set
K A = Env
h : ∀ {A} → PH K A → (Δ : Env) → Exp Δ A
h {A} (var Γ) Δ = var (compare A Γ Δ)
h {A ⇒ B} (abs N) Δ = abs (h (N Δ) (Δ , A))
h (app L M) Δ = app (h L Δ) (h M Δ)
ex₁ : PH→Exp twoPH ≡ twoExp
ex₁ = refl
\end{code}
## When one environment extends another
We could get rid of the use of `impossible` above if we could prove
that `Extends (Γ , A) Δ` in the `(var Γ)` case of the definition of `h`.
\begin{code}
data Extends : (Γ : Env) → (Δ : Env) → Set where
Z : ∀ {Γ : Env} → Extends Γ Γ
S : ∀ {A : Type} {Γ Δ : Env} → Extends Γ Δ → Extends Γ (Δ , A)
extract : ∀ {A : Type} {Γ Δ : Env} → Extends (Γ , A) Δ → Var Δ A
extract Z = Z
extract (S k) = S (extract k)
\end{code}

View file

@ -1,200 +0,0 @@
Many thanks to Nils and Roman.
Attached find an implementation along the lines sketched by Roman;
I found it after I sent my request and before Roman sent his helpful
reply.
One thing I note, in both Roman's code and mine, is that the code to
decide whether two contexts are equal is lengthy (_≟T_ and _≟_,
below). Is there a better way to do it? Does Agda offer an
equivalent of Haskell's derivable for equality?
Cheers, -- P
[Version using Ulf's prelude to derive equality]
## Imports
\begin{code}
open import Relation.Binary.PropositionalEquality using (_≡_; refl)
open import Data.Nat using (; zero; suc; _+_; _∸_)
open import Data.Product using (_×_; proj₁; proj₂; ∃; ∃-syntax) renaming (_,_ to ⟨_,_⟩)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Decidable using (map)
open import Relation.Nullary.Negation using (contraposition)
open import Relation.Nullary.Product using (_×-dec_)
open import Data.Unit using (; tt)
open import Data.Empty using (⊥; ⊥-elim)
open import Function using (_∘_)
open import Function.Equivalence using (_⇔_; equivalence)
\end{code}
## Typed DeBruijn
\begin{code}
infixr 5 _⇒_
data Type : Set where
o : Type
_⇒_ : Type → Type → Type
data Env : Set where
ε : Env
_,_ : Env → Type → Env
data Var : Env → Type → Set where
Z : ∀ {Γ : Env} {A : Type} → Var (Γ , A) A
S : ∀ {Γ : Env} {A B : Type} → Var Γ B → Var (Γ , A) B
data Exp : Env → Type → Set where
var : ∀ {Γ : Env} {A : Type} → Var Γ A → Exp Γ A
abs : ∀ {Γ : Env} {A B : Type} → Exp (Γ , A) B → Exp Γ (A ⇒ B)
app : ∀ {Γ : Env} {A B : Type} → Exp Γ (A ⇒ B) → Exp Γ A → Exp Γ B
\end{code}
## Untyped DeBruijn
\begin{code}
data DB : Set where
var : → DB
abs : DB → DB
app : DB → DB → DB
\end{code}
# PHOAS
\begin{code}
data PH (X : Type → Set) : Type → Set where
var : ∀ {A : Type} → X A → PH X A
abs : ∀ {A B : Type} → (X A → PH X B) → PH X (A ⇒ B)
app : ∀ {A B : Type} → PH X (A ⇒ B) → PH X A → PH X B
\end{code}
# Convert PHOAS to DB
\begin{code}
PH→DB : ∀ {A} → (∀ {X} → PH X A) → DB
PH→DB M = h M 0
where
K : Type → Set
K A =
h : ∀ {A} → PH K A → → DB
h (var k) j = var (j ∸ (k + 1))
h (abs N) j = abs (h (N j) (j + 1))
h (app L M) j = app (h L j) (h M j)
\end{code}
# Test examples
\begin{code}
Church : Type
Church = (o ⇒ o) ⇒ o ⇒ o
twoExp : Exp ε Church
twoExp = (abs (abs (app (var (S Z)) (app (var (S Z)) (var Z)))))
twoPH : ∀ {X} → PH X Church
twoPH = (abs (λ f → (abs (λ x → (app (var f) (app (var f) (var x)))))))
twoDB : DB
twoDB = (abs (abs (app (var 1) (app (var 1) (var 0)))))
ex : PH→DB twoPH ≡ twoDB
ex = refl
\end{code}
## Decide whether environments and types are equal
\begin{code}
-- These two imports are from agda-prelude (https://github.com/UlfNorell/agda-prelude)
open import Tactic.Deriving.Eq using (deriveEq)
import Prelude
instance
unquoteDecl EqType = deriveEq EqType (quote Type)
unquoteDecl EqEnv = deriveEq EqEnv (quote Env)
⊥To⊥ : Prelude.⊥ → ⊥
⊥To⊥ ()
decToDec : ∀ {a} {A : Set a} → Prelude.Dec A → Dec A
decToDec (Prelude.yes x) = yes x
decToDec (Prelude.no nx) = no (⊥To⊥ ∘ nx)
_≟T_ : ∀ (A B : Type) → Dec (A ≡ B)
A ≟T B = decToDec (A Prelude.== B)
_≟_ : ∀ (Γ Δ : Env) → Dec (Γ ≡ Δ)
Γ ≟ Δ = decToDec (Γ Prelude.== Δ)
\end{code}
[Old version, no longer needed]
_≟T_ : ∀ (A B : Type) → Dec (A ≡ B)
o ≟T o = yes refl
o ≟T (A ⇒ B) = no (λ())
(A ⇒ B) ≟T o = no (λ())
(A ⇒ B) ≟T (A ⇒ B) = map (equivalence obv1 obv2) ((A ≟T A) ×-dec (B ≟T B))
where
obv1 : ∀ {A B A B : Type} → (A ≡ A) × (B ≡ B) → A ⇒ B ≡ A ⇒ B
obv1 ⟨ refl , refl ⟩ = refl
obv2 : ∀ {A B A B : Type} → A ⇒ B ≡ A ⇒ B → (A ≡ A) × (B ≡ B)
obv2 refl = ⟨ refl , refl ⟩
_≟_ : ∀ (Γ Δ : Env) → Dec (Γ ≡ Δ)
ε ≟ ε = yes refl
ε ≟ (Γ , A) = no (λ())
(Γ , A) ≟ ε = no (λ())
(Γ , A) ≟ (Δ , B) = map (equivalence obv1 obv2) ((Γ ≟ Δ) ×-dec (A ≟T B))
where
obv1 : ∀ {Γ Δ A B} → (Γ ≡ Δ) × (A ≡ B) → (Γ , A) ≡ (Δ , B)
obv1 ⟨ refl , refl ⟩ = refl
obv2 : ∀ {Γ Δ A B} → (Γ , A) ≡ (Δ , B) → (Γ ≡ Δ) × (A ≡ B)
obv2 refl = ⟨ refl , refl ⟩
## Convert Phoas to Exp
\begin{code}
compare : ∀ (A : Type) (Γ Δ : Env) → Var Δ A
compare A Γ Δ with (Γ , A) ≟ Δ
compare A Γ Δ | yes refl = Z
compare A Γ (Δ , B) | no _ = S (compare A Γ Δ)
compare A Γ ε | no _ = impossible
where
postulate
impossible : ∀ {A : Set} → A
PH→Exp : ∀ {A : Type} → (∀ {X} → PH X A) → Exp ε A
PH→Exp M = h M ε
where
K : Type → Set
K A = Env
h : ∀ {A} → PH K A → (Δ : Env) → Exp Δ A
h {A} (var Γ) Δ = var (compare A Γ Δ)
h {A ⇒ B} (abs N) Δ = abs (h (N Δ) (Δ , A))
h (app L M) Δ = app (h L Δ) (h M Δ)
ex₁ : PH→Exp twoPH ≡ twoExp
ex₁ = refl
\end{code}
## When one environment extends another
We could get rid of the use of `impossible` above if we could prove
that `Extends (Γ , A) Δ` in the `(var Γ)` case of the definition of `h`.
\begin{code}
data Extends : (Γ : Env) → (Δ : Env) → Set where
Z : ∀ {Γ : Env} → Extends Γ Γ
S : ∀ {A : Type} {Γ Δ : Env} → Extends Γ Δ → Extends Γ (Δ , A)
extract : ∀ {A : Type} {Γ Δ : Env} → Extends (Γ , A) Δ → Var Δ A
extract Z = Z
extract (S k) = S (extract k)
\end{code}

View file

@ -1,233 +0,0 @@
Many thanks to Nils and Roman.
Attached find an implementation along the lines sketched by Roman;
I found it after I sent my request and before Roman sent his helpful
reply.
One thing I note, in both Roman's code and mine, is that the code to
decide whether two contexts are equal is lengthy (_≟T_ and _≟_,
below). Is there a better way to do it? Does Agda offer an
equivalent of Haskell's derivable for equality?
Cheers, -- P
[Version using Ulf's prelude to derive equality]
## Imports
\begin{code}
open import Relation.Binary.PropositionalEquality using (_≡_; refl)
open import Data.Nat using (; zero; suc; _+_; _∸_)
open import Data.Product using (_×_; proj₁; proj₂; ∃; ∃-syntax) renaming (_,_ to ⟨_,_⟩)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Decidable using (map)
open import Relation.Nullary.Negation using (contraposition)
open import Relation.Nullary.Product using (_×-dec_)
open import Data.Unit using (; tt)
open import Data.Empty using (⊥; ⊥-elim)
open import Function using (_∘_)
open import Function.Equivalence using (_⇔_; equivalence)
\end{code}
## Typed DeBruijn
\begin{code}
infixr 5 _⇒_
data Type : Set where
o : Type
_⇒_ : Type → Type → Type
data Env : Set where
ε : Env
_,_ : Env → Type → Env
data Var : Env → Type → Set where
Z : ∀ {Γ : Env} {A : Type} → Var (Γ , A) A
S : ∀ {Γ : Env} {A B : Type} → Var Γ B → Var (Γ , A) B
data Exp : Env → Type → Set where
var : ∀ {Γ : Env} {A : Type} → Var Γ A → Exp Γ A
abs : ∀ {Γ : Env} {A B : Type} → Exp (Γ , A) B → Exp Γ (A ⇒ B)
app : ∀ {Γ : Env} {A B : Type} → Exp Γ (A ⇒ B) → Exp Γ A → Exp Γ B
\end{code}
## Untyped DeBruijn
\begin{code}
data DB : Set where
var : → DB
abs : DB → DB
app : DB → DB → DB
\end{code}
# PHOAS
\begin{code}
data PH (X : Type → Set) : Type → Set where
var : ∀ {A : Type} → X A → PH X A
abs : ∀ {A B : Type} → (X A → PH X B) → PH X (A ⇒ B)
app : ∀ {A B : Type} → PH X (A ⇒ B) → PH X A → PH X B
\end{code}
# Convert PHOAS to DB
\begin{code}
PH→DB : ∀ {A} → (∀ {X} → PH X A) → DB
PH→DB M = h M 0
where
K : Type → Set
K A =
h : ∀ {A} → PH K A → → DB
h (var k) j = var (j ∸ (k + 1))
h (abs N) j = abs (h (N j) (j + 1))
h (app L M) j = app (h L j) (h M j)
\end{code}
# Test examples
\begin{code}
Church : Type
Church = (o ⇒ o) ⇒ o ⇒ o
twoExp : Exp ε Church
twoExp = (abs (abs (app (var (S Z)) (app (var (S Z)) (var Z)))))
twoPH : ∀ {X} → PH X Church
twoPH = (abs (λ f → (abs (λ x → (app (var f) (app (var f) (var x)))))))
twoDB : DB
twoDB = (abs (abs (app (var 1) (app (var 1) (var 0)))))
ex : PH→DB twoPH ≡ twoDB
ex = refl
\end{code}
## Decide whether environments and types are equal
\begin{code}
-- These two imports are from agda-prelude (https://github.com/UlfNorell/agda-prelude)
open import Tactic.Deriving.Eq using (deriveEq)
import Prelude
instance
unquoteDecl EqType = deriveEq EqType (quote Type)
unquoteDecl EqEnv = deriveEq EqEnv (quote Env)
⊥To⊥ : Prelude.⊥ → ⊥
⊥To⊥ ()
decToDec : ∀ {a} {A : Set a} → Prelude.Dec A → Dec A
decToDec (Prelude.yes x) = yes x
decToDec (Prelude.no nx) = no (⊥To⊥ ∘ nx)
_≟T_ : ∀ (A B : Type) → Dec (A ≡ B)
A ≟T B = decToDec (A Prelude.== B)
_≟_ : ∀ (Γ Δ : Env) → Dec (Γ ≡ Δ)
Γ ≟ Δ = decToDec (Γ Prelude.== Δ)
\end{code}
[Old version, no longer needed]
_≟T_ : ∀ (A B : Type) → Dec (A ≡ B)
o ≟T o = yes refl
o ≟T (A ⇒ B) = no (λ())
(A ⇒ B) ≟T o = no (λ())
(A ⇒ B) ≟T (A ⇒ B) = map (equivalence obv1 obv2) ((A ≟T A) ×-dec (B ≟T B))
where
obv1 : ∀ {A B A B : Type} → (A ≡ A) × (B ≡ B) → A ⇒ B ≡ A ⇒ B
obv1 ⟨ refl , refl ⟩ = refl
obv2 : ∀ {A B A B : Type} → A ⇒ B ≡ A ⇒ B → (A ≡ A) × (B ≡ B)
obv2 refl = ⟨ refl , refl ⟩
_≟_ : ∀ (Γ Δ : Env) → Dec (Γ ≡ Δ)
ε ≟ ε = yes refl
ε ≟ (Γ , A) = no (λ())
(Γ , A) ≟ ε = no (λ())
(Γ , A) ≟ (Δ , B) = map (equivalence obv1 obv2) ((Γ ≟ Δ) ×-dec (A ≟T B))
where
obv1 : ∀ {Γ Δ A B} → (Γ ≡ Δ) × (A ≡ B) → (Γ , A) ≡ (Δ , B)
obv1 ⟨ refl , refl ⟩ = refl
obv2 : ∀ {Γ Δ A B} → (Γ , A) ≡ (Δ , B) → (Γ ≡ Δ) × (A ≡ B)
obv2 refl = ⟨ refl , refl ⟩
## Convert Phoas to Exp
\begin{code}
compare : ∀ (A : Type) (Γ Δ : Env) → Var Δ A
compare A Γ Δ with (Γ , A) ≟ Δ
compare A Γ Δ | yes refl = Z
compare A Γ (Δ , B) | no _ = S (compare A Γ Δ)
compare A Γ ε | no _ = impossible
where
postulate
impossible : ∀ {A : Set} → A
PH→Exp : ∀ {A : Type} → (∀ {X} → PH X A) → Exp ε A
PH→Exp M = h M ε
where
K : Type → Set
K A = Env
h : ∀ {A} → PH K A → (Δ : Env) → Exp Δ A
h {A} (var Γ) Δ = var (compare A Γ Δ)
h {A ⇒ B} (abs N) Δ = abs (h (N Δ) (Δ , A))
h (app L M) Δ = app (h L Δ) (h M Δ)
ex₁ : PH→Exp twoPH ≡ twoExp
ex₁ = refl
\end{code}
## Convert Exp to Phoas
\begin{code}
Exp→PH : ∀ {A} → Exp ε A → ∀ {X} → PH X A
Exp→PH M = h M tt
where
env : (Type → Set) → Env → Set
env X ε =
env X (Γ , A) = env X Γ × X A
g : ∀ {X Γ A} → Var Γ A → env X Γ → X A
g Z ⟨ _ , v ⟩ = v
g (S x) ⟨ ρ , _ ⟩ = g x ρ
h : ∀ {X Γ A} → Exp Γ A → env X Γ → PH X A
h (var x) ρ = var (g x ρ)
h (abs N) ρ = abs (λ v → h N ⟨ ρ , v ⟩)
h (app L M) ρ = app (h L ρ) (h M ρ)
_ : ∀ {X} → Exp→PH twoExp {X} ≡ twoPH {X}
_ = refl
\end{code}
Executing
Exp→PH twoExp
returns
λ {_} → abs (λ v → abs (λ v₁ → app (var v) (app (var v) (var v₁))))
## When one environment extends another
We could get rid of the use of `impossible` above if we could prove
that `Extends (Γ , A) Δ` in the `(var Γ)` case of the definition of `h`.
\begin{code}
data Extends : (Γ : Env) → (Δ : Env) → Set where
Z : ∀ {Γ : Env} → Extends Γ Γ
S : ∀ {A : Type} {Γ Δ : Env} → Extends Γ Δ → Extends Γ (Δ , A)
extract : ∀ {A : Type} {Γ Δ : Env} → Extends (Γ , A) Δ → Var Δ A
extract Z = Z
extract (S k) = S (extract k)
\end{code}

View file

@ -1,89 +0,0 @@
The typed DeBruijn representation is well known, as are typed PHOAS
and untyped DeBruijn. It is easy to convert PHOAS to untyped
DeBruijn. Is it known how to convert PHOAS to typed DeBruijn?
Yours, -- P
## Imports
\begin{code}
open import Relation.Binary.PropositionalEquality using (_≡_; refl)
open import Data.Nat using (; zero; suc; _+_; _∸_)
\end{code}
## Typed DeBruijn
\begin{code}
infixr 4 _⇒_
data Type : Set where
o : Type
_⇒_ : Type → Type → Type
data Env : Set where
ε : Env
_,_ : Env → Type → Env
data Var : Env → Type → Set where
Z : ∀ {Γ : Env} {A : Type} → Var (Γ , A) A
S : ∀ {Γ : Env} {A B : Type} → Var Γ B → Var (Γ , A) B
data Exp : Env → Type → Set where
var : ∀ {Γ : Env} {A : Type} → Var Γ A → Exp Γ A
abs : ∀ {Γ : Env} {A B : Type} → Exp (Γ , A) B → Exp Γ (A ⇒ B)
app : ∀ {Γ : Env} {A B : Type} → Exp Γ (A ⇒ B) → Exp Γ A → Exp Γ B
\end{code}
## Untyped DeBruijn
\begin{code}
data DB : Set where
var : → DB
abs : DB → DB
app : DB → DB → DB
\end{code}
# PHOAS
\begin{code}
data PH (X : Type → Set) : Type → Set where
var : ∀ {A : Type} → X A → PH X A
abs : ∀ {A B : Type} → (X A → PH X B) → PH X (A ⇒ B)
app : ∀ {A B : Type} → PH X (A ⇒ B) → PH X A → PH X B
\end{code}
# Convert PHOAS to DB
\begin{code}
PH→DB : ∀ {A} → (∀ {X} → PH X A) → DB
PH→DB M = h M 0
where
K : Type → Set
K A =
h : ∀ {A} → PH K A → → DB
h (var k) j = var (j ∸ k)
h (abs N) j = abs (h (N (j + 1)) (j + 1))
h (app L M) j = app (h L j) (h M j)
\end{code}
# Test examples
\begin{code}
Church : Type
Church = (o ⇒ o) ⇒ o ⇒ o
twoExp : Exp ε Church
twoExp = (abs (abs (app (var (S Z)) (app (var (S Z)) (var Z)))))
twoPH : ∀ {X} → PH X Church
twoPH = (abs (λ f → (abs (λ x → (app (var f) (app (var f) (var x)))))))
twoDB : DB
twoDB = (abs (abs (app (var 1) (app (var 1) (var 0)))))
ex : PH→DB twoPH ≡ twoDB
ex = refl
\end{code}

View file

@ -1,75 +0,0 @@
## DeBruijn encodings in Agda
\begin{code}
module DeBruijn2 where
\end{code}
## Imports
\begin{code}
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong)
open Eq.≡-Reasoning
open import Data.Nat using (; zero; suc)
open import Data.Product using (_×_; proj₁; proj₂) renaming (_,_ to ⟨_,_⟩)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Relation.Nullary using (¬_)
open import Relation.Nullary.Negation using (contraposition)
open import Data.Unit using (; tt)
open import Data.Empty using (⊥; ⊥-elim)
open import Function using (_∘_)
\end{code}
## Representation
\begin{code}
infixr 4 _,_
data TEnv : Set where
ε : TEnv
_,* : TEnv → TEnv
data Type : TEnv → Set where
` : ∀ {Δ : TEnv} → Type Δ
_`→_ : ∀ {Δ : TEnv} → Type Δ → Type Δ → Type Δ
`∀ : ∀ {Δ : TEnv} → Type (Δ ,*) → Type Δ
data Env : TEnv → Set where
ε : {Δ : TEnv} → Env Δ
_,_ : {Δ : TEnv} → Env Δ → Type Δ → Env Δ
data TVar : TEnv → Set where
zero : ∀ {Δ : TEnv} → TVar (Δ ,*)
suc : ∀ {Δ : TEnv} → TVar Δ → TVar (Δ ,*)
data Var : (Δ : TEnv) → Env Δ → Type Δ → Set where
zero : ∀ {Δ : TEnv} {Γ : Env Δ} {A : Type Δ} → Var Δ (Γ , A) A
suc : ∀ {Δ : TEnv} {Γ : Env Δ} {A B : Type Δ} → Var Δ Γ B → Var Δ (Γ , A) B
sub : ∀ {Δ : TEnv} → Type (Δ ,*) → TVar (Δ ,*) → Type Δ → Type Δ
sub = ?
data Exp : (Δ : TEnv) → Env Δ → Type Δ → Set where
var : ∀ {Δ : TEnv} {Γ : Env Δ} {A : Type Δ} → Var Δ Γ A → Exp Δ Γ A
abs : ∀ {Δ : TEnv} {Γ : Env Δ} {A B : Type Δ} → Exp Δ (Γ , A) B → Exp Δ Γ (A `→ B)
app : ∀ {Δ : TEnv} {Γ : Env Δ} {A B : Type Δ} → Exp Δ Γ (A `→ B) → Exp Δ Γ A → Exp Δ Γ B
tabs : ∀ {Δ : TEnv} {Γ : Env Δ} {B : Type Δ} → Exp (Δ ,*) Γ B → Exp Δ Γ (`∀ B)
tapp : ∀ {Δ : TEnv} {Γ : Env Δ} {B : Type Δ} → Exp Δ Γ (`∀ B) → (A : Type Δ) → Exp Δ Γ (sub B zero A)
type : Type → Set
type ` =
type (A `→ B) = type A → type B
env : Env → Set
env ε =
env (Γ , A) = env Γ × type A
lookup : ∀ {Γ : Env} {A : Type} → Var Γ A → env Γ → type A
lookup zero ⟨ ρ , v ⟩ = v
lookup (suc n) ⟨ ρ , v ⟩ = lookup n ρ
eval : ∀ {Γ : Env} {A : Type} → Exp Γ A → env Γ → type A
eval (var n) ρ = lookup n ρ
eval (abs N) ρ = λ{ v → eval N ⟨ ρ , v ⟩ }
eval (app L M) ρ = eval L ρ (eval M ρ)
\end{code}

View file

@ -1,29 +0,0 @@
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl)
open import Data.Nat using (; zero; suc)
open import Relation.Nullary using (Dec; yes; no)
data _≤_ : Set where
z≤n : {n : } zero n
s≤s : {m n : } m n suc m suc n
_≤?_ : (m n : ) Dec (m n)
zero ≤? n = yes z≤n
suc m ≤? zero = no λ()
suc m ≤? suc n with m ≤? n
... | yes m≤n = yes (s≤s m≤n)
... | no ¬m≤n = no λ{ (s≤s m≤n) ¬m≤n m≤n }
_ : 2 ≤? 4 yes (s≤s (s≤s z≤n))
_ = refl
_ : 4 ≤? 2 no {!!}
_ = refl
{-
Using ^C ^N, the term
4 ≤? 2
evaluates to
no (λ { (s≤s m≤n) (λ { (s≤s m≤n) (λ ()) 1 m≤n }) m≤n })
The 1 is spurious.
-}

View file

@ -1,603 +0,0 @@
---
title : "Decidable: Booleans and decision procedures"
layout : page
permalink : /DecidableExtra/
---
\begin{code}
module plfa.DecidableExtra where
\end{code}
We have a choice as to how to represent relations:
as an inductive data type of _evidence_ that the relation holds,
or as a function that _computes_ whether the relation holds.
Here we explore the relation between these choices.
## Imports
\begin{code}
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong)
open Eq.≡-Reasoning
open import Data.Nat using (; zero; suc; _≤_; z≤n; s≤s)
open import Data.Nat.Properties using (≤-total)
open import Data.Product using (_×_; ∃; ∃-syntax) renaming (_,_ to ⟨_,_⟩)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Relation.Nullary using (¬_)
open import Relation.Nullary.Negation using (contraposition)
renaming (contradiction to ¬¬-intro)
open import Data.Unit using (; tt)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.List using (List; []; _∷_; foldr; map)
open import Function using (_∘_)
open import plfa.Relations using (_<_; z<s; s<s)
open import plfa.Isomorphism using (_⇔_)
\end{code}
## Evidence vs Computation
Recall that Chapter [Relations][plfa.Relations]
defined comparison an inductive datatype, which provides _evidence_ that one number
is less than or equal to another.
infix 4 _≤_
data _≤_ : → Set where
z≤n : ∀ {n : }
--------
→ zero ≤ n
s≤s : ∀ {m n : }
→ m ≤ n
-------------
→ suc m ≤ suc n
For example, we can provide evidence that `2 ≤ 4`,
and show there is no possible evidence that `4 ≤ 2`.
\begin{code}
2≤4 : 2 ≤ 4
2≤4 = s≤s (s≤s z≤n)
¬4≤2 : ¬ (4 ≤ 2)
¬4≤2 (s≤s (s≤s ()))
\end{code}
The occurrence of `()` attests to the fact that there is
no possible evidence for `2 ≤ 0`, which `z≤n` cannot match
(because `2` is not `zero`) and `s≤s` cannot match
(because `0` cannot match `suc n`).
An alternative, which may seem more familiar, is to define a
type of booleans.
\begin{code}
data Bool : Set where
true : Bool
false : Bool
\end{code}
Given booleans, we can define a function of two numbers that
_computes_ to `true` if the comparison holds and to `false` otherwise.
\begin{code}
infix 4 _≤ᵇ_
_≤ᵇ_ : → Bool
zero ≤ᵇ n = true
suc m ≤ᵇ zero = false
suc m ≤ᵇ suc n = m ≤ᵇ n
\end{code}
The first and last clauses of this definition resemble the two
constructors of the corresponding inductive datatype, while the
middle clause arises because there is no possible evidence that
`suc m ≤ zero` for any `m`.
For example, we can compute that `2 ≤ 4` holds,
and we can compute that `4 ≤ 2` does not hold.
\begin{code}
_ : (2 ≤ᵇ 4) ≡ true
_ =
begin
2 ≤ᵇ 4
≡⟨⟩
1 ≤ᵇ 3
≡⟨⟩
0 ≤ᵇ 2
≡⟨⟩
true
_ : (4 ≤ᵇ 2) ≡ false
_ =
begin
4 ≤ᵇ 2
≡⟨⟩
3 ≤ᵇ 1
≡⟨⟩
2 ≤ᵇ 0
≡⟨⟩
false
\end{code}
In the first case, it takes two steps to reduce the first argument to zero,
and one more step to compute true, corresponding to the two uses of `s≤s`
and the one use of `z≤n` when providing evidence that `2 ≤ 4`.
In the second case, it takes two steps to reduce the second argument to zero,
and one more step to compute false, corresponding to the two uses of `s≤s`
and the one use of `()` when showing there can be no evidence that `4 ≤ 2`.
## Relating evidence and computation
We would hope to be able to show these two approaches are related, and
indeed we can. First, we define a function that lets us map from the
computation world to the evidence world.
\begin{code}
T : Bool → Set
T true =
T false = ⊥
\end{code}
Recall that `` is the unit type which contains the single element `tt`,
and the `⊥` is the empty type which contains no values. (Also note that
`T` is a capital letter t, and distinct from ``.) If `b` is of type `Bool`,
then `tt` provides evidence that `T b` holds if `b` is true, while there is
no possible evidence that `T b` holds if `b` is false.
Another way to put this is that `T b` is inhabited exactly when `b ≡ true`
is inhabited.
In the forward direction, we need to do a case analysis on the boolean `b`.
\begin{code}
T→≡ : ∀ (b : Bool) → T b → b ≡ true
T→≡ true tt = refl
T→≡ false ()
\end{code}
If `b` is true then `T b` is inhabited by `tt` and `b ≡ true` is inhabited
by `refl`, while if `b` is false then `T b` in uninhabited.
In the reverse direction, there is no need for a case analysis.
\begin{code}
≡→T : ∀ {b : Bool} → b ≡ true → T b
≡→T refl = tt
\end{code}
If `b ≡ true` is inhabited by `refl` we know that `b` is `true` and
hence `T b` is inhabited by `tt`.
Now we can show that `T (m ≤ᵇ n)` is inhabited exactly when `m ≤ n` is inhabited.
In the forward direction, we consider the three clauses in the definition
of `_≤ᵇ_`.
\begin{code}
≤ᵇ→≤ : ∀ (m n : ) → T (m ≤ᵇ n) → m ≤ n
≤ᵇ→≤ zero n tt = z≤n
≤ᵇ→≤ (suc m) zero ()
≤ᵇ→≤ (suc m) (suc n) t = s≤s (≤ᵇ→≤ m n t)
\end{code}
In the first clause, we immediately have that `zero ≤ᵇ n` is
true, so `T (m ≤ᵇ n)` is evidenced by `tt`, and correspondingly `m ≤ n` is
evidenced by `z≤n`. In the middle clause, we immediately have that
`suc m ≤ᵇ zero` is false, and hence `T (m ≤ᵇ n)` is empty, so we need
not provide evidence that `m ≤ n`, which is just as well since there is no
such evidence. In the last clause, we have the `suc m ≤ suc n` recurses
to `m ≤ n` and we let `t` be the evidence of `T (m ≤ᵇ n)` if it exists.
We recursively invoke the function to get evidence that `m ≤ n`, which
`s≤s` converts to evidence that `suc m ≤ suc n`.
In the reverse direction, we consider the possible forms of evidence
that `m ≤ n`.
\begin{code}
≤→≤ᵇ : ∀ {m n : } → m ≤ n → T (m ≤ᵇ n)
≤→≤ᵇ z≤n = tt
≤→≤ᵇ (s≤s m≤n) = ≤→≤ᵇ m≤n
\end{code}
If the evidence is `z≤n` then we immediately have that `zero ≤ᵇ n` is
true, so `T (m ≤ᵇ n)` is evidenced by `tt`. If the evidence is `s≤s`
applied to `m≤n`, then `suc m ≤ᵇ suc n` reduces to `m ≤ᵇ n`, and we
may recursively invoke the function to produce evidence that `T (m ≤ᵇ n)`.
The forward proof has one more clause than the reverse proof,
precisely because in the forward proof we need clauses corresponding to
the comparison yielding both true and false, while in the reverse proof
we only need clauses corresponding to the case where there is evidence
that the comparision holds. This is exactly why we tend to prefer the
evidence formulation to the computation formulation, because it allows
us to do less work: we consider only cases where the relation holds,
and can ignore those where it does not.
On the other hand, sometimes the computation formulation may be just what
we want. Given a non-obvious relation over large values, it might be
handy to have the computer work out the answer for us. Fortunately,
rather than choosing between _evidence_ and _computation_,
there is a way to get the benefits of both.
## The best of both worlds
A function that returns a boolean returns exactly a single bit of information:
does the relation hold or does it not? Conversely, the evidence approach tells
us exactly why the relation holds, but we are responsible for generating the
evidence. But it is easy to define a type that combines the benefits of
both approaches. It is called `Dec A`, where `Dec` is short for _decidable_.
\begin{code}
data Dec (A : Set) : Set where
yes : A → Dec A
no : ¬ A → Dec A
\end{code}
Like booleans, the type has two constructors. A value of type `Dec A`
is either of the form `yes x`, where `x` provides evidence that `A` holds,
or of the form `no ¬x`, where `¬x` provides evidence that `A` cannot hold
(that is, `¬x` is a function which given evidence of `A` yields a contradiction).
For example, we define a function `_≤?_` which given two numbers decides whether one
is less than or equal to the other, and provides evidence to justify its conclusion.
First, we introduce two functions useful for constructing evidence that
an inequality does not hold.
\begin{code}
¬s≤z : ∀ {m : } → ¬ (suc m ≤ zero)
¬s≤z ()
¬s≤s : ∀ {m n : } → ¬ (m ≤ n) → ¬ (suc m ≤ suc n)
¬s≤s ¬m≤n (s≤s m≤n) = ¬m≤n m≤n
\end{code}
The first of these asserts that `¬ (suc m ≤ zero)`, and follows by
absurdity, since any evidence of inequality has the form `zero ≤ n`
or `suc m ≤ suc n`, neither of which match `suc m ≤ zero`. The second
of these takes evidence `¬m≤n` of `¬ (m ≤ n)` and returns a proof of
`¬ (suc m ≤ suc n)`. Any evidence of `suc m ≤ suc n` must have the
form `s≤s m≤n` where `m≤n` is evidence that `m ≤ n`. Hence, we have
a contradiction, evidenced by `¬m≤n m≤n`.
Using these, it is straightforward to decide an inequality.
\begin{code}
_≤?_ : ∀ (m n : ) → Dec (m ≤ n)
zero ≤? n = yes z≤n
suc m ≤? zero = no ¬s≤z
suc m ≤? suc n with m ≤? n
... | yes m≤n = yes (s≤s m≤n)
... | no ¬m≤n = no (¬s≤s ¬m≤n)
\end{code}
As with `_≤ᵇ_`, the definition has three clauses. In the first
clause, it is immediate that `zero ≤ n` holds, and it is evidenced by
`z≤n`. In the second clause, it is immediate that `suc m ≤ n` does
not hold, and it is evidenced by `¬s≤z`.
In the third clause, to decide whether `suc m ≤ suc n` holds we
recursively invoke `m ≤? n`. There are two possibilities. In the
`yes` case it returns evidence `m≤n` that `m ≤ n`, and `s≤s m≤n`
provides evidence that `suc m ≤ suc n`. In the `no` case it returns
evidence `¬m≤n` that `¬ (m ≤ n)`, and `¬s≤s ¬m≤n` provides evidence
that `¬ (suc m ≤ suc n)`.
When we wrote `_≤ᵇ_`, we had to write two other functions, `≤ᵇ→≤` and `≤→≤ᵇ`,
in order to show that it was correct. In contrast, the definition of `_≤?_`
proves itself correct, as attested to by its type. The code of `_≤?_`
is far more compact than the combined code of `_≤ᵇ_`, `≤ᵇ→≤`, and `≤→≤ᵇ`.
And, as we will later show, if you really want the latter three, it is easy
to derive them from `_≤?_`.
We can use our new function to _compute_ the _evidence_ that earlier we had to
think up on our own.
\begin{code}
_ : 2 ≤? 4 ≡ yes (s≤s (s≤s z≤n))
_ = refl
_ : 4 ≤? 2 ≡ no (¬s≤s (¬s≤s ¬s≤z))
_ = refl
\end{code}
You can check that Agda will indeed compute these values. Typing
`C-c C-n` and providing `2 ≤? 4` or `4 ≤? 2` as the requested expression
causes Agda to print the values given above.
(A subtlety: if we do not define `¬s≤z` and `¬s≤s` as top-level functions,
but instead use inline anonymous functions then Agda may have
trouble normalising evidence of negation.)
#### Exercise `_<?_` (recommended)
Analogous to the function above, define a function to decide strict inequality.
\begin{code}
postulate
_<?_ : ∀ (m n : ) → Dec (m < n)
\end{code}
#### Exercise `_≡?_`
Define a function to decide whether two naturals are equal.
\begin{code}
postulate
_≡?_ : ∀ (m n : ) → Dec (m ≡ n)
\end{code}
## Decidables from booleans, and booleans from decidables
Curious readers might wonder if we could reuse the definition of
`m ≤ᵇ n`, together with the proofs that it is equivalent to `m ≤ n`, to show
decidability. Indeed, we can do so as follows.
\begin{code}
_≤?_ : ∀ (m n : ) → Dec (m ≤ n)
m ≤? n with m ≤ᵇ n | ≤ᵇ→≤ m n | ≤→≤ᵇ {m} {n}
... | true | p | _ = yes (p tt)
... | false | _ | ¬p = no ¬p
\end{code}
If `m ≤ᵇ n` is true then `≤ᵇ→≤` yields a proof that `m ≤ n` holds,
while if it is false then `≤→≤ᵇ` takes a proof the `m ≤ n` holds into a contradiction.
The triple binding of the `with` clause in this proof is essential.
If instead we wrote
_≤?″_ : ∀ (m n : ) → Dec (m ≤ n)
m ≤?″ n with m ≤ᵇ n
... | true = yes (≤ᵇ→≤ m n tt)
... | false = no (≤→≤ᵇ {m} {n})
then Agda would make two complaints, one for each clause
!=< (T (m ≤ᵇ n)) of type Set
when checking that the expression tt has type T (m ≤ᵇ n)
T (m ≤ᵇ n) !=< ⊥ of type Set
when checking that the expression ≤→≤ᵇ {m} {n} has type ¬ m ≤ n
Putting the expressions into the `with` clause permits Agda to exploit
the fact that `T (m ≤ᵇ n)` is `` when `m ≤ᵇ n` is true, and that
`T (m ≤ᵇ n)` is `⊥` when `m ≤ᵇ n` is false.
However, overall it is simpler to just define `_≤?_` directly, as in the previous
section. If one really wants `_≤ᵇ_`, then it and its properties are easily derived
from `_≤?_`, as we will now show.
Erasure takes a decidable value to a boolean.
\begin{code}
⌊_⌋ : ∀ {A : Set} → Dec A → Bool
⌊ yes x ⌋ = true
⌊ no ¬x ⌋ = false
\end{code}
Using erasure, we can easily derive `_≤ᵇ_` from `_≤?_`.
\begin{code}
_≤ᵇ_ : → Bool
m ≤ᵇ′ n = ⌊ m ≤? n ⌋
\end{code}
Further, if `D` is a value of type `Dec A`, then `T ⌊ D ⌋` is
inhabited exactly when `A` is inhabited.
\begin{code}
toWitness : ∀ {A : Set} → {D : Dec A} → T ⌊ D ⌋ → A
toWitness {A} {yes x} tt = x
toWitness {A} {no ¬x} ()
fromWitness : ∀ {A : Set} → {D : Dec A} → A → T ⌊ D ⌋
fromWitness {A} {yes x} _ = tt
fromWitness {A} {no ¬x} x = ¬x x
\end{code}
Using these, we can easily derive that `T (m ≤ᵇ′ n)` is inhabited
exactly when `m ≤ n` is inhabited.
\begin{code}
≤ᵇ′→≤ : ∀ {m n : } → T (m ≤ᵇ′ n) → m ≤ n
≤ᵇ′→≤ = toWitness
≤→≤ᵇ′ : ∀ {m n : } → m ≤ n → T (m ≤ᵇ′ n)
≤→≤ᵇ′ = fromWitness
\end{code}
In summary, it is usually best to eschew booleans and rely on decidables instead.
If you need booleans, they and their properties are easily derived from the
corresponding decidables.
## Oliver's problem
\begin{code}
swap-≤ : ∀ {m n : } → ¬ (m ≤ n) → n ≤ m
swap-≤ {m} {n} ¬m≤n with ≤-total m n
... | inj₁ m≤n = ⊥-elim (¬m≤n m≤n)
... | inj₂ n≤m = n≤m
data Max (m n p : ) : Set where
left :
m ≤ p
→ n ≡ p
---------
→ Max m n p
right :
m ≡ p
→ n ≤ p
---------
→ Max m n p
_max_ : ∀ (m n : ) → ∃[ p ] (Max m n p)
m max n with m ≤? n
... | yes m≤n = ⟨ n , left m≤n refl ⟩
... | no ¬m≤n = ⟨ m , right refl (swap-≤ ¬m≤n) ⟩
_maxᵇ_ :
m maxᵇ n with m ≤ᵇ n
... | true = n
... | false = m
\end{code}
## Logical connectives
Most readers will be familiar with the logical connectives for booleans.
Each of these extends to decidables.
The conjunction of two booleans is true if both are true,
and false is either is false.
\begin{code}
infixr 6 _∧_
_∧_ : Bool → Bool → Bool
true ∧ true = true
false ∧ _ = false
_ ∧ false = false
\end{code}
In Emacs, the left-hand side of the third equation displays in grey,
indicating that the order of the equations determines which of the
second or the third can match. However, regardless of which matches
the answer is the same.
Correspondingly, given two decidable propositions, we can
decide their conjunction.
\begin{code}
infixr 6 _×-dec_
_×-dec_ : {A B : Set} → Dec A → Dec B → Dec (A × B)
yes x ×-dec yes y = yes ⟨ x , y ⟩
no ¬x ×-dec _ = no λ{ ⟨ x , y ⟩ → ¬x x }
_ ×-dec no ¬y = no λ{ ⟨ x , y ⟩ → ¬y y }
\end{code}
The conjunction of two propositions holds if they both hold,
and its negation holds if the negation of either holds.
If both hold, then we pair the evidence for each to yield
evidence of the conjunct. If the negation of either holds,
assuming the conjunct will lead to a contradiction.
Again in Emacs, the left-hand side of the third equation displays in grey,
indicating that the order of the equations determines which of the
second or the third can match. This time the answer is different depending
on which matches; if both conjuncts fail to hold we pick the first to
yield the contradiction, but it would be equally valid to pick the second.
The disjunction of two booleans is true if either is true,
and false if both are false.
\begin{code}
infixr 5 __
__ : Bool → Bool → Bool
true _ = true
_ true = true
false false = false
\end{code}
In Emacs, the left-hand side of the second equation displays in grey,
indicating that the order of the equations determines which of the
first or the second can match. However, regardless of which matches
the answer is the same.
Correspondingly, given two decidable propositions, we can
decide their disjunction.
\begin{code}
infixr 5 _⊎-dec_
_⊎-dec_ : {A B : Set} → Dec A → Dec B → Dec (A ⊎ B)
yes x ⊎-dec _ = yes (inj₁ x)
_ ⊎-dec yes y = yes (inj₂ y)
no ¬x ⊎-dec no ¬y = no λ{ (inj₁ x) → ¬x x ; (inj₂ y) → ¬y y }
\end{code}
The disjunction of two propositions holds if either holds,
and its negation holds if the negation of both hold.
If either holds, we inject the evidence to yield
evidence of the disjunct. If the negation of both hold,
assuming either disjunct will lead to a contradiction.
Again in Emacs, the left-hand side of the second equation displays in grey,
indicating that the order of the equations determines which of the
first or the second can match. This time the answer is different depending
on which matches; if both disjuncts hold we pick the first,
but it would be equally valid to pick the second.
The negation of a boolean is false if its argument is true,
and vice versa.
\begin{code}
not : Bool → Bool
not true = false
not false = true
\end{code}
Correspondingly, given a decidable proposition, we
can decide its negation.
\begin{code}
¬? : {A : Set} → Dec A → Dec (¬ A)
¬? (yes x) = no (¬¬-intro x)
¬? (no ¬x) = yes ¬x
\end{code}
We simply swap yes and no. In the first equation,
the right-hand side asserts that the negation of `¬ A` holds,
in other words, that `¬ ¬ A` holds, which is an easy consequence
of the fact that `A` holds.
There is also a slightly less familiar connective,
corresponding to implication.
\begin{code}
_⊃_ : Bool → Bool → Bool
_ ⊃ true = true
false ⊃ _ = true
true ⊃ false = false
\end{code}
One boolean implies another if
whenever the first is true then the second is true.
Hence, the implication of two booleans is true if
the second is true or the first is false,
and false if the first is true and the second is false.
In Emacs, the left-hand side of the second equation displays in grey,
indicating that the order of the equations determines which of the
first or the second can match. However, regardless of which matches
the answer is the same.
Correspondingly, given two decidable propositions,
we can decide if the first implies the second.
\begin{code}
_→-dec_ : {A B : Set} → Dec A → Dec B → Dec (A → B)
_ →-dec yes y = yes (λ _ → y)
no ¬x →-dec _ = yes (λ x → ⊥-elim (¬x x))
yes x →-dec no ¬y = no (λ f → ¬y (f x))
\end{code}
The implication holds if either the second holds or
the negatioin of the first holds, and its negation
holds if the first holds and the negation of the second holds.
Evidence for the implication is a function from evidence
of the first to evidence of the second.
If the second holds, the function returns the evidence for it.
If the negation of the first holds, the function takes the
evidence of the first and derives a contradiction.
If the first holds and the negation of the second holds,
given evidence of the implication we must derive a contradiction;
we apply the evidence of the implication `f` to the evidence of the
first `x`, yielding a contradiction with the evidence `¬y` of
the negation of the second.
Again in Emacs, the left-hand side of the second equation displays in grey,
indicating that the order of the equations determines which of the
first or the second can match. This time the answer is different depending
on which matches; but either is equally valid.
#### Exercise `erasure`
Show that erasure relates corresponding boolean and decidable operations.
\begin{code}
postulate
∧-× : ∀ {A B : Set} (x : Dec A) (y : Dec B) → ⌊ x ⌋ ∧ ⌊ y ⌋ ≡ ⌊ x ×-dec y ⌋
-× : ∀ {A B : Set} (x : Dec A) (y : Dec B) → ⌊ x ⌋ ⌊ y ⌋ ≡ ⌊ x ⊎-dec y ⌋
not-¬ : ∀ {A : Set} (x : Dec A) → not ⌊ x ⌋ ≡ ⌊ ¬? x ⌋
\end{code}
#### Exercise `iff-erasure` (recommended)
Give analogues of the `_⇔_` operation from
Chapter [Isomorphism][plfa.Isomorphism#iff],
operation on booleans and decidables, and also show the corresponding erasure.
\begin{code}
postulate
_iff_ : Bool → Bool → Bool
_⇔-dec_ : ∀ {A B : Set} → Dec A → Dec B → Dec (A ⇔ B)
iff-⇔ : ∀ {A B : Set} (x : Dec A) (y : Dec B) → ⌊ x ⌋ iff ⌊ y ⌋ ≡ ⌊ x ⇔-dec y ⌋
\end{code}
## Standard Library
\begin{code}
import Data.Bool.Base using (Bool; true; false; T; _∧_; __; not)
import Data.Nat.Base using (_≤?_)
import Data.List.All using (All; []; _∷_) renaming (all to All?)
import Relation.Nullary using (Dec; yes; no)
import Relation.Nullary.Decidable using (⌊_⌋; toWitness; fromWitness)
import Relation.Nullary.Negation using (¬?)
import Relation.Nullary.Product using (_×-dec_)
import Relation.Nullary.Sum using (_⊎-dec_)
\end{code}
## Unicode
∧ U+2227 LOGICAL AND (\and, \wedge)
U+2228 LOGICAL OR (\or, \vee)
⊃ U+2283 SUPERSET OF (\sup)
ᵇ U+1D47 MODIFIER LETTER SMALL B (\^b)
⌊ U+230A LEFT FLOOR (\cll)
⌋ U+230B RIGHT FLOOR (\clr)

View file

@ -1,28 +0,0 @@
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl)
open import Data.Nat using (; zero; suc)
open import Relation.Nullary using (¬_; Dec; yes; no)
data _≤_ : Set where
z≤n : {n : } zero n
s≤s : {m n : } m n suc m suc n
¬s≤z : {m : } ¬ (suc m zero)
¬s≤z ()
¬s≤s : {m n : } ¬ (m n) ¬ (suc m suc n)
¬s≤s ¬m≤n (s≤s m≤n) = ¬m≤n m≤n
_≤?_ : (m n : ) Dec (m n)
zero ≤? n = yes z≤n
suc m ≤? zero = no ¬s≤z
suc m ≤? suc n with m ≤? n
... | yes m≤n = yes (s≤s m≤n)
... | no ¬m≤n = no (¬s≤s ¬m≤n)
_ : 2 ≤? 4 yes (s≤s (s≤s z≤n))
_ = refl
_ : 4 ≤? 2 no (¬s≤s (¬s≤s ¬s≤z))
_ = refl

View file

@ -1,65 +0,0 @@
---
title : "Denotational: Denotational Semantics"
layout : page
permalink : /Denotational
---
## Imports
\begin{code}
module Denotational where
\end{code}
\begin{code}
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl)
open import Data.Nat using (; zero; suc)
open import Data.Product using (_×_; proj₁; proj₂) renaming (_,_ to ⟨_,_⟩)
open import Data.Unit using (; tt)
open import Typed
\end{code}
# Denotational semantics
\begin{code}
⟦_⟧ᵀ : Type → Set
⟦ ` ⟧ᵀ =
⟦ A ⇒ B ⟧ᵀ = ⟦ A ⟧ᵀ → ⟦ B ⟧ᵀ
⟦_⟧ᴱ : Env → Set
⟦ ε ⟧ᴱ =
⟦ Γ , x ⦂ A ⟧ᴱ = ⟦ Γ ⟧ᴱ × ⟦ A ⟧ᵀ
⟦_⟧ⱽ : ∀ {Γ x A} → Γ ∋ x ⦂ A → ⟦ Γ ⟧ᴱ → ⟦ A ⟧ᵀ
⟦ Z ⟧ⱽ ⟨ ρ , v ⟩ = v
⟦ S _ x ⟧ⱽ ⟨ ρ , v ⟩ = ⟦ x ⟧ⱽ ρ
⟦_⟧ : ∀ {Γ M A} → Γ ⊢ M ⦂ A → ⟦ Γ ⟧ᴱ → ⟦ A ⟧ᵀ
⟦ Ax x ⟧ ρ = ⟦ x ⟧ⱽ ρ
⟦ ⊢λ ⊢N ⟧ ρ = λ{ v → ⟦ ⊢N ⟧ ⟨ ρ , v ⟩ }
⟦ ⊢L · ⊢M ⟧ ρ = (⟦ ⊢L ⟧ ρ) (⟦ ⊢M ⟧ ρ)
⟦ ⊢zero ⟧ ρ = zero
⟦ ⊢suc ⊢M ⟧ ρ = suc (⟦ ⊢M ⟧ ρ)
⟦ ⊢pred ⊢M ⟧ ρ = pred (⟦ ⊢M ⟧ ρ)
where
pred :
pred zero = zero
pred (suc n) = n
⟦ ⊢if0 ⊢L ⊢M ⊢N ⟧ ρ = if0 ⟦ ⊢L ⟧ ρ then ⟦ ⊢M ⟧ ρ else ⟦ ⊢N ⟧ ρ
where
if0_then_else_ : ∀ {A} → → A → A → A
if0 zero then m else n = m
if0 suc _ then m else n = n
⟦ ⊢Y ⊢M ⟧ ρ = {!!}
{-
_ : ⟦ ⊢four ⟧ tt ≡ 4
_ = refl
-}
_ : ⟦ ⊢fourCh ⟧ tt ≡ 4
_ = refl
\end{code}

View file

@ -1,6 +0,0 @@
import Data.Bool
import Relation.Nullary.Negation
import Relation.Nullary.Decidable

View file

@ -1,475 +0,0 @@
---
title : "Equivalence: Equivalence and equational reasoning"
layout : page
permalink : /Equivalence
---
<!-- TODO: Consider changing `Equivalence` to `Equality` or `Identity`.
Possibly introduce the name `Martin Löf Identity` early on. -->
Much of our reasoning has involved equivalence. Given two terms `M`
and `N`, both of type `A`, we write `M ≡ N` to assert that `M` and `N`
are interchangeable. So far we have taken equivalence as a primitive,
but in fact it can be defined using the machinery of inductive
datatypes.
## Imports
Pretty much every module in the Agda
standard library, and every chapter in this book, imports the standard
definition of equivalence. Since we define equivalence here, any such
import would create a conflict. The only import we make is the
definition of type levels, which is so primitive that it precedes
the definition of equivalence.
\begin{code}
open import Agda.Primitive using (Level; lzero; lsuc)
open import Data.Nat using (; zero; suc; _+_)
\end{code}
## Equivalence
We declare equivalence as follows.
\begin{code}
data _≡_ {} {A : Set } (x : A) : A → Set where
refl : x ≡ x
\end{code}
In other words, for any type `A` and for any `x` of type `A`, the
constructor `refl` provides evidence that `x ≡ x`. Hence, every value
is equivalent to itself, and we have no other way of showing values
are equivalent. We have quantified over all levels, so that we can
apply equivalence to types belonging to any level. The definition
features an asymetry, in that the first argument to `_≡_` is given by
the parameter `x : A`, while the second is given by an index in `A → Set `.
We declare the precedence of equivalence as follows.
\begin{code}
infix 4 _≡_
\end{code}
We set the precedence of `_≡_` at level 4, the same as `_≤_`,
which means it binds less tightly than any arithmetic operator.
It associates neither to the left nor right; writing `x ≡ y ≡ z`
is illegal.
## Equivalence is an equivalence relation
An equivalence relation is one which is reflexive, symmetric, and transitive.
Reflexivity is built-in to the definition of equivalence, via the
constructor `refl`. It is straightforward to show symmetry.
\begin{code}
sym : ∀ {} {A : Set } {x y : A} → x ≡ y → y ≡ x
sym refl = refl
\end{code}
How does this proof work? The argument to `sym` has type `x ≡ y`,
but on the left-hand side of the equation the argument has been instantiated to the pattern `refl`,
which requires that `x` and `y` are the same. Hence, for the right-hand side of the equation
we need a term of type `x ≡ x`, and `refl` will do.
It is instructive to develop `sym` interactively.
To start, we supply a variable for the argument on the left, and a hole for the body on the right:
sym : ∀ {} {A : Set } {x y : A} → x ≡ y → y ≡ x
sym r = {! !}
If we go into the hole and type `C-C C-,` then Agda reports:
Goal: .y ≡ .x
————————————————————————————————————————————————————————————
r : .x ≡ .y
.y : .A
.x : .A
.A : Set .
. : .Agda.Primitive.Level
If in the hole we type `C-C C-C r` then Agda will instantiate `r` to all possible constructors,
with one equation for each. There is only one possible constructor:
sym : ∀ {} {A : Set } {x y : A} → x ≡ y → y ≡ x
sym refl = {! !}
If we go into the hole again and type `C-C C-,` then Agda now reports:
Goal: .x ≡ .x
————————————————————————————————————————————————————————————
.x : .A
.A : Set .
. : .Agda.Primitive.Level
This is the key step---Agda has worked out that `x` and `y` must be the same to match the pattern `refl`!
Finally, if we go back into the hole and type `C-C C-R` it will
instantiate the hole with the one constructor that yields a value of
the expected type.
sym : ∀ {} {A : Set } {x y : A} → x ≡ y → y ≡ x
sym refl = refl
This completes the definition as given above.
Transitivity is equally straightforward.
\begin{code}
trans : ∀ {} {A : Set } {x y z : A} → x ≡ y → y ≡ z → x ≡ z
trans refl refl = refl
\end{code}
Again, a useful exercise is to carry out an interactive development, checking
how Agda's knowledge changes as each of the two arguments is
instantiated.
Equivalence also satisfies *congruence*. If two terms are equivalent,
then they remain so after the same function is applied to both.
\begin{code}
cong : ∀ {} {A B : Set } (f : A → B) {x y : A} → x ≡ y → f x ≡ f y
cong f refl = refl
\end{code}
Once more, a useful exercise is to carry out an interactive development.
## Tabular reasoning
A few declarations allow us to support the form of tabular reasoning
that we have used throughout the book. We package the declarations
into a module, named `≡-Reasoning`, to match the format used in Agda's
standard library.
\begin{code}
module ≡-Reasoning {} {A : Set } where
infix 1 begin_
infixr 2 _≡⟨⟩_ _≡⟨_⟩_
infix 3 _∎
begin_ : ∀ {x y : A} → x ≡ y → x ≡ y
begin x≡y = x≡y
_≡⟨⟩_ : ∀ (x {y} : A) → x ≡ y → x ≡ y
x ≡⟨⟩ x≡y = x≡y
_≡⟨_⟩_ : ∀ (x : A) {y z : A} → x ≡ y → y ≡ z → x ≡ z
x ≡⟨ x≡y ⟩ y≡z = trans x≡y y≡z
_∎ : ∀ (x : A) → x ≡ x
x ∎ = refl
open ≡-Reasoning
\end{code}
Opening the module makes all of the definitions
available in the current environment.
As a simple example, let's look at the proof of transitivity
rewritten in tabular form.
\begin{code}
trans : ∀ {} {A : Set } {x y z : A} → x ≡ y → y ≡ z → x ≡ z
trans {_} {_} {x} {y} {z} x≡y y≡z =
begin
x
≡⟨ x≡y ⟩
y
≡⟨ y≡z ⟩
z
\end{code}
Tabular proofs begin with `begin`, end with `∎`
(which is sometimes pronounced "qed" or "tombstone")
and consist of a string of equations. Due to the
fixity declarations, the body parses as follows.
begin (x ≡⟨ x≡y ⟩ (y ≡⟨ y≡z ⟩ (z ∎)))
The application of `begin` is purely cosmetic, as it simply returns
its argument. That argument consists of `_≡⟨_⟩_` applied to `x`,
`x≡y`, and `y ≡⟨ y≡z ⟩ (z ∎)`. The first argument is a term, `x`,
while the second and third arguments are both proofs of equations, in
particular proofs of `x ≡ y` and `y ≡ z` respectively, which are
combined by `trans` in the body of `_≡⟨_⟩_` to yield a proof of `x ≡
z`. The proof of `y ≡ z` consists of `_≡⟨_⟩_` applied to `y`, `y≡z`,
and `z ∎`. The first argument is a term, `y`, while the second and
third arguments are both proofs of equations, in particular proofs of
`y ≡ z` and `z ≡ z` respectively, which are combined by `trans` in the
body of `_≡⟨_⟩_` to yield a proof of `y ≡ z`. Finally, the proof of
`z ≡ z` consists of `_∎` applied to the term `z`, which yields `refl`.
After simplification, the body is equivalent to the following term.
trans x≡y (trans y≡z refl)
We could replace all uses of tabular reasoning by a chain of
applications of `trans`, but the result would be far less perspicuous.
Also note that the syntactic trick behind `∎` means that the chain
always ends in the form `trans e refl` even though `e` alone would do,
where `e` is a proof of an equivalence.
<!--
## Tabular reasoning, another example
As a second example of tabular reasoning, we consider the proof that addition
is commutative. We first repeat the definitions of naturals and addition.
We cannot import them because (as noted at the beginning of this chapter)
it would cause a conflict.
\begin{code}
{-
data : Set where
zero :
suc :
_+_ :
zero + n = n
(suc m) + n = suc (m + n)
-}
\end{code}
To save space we postulate (rather than prove in full) two lemmas,
and then repeat the proof of commutativity.
\begin{code}
postulate
+-identity : ∀ (m : ) → m + zero ≡ m
+-suc : ∀ (m n : ) → m + suc n ≡ suc (m + n)
{-
+-comm : ∀ (m n : ) → m + n ≡ n + m
+-comm m zero =
begin
m + zero
≡⟨ +-identity m ⟩
m
≡⟨⟩
zero + m
+-comm m (suc n) =
begin
m + suc n
≡⟨ +-suc m n ⟩
suc (m + n)
≡⟨ cong suc (+-comm m n) ⟩
suc (n + m)
≡⟨⟩
suc n + m
-}
\end{code}
The tabular reasoning here is similar to that in the
preceding section, the one addition being the use of
`_≡⟨⟩_`, which we use when no justification is required.
One can think of occurrences of `≡⟨⟩` as an equivalent
to `≡⟨ refl ⟩`.
Agda always treats a term as equivalent to its
simplified term. The reason that one can write
suc (n + m)
≡⟨⟩
suc n + m
is because Agda treats both terms as the same.
This also means that one could instead interchange
the lines and write
suc n + m
≡⟨⟩
suc (n + m)
and Agda would not object. Agda only checks that the terms
separated by `≡⟨⟩` are equivalent; it's up to us to write
them in an order that will make sense to the reader.
-->
## Rewriting
Consider a property of natural numbers, such as being even.
\begin{code}
data even : → Set where
ev0 : even zero
ev+2 : ∀ {n : } → even n → even (suc (suc n))
\end{code}
In the previous section, we proved addition is commutative.
Given evidence that `even (m + n)` holds,
we ought also to be able to take that as evidence
that `even (n + m)` holds.
Agda includes special notation to support just this
kind of reasoning. To enable this notation, we use
pragmas to tell Agda which type
corresponds to equivalence.
\begin{code}
{-# BUILTIN EQUALITY _≡_ #-}
\end{code}
We can then prove the desired property as follows.
\begin{code}
postulate
+-comm : ∀ (m n : ) → m + n ≡ n + m
even-comm : ∀ (m n : ) → even (m + n) → even (n + m)
even-comm m n ev rewrite +-comm m n = ev
\end{code}
Here `ev` ranges over evidence that `even (m + n)` holds, and we show
that it is also provides evidence that `even (n + m)` holds. In
general, the keyword `rewrite` is followed by evidence of an
equivalence, and that equivalence is used to rewrite the type of the
goal and of any variable in scope.
It is instructive to develop `even-comm` interactively.
To start, we supply variables for the arguments on the left, and a hole for the body on the right:
even-comm : ∀ (m n : ) → even (m + n) → even (n + m)
even-comm m n ev = {! !}
If we go into the hole and type `C-C C-,` then Agda reports:
Goal: even (n + m)
————————————————————————————————————————————————————————————
ev : even (m + n)
n :
m :
Now we add the rewrite.
even-comm : ∀ (m n : ) → even (m + n) → even (n + m)
even-comm m n ev rewrite +-comm m n = {! !}
If we go into the hole again and type `C-C C-,` then Agda now reports:
Goal: even (n + m)
————————————————————————————————————————————————————————————
ev : even (n + m)
n :
m :
Now it is trivial to see that `ev` satisfies the goal, and typing `C-C C-A` in the
hole causes it to be filled with `ev`.
## Multiple rewrites
One may perform multiple rewrites, each separated by a vertical bar. For instance,
here is a second proof that addition is commutative, relying on rewrites rather
than tabular reasoning.
\begin{code}
+-comm : ∀ (m n : ) → m + n ≡ n + m
+-comm zero n rewrite +-identity n = refl
+-comm (suc m) n rewrite +-suc n m | +-comm m n = refl
\end{code}
This is far more compact. Among other things, whereas the previous
proof required `cong suc (+-comm m n)` as the justification to invoke the
inductive hypothesis, here it is sufficient to rewrite with `+-comm m n`, as
rewriting automatically takes congruence into account. Although proofs
with rewriting are shorter, proofs in tabular form make the reasoning
involved easier to follow, and we will stick with the latter when feasible.
## Rewriting expanded
The `rewrite` notation is in fact shorthand for an appropriate use of `with`
abstraction.
\begin{code}
even-comm : ∀ (m n : ) → even (m + n) → even (n + m)
even-comm m n ev with m + n | +-comm m n
... | .(n + m) | refl = ev
\end{code}
The first clause asserts that `m + n` and `n + m` are identical, and
the second clause justifies that assertion with evidence of the
appropriate equivalence. Note the use of the "dot pattern" `.(n +
m)`. A dot pattern is followed by an expression and is made when
other information allows one to identify the expession in the `with`
clause with the expression it matches against. In this case, the
identification of `m + n` and `n + m` is justified by the subsequent
matching of `+-comm m n` against `refl`. One might think that the
first clause is redundant as the information is inherent in the second
clause, but in fact Agda is rather picky on this point: omitting the
first clause or reversing the order of the clauses will cause Agda to
report an error. (Try it and see!)
## Leibniz equality
The form of asserting equivalence that we have used is due to Martin Löf,
and was published in 1975. An older form is due to Leibniz, and was published
in 1686. Leibniz asserted the *identity of indiscernibles*: two objects are
equal if and only if they satisfy the same properties. This
principle sometimes goes by the name Leibniz' Law, and is closely
related to Spock's Law, ``A difference that makes no difference is no
difference''. Here we define Leibniz equality, and show that two terms
satsisfy Lebiniz equality if and only if they satisfy Martin Löf equivalence.
Leibniz equality is usually formalized to state that `x ≐ y`
holds if every property `P` that holds of `x` also holds of
`y`. Perhaps surprisingly, this definition is
sufficient to also ensure the converse, that every property `P` that
holds of `y` also holds of `x`.
Let `x` and `y` be objects of type $A$. We say that `x ≐ y` holds if
for every predicate $P$ over type $A$ we have that `P x` implies `P y`.
\begin{code}
_≐_ : ∀ {} {A : Set } (x y : A) → Set (lsuc )
_≐_ {} {A} x y = (P : A → Set ) → P x → P y
\end{code}
Here we must make use of levels: if `A` is a set at level `` and `x` and `y`
are two values of type `A` then `x ≐ y` is at the next level `lsuc `.
Leibniz equality is reflexive and transitive,
where the first follows by a variant of the identity function
and the second by a variant of function composition.
\begin{code}
refl-≐ : ∀ {} {A : Set } {x : A} → x ≐ x
refl-≐ P Px = Px
trans-≐ : ∀ {} {A : Set } {x y z : A} → x ≐ y → y ≐ z → x ≐ z
trans-≐ x≐y y≐z P Px = y≐z P (x≐y P Px)
\end{code}
Symmetry is less obvious. We have to show that if `P x` implies `P y`
for all predicates `P`, then the implication holds the other way round
as well. Given a specific `P` and a proof `Py` of `P y`, we have to
construct a proof of `P x` given `x ≐ y`. To do so, we instantiate
the equality with a predicate `Q` such that `Q z` holds if `P z`
implies `P x`. The property `Q x` is trivial by reflexivity, and
hence `Q y` follows from `x ≐ y`. But `Q y` is exactly a proof of
what we require, that `P y` implies `P x`.
\begin{code}
sym-≐ : ∀ {} {A : Set } {x y : A} → x ≐ y → y ≐ x
sym-≐ {} {A} {x} {y} x≐y P = Qy
where
Q : A → Set
Q z = P z → P x
Qx : Q x
Qx = refl-≐ P
Qy : Q y
Qy = x≐y Q Qx
\end{code}
We now show that Martin Löf equivalence implies
Leibniz equality, and vice versa. In the forward direction, if we know
`x ≡ y` we need for any `P` to take evidence of `P x` to evidence of `P y`,
which is easy since equivalence of `x` and `y` implies that any proof
of `P x` is also a proof of `P y`.
\begin{code}
≡-implies-≐ : ∀ {} {A : Set } {x y : A} → x ≡ y → x ≐ y
≡-implies-≐ refl P Px = Px
\end{code}
The function `≡-implies-≐` is often called *substitution* because it
says that if we know `x ≡ y` then we can substitute `y` for `x`,
taking a proof of `P x` to a proof of `P y` for any property `P`.
In the reverse direction, given that for any `P` we can take a proof of `P x`
to a proof of `P y` we need to show `x ≡ y`. The proof is similar to that
for symmetry of Leibniz equality. We take $Q$
to be the predicate that holds of `z` if `x ≡ z`. Then `Q x` is trivial
by reflexivity of Martin Löf equivalence, and hence `Q y` follows from
`x ≐ y`. But `Q y` is exactly a proof of what we require, that `x ≡ y`.
\begin{code}
≐-implies-≡ : ∀ {} {A : Set } {x y : A} → x ≐ y → x ≡ y
≐-implies-≡ {} {A} {x} {y} x≐y = Qy
where
Q : A → Set
Q z = x ≡ z
Qx : Q x
Qx = refl
Qy : Q y
Qy = x≐y Q Qx
\end{code}
(Parts of this section are adapted from *≐≃≡: Leibniz Equality is
Isomorphic to Martin-Löf Identity, Parametrically*, by Andreas Abel,
Jesper Cockx, Dominique Devries, Andreas Nuyts, and Philip Wadler,
draft paper, 2017.)

View file

@ -1,70 +0,0 @@
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong)
open Eq.≡-Reasoning
open import Function using (_∘_)
open import Data.Product using (_×_) using (_,_; proj₁; proj₂)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Data.Unit using (; tt)
open import Data.Empty using (⊥; ⊥-elim)
postulate
extensionality : {A B : Set} {f g : A B} ( (x : A) f x g x) f g
β-×₁ : {A B : Set} (x : A) (y : B) proj₁ (x , y) x
β-×₁ x y = refl
β-×₂ : {A B : Set} (x : A) (y : B) proj₂ (x , y) y
β-×₂ x y = refl
η-× : {A B : Set} (w : A × B) (proj₁ w , proj₂ w) w
η-× (x , y) = refl
uniq-× : {A B C : Set} (h : C A × B) (v : C) (proj₁ (h v) , proj₂ (h v)) h v
uniq-× h v = η-× (h v)
⊎-elim : {A B C : Set} (A C) (B C) (A B C)
⊎-elim f g (inj₁ x) = f x
⊎-elim f g (inj₂ y) = g y
β-⊎₁ : {A B C : Set} (f : A C) (g : B C) (x : A) ⊎-elim f g (inj₁ x) f x
β-⊎₁ f g x = refl
β-⊎₂ : {A B C : Set} (f : A C) (g : B C) (y : B) ⊎-elim f g (inj₂ y) g y
β-⊎₂ f g x = refl
η-⊎ : {A B : Set} (w : A B) ⊎-elim inj₁ inj₂ w w
η-⊎ (inj₁ x) = refl
η-⊎ (inj₂ y) = refl
natural-⊎ : {A B C D : Set} (f : A C) (g : B C) (h : C D) (w : A B) ⊎-elim (h f) (h g) w (h ⊎-elim f g) w
natural-⊎ f g h (inj₁ x) = refl
natural-⊎ f g h (inj₂ y) = refl
uniq-⊎ : {A B C : Set} (h : A B C) (w : A B) ⊎-elim (h inj₁) (h inj₂) w h w
uniq-⊎ h w rewrite natural-⊎ inj₁ inj₂ h w | η-⊎ w = refl
η- : (w : ) tt w
η- tt = refl
uniq- : {C : Set} (h : C ) (v : C) tt h v
uniq- h v = η- (h v)
η-⊥ : (w : ) ⊥-elim w w
η-⊥ ()
natural-⊥ : {C D : Set} (h : C D) (w : ) ⊥-elim w (h ⊥-elim) w
natural-⊥ h ()
uniq-⊥ : {C : Set} (h : C) (w : ) ⊥-elim w h w
uniq-⊥ h w rewrite natural-⊥ h w | η-⊥ w = refl
η-→ : {A B : Set} (f : A B) (λ{x f x}) f
η-→ {A} {B} f = extensionality η-helper
where
η-lhs : A B
η-lhs = λ{x f x}
η-helper : (x : A) η-lhs x f x
η-helper x = refl

View file

@ -1,139 +0,0 @@
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong; cong-app)
open Eq.≡-Reasoning
open import Data.Nat using (; zero; suc; _+_; _*_)
open import Data.Product using (∃; _,_)
+-assoc : (m n p : ) m + (n + p) (m + n) + p
+-assoc zero n p =
begin
zero + (n + p)
≡⟨⟩
n + p
≡⟨⟩
(zero + n) + p
+-assoc (suc m) n p =
begin
suc m + (n + p)
≡⟨⟩
suc (m + (n + p))
≡⟨ cong suc (+-assoc m n p)
suc ((m + n) + p)
≡⟨⟩
(suc m + n) + p
+-identity : (m : ) m + zero m
+-identity zero =
begin
zero + zero
≡⟨⟩
zero
+-identity (suc m) =
begin
suc m + zero
≡⟨⟩
suc (m + zero)
≡⟨ cong suc (+-identity m)
suc m
+-suc : (m n : ) m + suc n suc (m + n)
+-suc zero n =
begin
zero + suc n
≡⟨⟩
suc n
≡⟨⟩
suc (zero + n)
+-suc (suc m) n =
begin
suc m + suc n
≡⟨⟩
suc (m + suc n)
≡⟨ cong suc (+-suc m n)
suc (suc (m + n))
≡⟨⟩
suc (suc m + n)
+-comm : (m n : ) m + n n + m
+-comm m zero =
begin
m + zero
≡⟨ +-identity m
m
≡⟨⟩
zero + m
+-comm m (suc n) =
begin
m + suc n
≡⟨ +-suc m n
suc (m + n)
≡⟨ cong suc (+-comm m n)
suc (n + m)
≡⟨⟩
suc n + m
*-distrib-+ : (m n p : ) (m + n) * p m * p + n * p
*-distrib-+ zero n p =
begin
(zero + n) * p
≡⟨⟩
n * p
≡⟨⟩
zero * p + n * p
*-distrib-+ (suc m) n p =
begin
(suc m + n) * p
≡⟨⟩
p + (m + n) * p
≡⟨ cong (_+_ p) (*-distrib-+ m n p)
p + (m * p + n * p)
≡⟨ +-assoc p (m * p) (n * p)
(p + m * p) + n * p
≡⟨⟩
suc m * p + n * p
data even : Set where
ev0 : even zero
ev+2 : {n : } even n even (suc (suc n))
lemma : (m : ) 2 * suc m suc (suc (2 * m))
lemma m =
begin
2 * suc m
≡⟨⟩
suc m + (suc m + zero)
≡⟨⟩
suc (m + (suc (m + zero)))
≡⟨ cong suc (+-suc m (m + zero))
suc (suc (m + (m + zero)))
≡⟨⟩
suc (suc (2 * m))
ev-ex : {n : } even n (λ (m : ) 2 * m n)
ev-ex ev0 = (0 , refl)
ev-ex (ev+2 ev) with ev-ex ev
... | (m , refl) = (suc m , lemma m)
ex-ev : {n : } (λ (m : ) 2 * m n) even n
ex-ev (zero , refl) = ev0
ex-ev (suc m , refl) rewrite lemma m = ev+2 (ex-ev (m , refl))
-- I can't see how to avoid using rewrite in the second proof,
-- or how to use rewrite in the first proof!

View file

@ -1,44 +0,0 @@
open import Data.Nat using (; zero; suc; _+_; _*_)
open import Data.Product using (∃; _,_)
open import Relation.Binary.PropositionalEquality using (_≡_; refl; sym)
+-identity : (m : ) m + zero m
+-identity zero = refl
+-identity (suc m) rewrite +-identity m = refl
+-suc : (m n : ) n + suc m suc (n + m)
+-suc m zero = refl
+-suc m (suc n) rewrite +-suc m n = refl
+-comm : (m n : ) m + n n + m
+-comm zero n rewrite +-identity n = refl
+-comm (suc m) n rewrite +-suc m n | +-comm m n = refl
mutual
data even : Set where
zero : even zero
suc : {n : } odd n even (suc n)
data odd : Set where
suc : {n : } even n odd (suc n)
+-lemma : (m : ) suc (suc (m + (m + 0))) suc m + suc (m + 0)
+-lemma m rewrite +-identity m | +-suc m m = refl
mutual
is-even : (n : ) even n (λ (m : ) n 2 * m)
is-even zero zero = zero , refl
is-even (suc n) (suc oddn) with is-odd n oddn
... | m , n≡1+2*m rewrite n≡1+2*m | +-lemma m = suc m , refl
is-odd : (n : ) odd n (λ (m : ) n 1 + 2 * m)
is-odd (suc n) (suc evenn) with is-even n evenn
... | m , n≡2*m rewrite n≡2*m = m , refl
+-lemma : (m : ) suc (suc (m + (m + 0))) suc m + suc (m + 0)
+-lemma m rewrite +-suc (m + 0) m = refl
is-even : (n : ) even n (λ (m : ) n 2 * m)
is-even zero zero = zero , refl
is-even (suc n) (suc oddn) with is-odd n oddn
... | m , n≡1+2*m rewrite n≡1+2*m | +-identity m | +-suc m m = suc m , {!!}

View file

@ -1,46 +0,0 @@
open import Data.Nat using (; zero; suc; _+_; _*_)
open import Data.Product using (∃; _,_)
open import Relation.Binary.PropositionalEquality using (_≡_; refl; sym)
+-identity : (m : ) m + zero m
+-identity zero = refl
+-identity (suc m) rewrite +-identity m = refl
+-suc : (m n : ) n + suc m suc (n + m)
+-suc m zero = refl
+-suc m (suc n) rewrite +-suc m n = refl
+-comm : (m n : ) m + n n + m
+-comm zero n rewrite +-identity n = refl
+-comm (suc m) n rewrite +-suc m n | +-comm m n = refl
data even : Set
data odd : Set
data even where
zero : even zero
suc : {n : } odd n even (suc n)
data odd where
suc : {n : } even n odd (suc n)
+-lemma : (m : ) suc (suc (m + (m + 0))) suc m + suc (m + 0)
+-lemma m rewrite +-identity m | +-suc m m = refl
mutual
is-even : (n : ) even n (λ (m : ) n 2 * m)
is-even zero zero = zero , refl
is-even (suc n) (suc oddn) with is-odd n oddn
... | m , n≡1+2*m rewrite n≡1+2*m | +-lemma m = suc m , refl
is-odd : (n : ) odd n (λ (m : ) n 1 + 2 * m)
is-odd (suc n) (suc evenn) with is-even n evenn
... | m , n≡2*m rewrite n≡2*m = m , refl
+-lemma : (m : ) suc (suc (m + (m + 0))) suc m + suc (m + 0)
+-lemma m rewrite +-suc (m + 0) m = refl
is-even : (n : ) even n (λ (m : ) n 2 * m)
is-even zero zero = zero , refl
is-even (suc n) (suc oddn) with is-odd n oddn
... | m , n≡1+2*m rewrite n≡1+2*m | +-identity m | +-suc m m = suc m , {!!}

View file

@ -1,31 +0,0 @@
-- Nils' suggestion
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong)
open Eq.≡-Reasoning
open import Data.Nat using (; zero; suc; _+_; _*_)
open import Data.Nat.Properties.Simple using (+-suc)
open import Relation.Nullary using (¬_)
open import Function using (_∘_; id)
open import Data.Product using (_×_; _,_; proj₁; proj₂; map; ∃; ∃-syntax)
open import Data.Sum using (_⊎_; inj₁; inj₂)
data even : Set
data odd : Set
data even where
even-zero : even zero
even-suc : {n : } odd n even (suc n)
data odd where
odd-suc : {n : } even n odd (suc n)
∃-even : {n : } even n ∃[ m ] (n m * 2)
∃-odd : {n : } odd n ∃[ m ] (n 1 + m * 2)
∃-even even-zero = zero , refl
∃-even (even-suc o) with ∃-odd o
... | m , refl = suc m , refl
∃-odd (odd-suc e) with ∃-even e
... | m , refl = m , refl

View file

@ -1,789 +0,0 @@
------------------------------------------------------------------------
-- The Agda standard library
--
-- All library modules, along with short descriptions
------------------------------------------------------------------------
-- Note that core modules are not included.
module Everything where
-- Definitions of algebraic structures like monoids and rings
-- (packed in records together with sets, operations, etc.)
open import Algebra
-- Solver for equations in commutative monoids
open import Algebra.CommutativeMonoidSolver
-- An example of how Algebra.CommutativeMonoidSolver can be used
open import Algebra.CommutativeMonoidSolver.Example
-- Properties of functions, such as associativity and commutativity
open import Algebra.FunctionProperties
-- Relations between properties of functions, such as associativity and
-- commutativity
open import Algebra.FunctionProperties.Consequences
-- Solver for equations in commutative monoids
open import Algebra.IdempotentCommutativeMonoidSolver
-- An example of how Algebra.IdempotentCommutativeMonoidSolver can be
-- used
open import Algebra.IdempotentCommutativeMonoidSolver.Example
-- Solver for monoid equalities
open import Algebra.Monoid-solver
-- Morphisms between algebraic structures
open import Algebra.Morphism
-- Some defined operations (multiplication by natural number and
-- exponentiation)
open import Algebra.Operations
-- Some derivable properties
open import Algebra.Properties.AbelianGroup
-- Some derivable properties
open import Algebra.Properties.BooleanAlgebra
-- Boolean algebra expressions
open import Algebra.Properties.BooleanAlgebra.Expression
-- Some derivable properties
open import Algebra.Properties.DistributiveLattice
-- Some derivable properties
open import Algebra.Properties.Group
-- Some derivable properties
open import Algebra.Properties.Lattice
-- Some derivable properties
open import Algebra.Properties.Ring
-- Solver for commutative ring or semiring equalities
open import Algebra.RingSolver
-- Commutative semirings with some additional structure ("almost"
-- commutative rings), used by the ring solver
open import Algebra.RingSolver.AlmostCommutativeRing
-- Some boring lemmas used by the ring solver
open import Algebra.RingSolver.Lemmas
-- Instantiates the ring solver, using the natural numbers as the
-- coefficient "ring"
open import Algebra.RingSolver.Natural-coefficients
-- Instantiates the ring solver with two copies of the same ring with
-- decidable equality
open import Algebra.RingSolver.Simple
-- Some algebraic structures (not packed up with sets, operations,
-- etc.)
open import Algebra.Structures
-- Applicative functors
open import Category.Applicative
-- Indexed applicative functors
open import Category.Applicative.Indexed
-- Applicative functors on indexed sets (predicates)
open import Category.Applicative.Predicate
-- Functors
open import Category.Functor
-- The identity functor
open import Category.Functor.Identity
-- Functors on indexed sets (predicates)
open import Category.Functor.Predicate
-- Monads
open import Category.Monad
-- A delimited continuation monad
open import Category.Monad.Continuation
-- The identity monad
open import Category.Monad.Identity
-- Indexed monads
open import Category.Monad.Indexed
-- The partiality monad
open import Category.Monad.Partiality
-- An All predicate for the partiality monad
open import Category.Monad.Partiality.All
-- Monads on indexed sets (predicates)
open import Category.Monad.Predicate
-- The state monad
open import Category.Monad.State
-- Basic types related to coinduction
open import Coinduction
-- AVL trees
open import Data.AVL
-- Types and functions which are used to keep track of height
-- invariants in AVL Trees
open import Data.AVL.Height
-- Indexed AVL trees
open import Data.AVL.Indexed
-- Finite maps with indexed keys and values, based on AVL trees
open import Data.AVL.IndexedMap
-- Keys for AVL trees
-- The key type extended with a new minimum and maximum.
open import Data.AVL.Key
-- Finite sets, based on AVL trees
open import Data.AVL.Sets
-- A binary representation of natural numbers
open import Data.Bin
-- Properties of the binary representation of natural numbers
open import Data.Bin.Properties
-- Booleans
open import Data.Bool
-- The type for booleans and some operations
open import Data.Bool.Base
-- A bunch of properties
open import Data.Bool.Properties
-- Showing booleans
open import Data.Bool.Show
-- Bounded vectors
open import Data.BoundedVec
-- Bounded vectors (inefficient, concrete implementation)
open import Data.BoundedVec.Inefficient
-- Characters
open import Data.Char
-- Basic definitions for Characters
open import Data.Char.Base
-- "Finite" sets indexed on coinductive "natural" numbers
open import Data.Cofin
-- Coinductive lists
open import Data.Colist
-- Infinite merge operation for coinductive lists
open import Data.Colist.Infinite-merge
-- Coinductive "natural" numbers
open import Data.Conat
-- Containers, based on the work of Abbott and others
open import Data.Container
-- Properties related to ◇
open import Data.Container.Any
-- Container combinators
open import Data.Container.Combinator
-- The free monad construction on containers
open import Data.Container.FreeMonad
-- Indexed containers aka interaction structures aka polynomial
-- functors. The notation and presentation here is closest to that of
-- Hancock and Hyvernat in "Programming interfaces and basic topology"
-- (2006/9).
open import Data.Container.Indexed
-- Indexed container combinators
open import Data.Container.Indexed.Combinator
-- The free monad construction on indexed containers
open import Data.Container.Indexed.FreeMonad
-- Coinductive vectors
open import Data.Covec
-- Lists with fast append
open import Data.DifferenceList
-- Natural numbers with fast addition (for use together with
-- DifferenceVec)
open import Data.DifferenceNat
-- Vectors with fast append
open import Data.DifferenceVec
-- Digits and digit expansions
open import Data.Digit
-- Empty type
open import Data.Empty
-- An irrelevant version of ⊥-elim
open import Data.Empty.Irrelevant
-- Finite sets
open import Data.Fin
-- Decision procedures for finite sets and subsets of finite sets
open import Data.Fin.Dec
-- Properties related to Fin, and operations making use of these
-- properties (or other properties not available in Data.Fin)
open import Data.Fin.Properties
-- Subsets of finite sets
open import Data.Fin.Subset
-- Some properties about subsets
open import Data.Fin.Subset.Properties
-- Substitutions
open import Data.Fin.Substitution
-- An example of how Data.Fin.Substitution can be used: a definition
-- of substitution for the untyped λ-calculus, along with some lemmas
open import Data.Fin.Substitution.Example
-- Substitution lemmas
open import Data.Fin.Substitution.Lemmas
-- Application of substitutions to lists, along with various lemmas
open import Data.Fin.Substitution.List
-- Floats
open import Data.Float
-- Directed acyclic multigraphs
open import Data.Graph.Acyclic
-- Integers
open import Data.Integer
-- Properties related to addition of integers
open import Data.Integer.Addition.Properties
-- Integers, basic types and operations
open import Data.Integer.Base
-- Divisibility and coprimality
open import Data.Integer.Divisibility
-- Properties related to multiplication of integers
open import Data.Integer.Multiplication.Properties
-- Some properties about integers
open import Data.Integer.Properties
-- Lists
open import Data.List
-- Lists where all elements satisfy a given property
open import Data.List.All
-- Properties related to All
open import Data.List.All.Properties
-- Lists where at least one element satisfies a given property
open import Data.List.Any
-- Properties related to bag and set equality
open import Data.List.Any.BagAndSetEquality
-- List membership and some related definitions
open import Data.List.Any.Membership
-- Properties related to propositional list membership
open import Data.List.Any.Membership.Properties
-- Data.List.Any.Membership instantiated with propositional equality,
-- along with some additional definitions.
open import Data.List.Any.Membership.Propositional
-- Properties related to propositional list membership
open import Data.List.Any.Membership.Propositional.Properties
-- Properties related to Any
open import Data.List.Any.Properties
-- Lists, basic types and operations
open import Data.List.Base
-- A categorical view of List
open import Data.List.Categorical
-- A data structure which keeps track of an upper bound on the number
-- of elements /not/ in a given list
open import Data.List.Countdown
-- Non-empty lists
open import Data.List.NonEmpty
-- Properties of non-empty lists
open import Data.List.NonEmpty.Properties
-- List-related properties
open import Data.List.Properties
-- Lexicographic ordering of lists
open import Data.List.Relation.NonStrictLex
-- Pointwise lifting of relations to lists
open import Data.List.Relation.Pointwise
-- Lexicographic ordering of lists
open import Data.List.Relation.StrictLex
-- Reverse view
open import Data.List.Reverse
-- M-types (the dual of W-types)
open import Data.M
-- Indexed M-types (the dual of indexed W-types aka Petersson-Synek
-- trees).
open import Data.M.Indexed
-- The Maybe type
open import Data.Maybe
-- The Maybe type and some operations
open import Data.Maybe.Base
-- Natural numbers
open import Data.Nat
-- Natural numbers, basic types and operations
open import Data.Nat.Base
-- Coprimality
open import Data.Nat.Coprimality
-- Integer division
open import Data.Nat.DivMod
-- Divisibility
open import Data.Nat.Divisibility
-- Greatest common divisor
open import Data.Nat.GCD
-- Boring lemmas used in Data.Nat.GCD and Data.Nat.Coprimality
open import Data.Nat.GCD.Lemmas
-- A generalisation of the arithmetic operations
open import Data.Nat.GeneralisedArithmetic
-- Definition of and lemmas related to "true infinitely often"
open import Data.Nat.InfinitelyOften
-- Least common multiple
open import Data.Nat.LCM
-- Primality
open import Data.Nat.Primality
-- A bunch of properties about natural number operations
open import Data.Nat.Properties
-- A bunch of properties about natural number operations
open import Data.Nat.Properties.Simple
-- Showing natural numbers
open import Data.Nat.Show
-- Transitive closures
open import Data.Plus
-- Products
open import Data.Product
-- N-ary products
open import Data.Product.N-ary
-- Properties of products
open import Data.Product.Properties
-- Lexicographic products of binary relations
open import Data.Product.Relation.NonStrictLex
-- Pointwise products of binary relations
open import Data.Product.Relation.Pointwise
-- Pointwise lifting of binary relations to sigma types
open import Data.Product.Relation.SigmaPointwise
-- Lexicographic products of binary relations
open import Data.Product.Relation.StrictLex
-- Rational numbers
open import Data.Rational
-- Properties of Rational numbers
open import Data.Rational.Properties
-- Reflexive closures
open import Data.ReflexiveClosure
-- Signs
open import Data.Sign
-- Some properties about signs
open import Data.Sign.Properties
-- The reflexive transitive closures of McBride, Norell and Jansson
open import Data.Star
-- Bounded vectors (inefficient implementation)
open import Data.Star.BoundedVec
-- Decorated star-lists
open import Data.Star.Decoration
-- Environments (heterogeneous collections)
open import Data.Star.Environment
-- Finite sets defined in terms of Data.Star
open import Data.Star.Fin
-- Lists defined in terms of Data.Star
open import Data.Star.List
-- Natural numbers defined in terms of Data.Star
open import Data.Star.Nat
-- Pointers into star-lists
open import Data.Star.Pointer
-- Some properties related to Data.Star
open import Data.Star.Properties
-- Vectors defined in terms of Data.Star
open import Data.Star.Vec
-- Streams
open import Data.Stream
-- Strings
open import Data.String
-- Strings
open import Data.String.Base
-- Sums (disjoint unions)
open import Data.Sum
-- Properties of sums (disjoint unions)
open import Data.Sum.Properties
-- Sums of binary relations
open import Data.Sum.Relation.General
-- Fixed-size tables of values, implemented as functions from 'Fin n'.
-- Similar to 'Data.Vec', but focusing on ease of retrieval instead of
-- ease of adding and removing elements.
open import Data.Table
-- Tables, basic types and operations
open import Data.Table.Base
-- Table-related properties
open import Data.Table.Properties
-- Pointwise table equality
open import Data.Table.Relation.Equality
-- Some unit types
open import Data.Unit
-- The unit type and the total relation on unit
open import Data.Unit.Base
-- Some unit types
open import Data.Unit.NonEta
-- Vectors
open import Data.Vec
-- Vectors where all elements satisfy a given property
open import Data.Vec.All
-- Properties related to All
open import Data.Vec.All.Properties
-- A categorical view of Vec
open import Data.Vec.Categorical
-- Code for converting Vec A n → B to and from n-ary functions
open import Data.Vec.N-ary
-- Some Vec-related properties
open import Data.Vec.Properties
-- Semi-heterogeneous vector equality
open import Data.Vec.Relation.Equality
-- Extensional pointwise lifting of relations to vectors
open import Data.Vec.Relation.ExtensionalPointwise
-- Inductive pointwise lifting of relations to vectors
open import Data.Vec.Relation.InductivePointwise
-- W-types
open import Data.W
-- Indexed W-types aka Petersson-Synek trees
open import Data.W.Indexed
-- Machine words
open import Data.Word
-- Type(s) used (only) when calling out to Haskell via the FFI
open import Foreign.Haskell
-- Simple combinators working solely on and with functions
open import Function
-- Bijections
open import Function.Bijection
-- Function setoids and related constructions
open import Function.Equality
-- Equivalence (coinhabitance)
open import Function.Equivalence
-- Injections
open import Function.Injection
-- Inverses
open import Function.Inverse
-- Left inverses
open import Function.LeftInverse
-- A universe which includes several kinds of "relatedness" for sets,
-- such as equivalences, surjections and bijections
open import Function.Related
-- Basic lemmas showing that various types are related (isomorphic or
-- equivalent or…)
open import Function.Related.TypeIsomorphisms
-- Surjections
open import Function.Surjection
-- IO
open import IO
-- Primitive IO: simple bindings to Haskell types and functions
open import IO.Primitive
-- An abstraction of various forms of recursion/induction
open import Induction
-- Lexicographic induction
open import Induction.Lexicographic
-- Various forms of induction for natural numbers
open import Induction.Nat
-- Well-founded induction
open import Induction.WellFounded
-- Universe levels
open import Level
-- Record types with manifest fields and "with", based on Randy
-- Pollack's "Dependently Typed Records in Type Theory"
open import Record
-- Support for reflection
open import Reflection
-- Properties of homogeneous binary relations
open import Relation.Binary
-- Some properties imply others
open import Relation.Binary.Consequences
-- Convenient syntax for equational reasoning
open import Relation.Binary.EqReasoning
-- Equivalence closures of binary relations
open import Relation.Binary.EquivalenceClosure
-- Many properties which hold for __ also hold for flip __
open import Relation.Binary.Flip
-- Heterogeneous equality
open import Relation.Binary.HeterogeneousEquality
-- Quotients for Heterogeneous equality
open import Relation.Binary.HeterogeneousEquality.Quotients
-- Example of a Quotient: as ( × / ~)
open import Relation.Binary.HeterogeneousEquality.Quotients.Examples
-- Indexed binary relations
open import Relation.Binary.Indexed
-- Induced preorders
open import Relation.Binary.InducedPreorders
-- Order-theoretic lattices
open import Relation.Binary.Lattice
-- Lexicographic ordering of lists
open import Relation.Binary.List.NonStrictLex
-- Pointwise lifting of relations to lists
open import Relation.Binary.List.Pointwise
-- Lexicographic ordering of lists
open import Relation.Binary.List.StrictLex
-- Conversion of ≤ to <, along with a number of properties
open import Relation.Binary.NonStrictToStrict
-- Many properties which hold for __ also hold for __ on f
open import Relation.Binary.On
-- Order morphisms
open import Relation.Binary.OrderMorphism
-- Convenient syntax for "equational reasoning" using a partial order
open import Relation.Binary.PartialOrderReasoning
-- Convenient syntax for "equational reasoning" using a preorder
open import Relation.Binary.PreorderReasoning
-- Lexicographic products of binary relations
open import Relation.Binary.Product.NonStrictLex
-- Pointwise products of binary relations
open import Relation.Binary.Product.Pointwise
-- Lexicographic products of binary relations
open import Relation.Binary.Product.StrictLex
-- Properties satisfied by bounded join semilattices
open import Relation.Binary.Properties.BoundedJoinSemilattice
-- Properties satisfied by bounded meet semilattices
open import Relation.Binary.Properties.BoundedMeetSemilattice
-- Properties satisfied by decidable total orders
open import Relation.Binary.Properties.DecTotalOrder
-- Properties satisfied by join semilattices
open import Relation.Binary.Properties.JoinSemilattice
-- Properties satisfied by lattices
open import Relation.Binary.Properties.Lattice
-- Properties satisfied by meet semilattices
open import Relation.Binary.Properties.MeetSemilattice
-- Properties satisfied by posets
open import Relation.Binary.Properties.Poset
-- Properties satisfied by preorders
open import Relation.Binary.Properties.Preorder
-- Properties satisfied by strict partial orders
open import Relation.Binary.Properties.StrictPartialOrder
-- Properties satisfied by strict partial orders
open import Relation.Binary.Properties.StrictTotalOrder
-- Properties satisfied by total orders
open import Relation.Binary.Properties.TotalOrder
-- Propositional (intensional) equality
open import Relation.Binary.PropositionalEquality
-- An equality postulate which evaluates
open import Relation.Binary.PropositionalEquality.TrustMe
-- Helpers intended to ease the development of "tactics" which use
-- proof by reflection
open import Relation.Binary.Reflection
-- Convenient syntax for "equational reasoning" in multiple Setoids
open import Relation.Binary.SetoidReasoning
-- Pointwise lifting of binary relations to sigma types
open import Relation.Binary.Sigma.Pointwise
-- Some simple binary relations
open import Relation.Binary.Simple
-- Convenient syntax for "equational reasoning" using a strict partial
-- order
open import Relation.Binary.StrictPartialOrderReasoning
-- Conversion of < to ≤, along with a number of properties
open import Relation.Binary.StrictToNonStrict
-- Sums of binary relations
open import Relation.Binary.Sum
-- Symmetric closures of binary relations
open import Relation.Binary.SymmetricClosure
-- Pointwise lifting of relations to vectors
open import Relation.Binary.Vec.Pointwise
-- Operations on nullary relations (like negation and decidability)
open import Relation.Nullary
-- Operations on and properties of decidable relations
open import Relation.Nullary.Decidable
-- Implications of nullary relations
open import Relation.Nullary.Implication
-- Properties related to negation
open import Relation.Nullary.Negation
-- Products of nullary relations
open import Relation.Nullary.Product
-- Sums of nullary relations
open import Relation.Nullary.Sum
-- A universe of proposition functors, along with some properties
open import Relation.Nullary.Universe
-- Unary relations
open import Relation.Unary
-- Predicate transformers
open import Relation.Unary.PredicateTransformer
-- Sizes for Agda's sized types
open import Size
-- Strictness combinators
open import Strict
-- Universes
open import Universe

View file

@ -1,31 +0,0 @@
(from Naturals.lagda)
#### Exercise (stretch: `ℕ¹`, `_+¹_`, `_*¹_`) {#Nat1}
Some mathematicians, instead of defining the naturals as starting
at zero define them as starting at one.
\begin{code}
data ℕ¹ : Set where
one : ℕ¹
suc : ℕ¹ → ℕ¹
\end{code}
In this system, there is no representation for zero, while
three is represented by `suc (suc one)`. This is our first
use of _overloaded_ constructors, that is, using the same
name for constructors of different types.
Define versions of addition and multiplication that act on
such numbers.
\begin{code}
postulate
_+¹_ : ℕ¹ → ℕ¹ → ℕ¹
_*¹_ : ℕ¹ → ℕ¹ → ℕ¹
\end{code}
In Agda, functions --- unlike constructors --- may not be overloaded,
so we have chosen `_+¹_` and `_*¹_` as names distinct from `_+_`
and `_*_`.
Confirm that two plus three is five and two times three is
six in this representation.

View file

@ -1,47 +0,0 @@
## Disjunction
In order to state totality, we need a way to formalise disjunction,
the notion that given two propositions either one or the other holds.
In Agda, we do so by declaring a suitable inductive type.
\begin{code}
data _⊎_ : Set → Set → Set where
inj₁ : ∀ {A B : Set} → A → A ⊎ B
inj₂ : ∀ {A B : Set} → B → A ⊎ B
\end{code}
This tells us that if `A` and `B` are propositions then `A ⊎ B` is
also a proposition. Evidence that `A ⊎ B` holds is either of the form
`inj₁ x`, where `x` is evidence that `A` holds, or `inj₂ y`, where
`y` is evidence that `B` holds.
We set the precedence of disjunction so that it binds less tightly than
inequality.
\begin{code}
infixr 1 _⊎_
\end{code}
Thus, `m ≤ n ⊎ n ≤ m` parses as `(m ≤ n) ⊎ (n ≤ m)`.
------------------------------------------------------------------------
I, along with many others, am a fan of Peirce's [Types and Programming
Languages][tapl], known by the acronym TAPL. One of my best students
started writing his own systems with no help from me, trained by that
book.
------------------------------------------------------------------------
\begin{code}
postulate
extensionality : ∀ {A B : Set} → {f g : A → B} → (∀ (x : A) → f x ≡ g x) → f ≡ g
extensionality2 : ∀ {A B C : Set} → {f g : A → B → C} → (∀ (x : A) (y : B) → f x y ≡ g x y) → f ≡ g
extensionality2 fxy≡gxy = extensionality (λ x → extensionality (λ y → fxy≡gxy x y))
\end{code}
------------------------------------------------------------------------
Inference
Confirm for the resulting type rules that inputs of the conclusion
(and output of any preceding hypothesis) determine inputs of each
hypothesis, and outputs of the hypotheses determine the output of the
conclusion.
------------------------------------------------------------------------

View file

@ -1,249 +0,0 @@
---
title : "FreshId: Generation of fresh names"
layout : page
permalink : /FreshId
---
Generation of fresh names, where names are strings.
Each name has a base (a string not ending in a prime)
and a suffix (a sequence of primes).
Based on an earlier version fixed by James McKinna.
\begin{code}
module FreshId where
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong; cong₂; _≢_)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.List using (List; []; _∷_; _++_; map; foldr;
reverse; replicate; length)
open import Data.List.Properties using (reverse-involutive)
open import Data.List.All using (All; []; _∷_)
open import Data.Nat using (; zero; suc; _+_; _∸_; _≤_; _⊔_)
open import Data.Nat.Properties using (≤-refl; ≤-trans; m≤m⊔n; n≤m⊔n; 1+n≰n)
open import Data.Bool using (Bool; true; false; T)
open import Data.Char using (Char)
import Data.Char as Char using (_≟_)
open import Data.String using (String; toList; fromList; _≟_;
toList∘fromList; fromList∘toList)
open import Data.Product using (_×_; proj₁; proj₂; ∃; ∃-syntax)
renaming (_,_ to ⟨_,_⟩)
open import Data.Unit using (; tt)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Function using (_∘_)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Negation using (¬?)
-- open import Relation.Nullary.Decidable using (⌊_⌋)
open import Relation.Unary using (Decidable)
import Data.Nat as Nat
import Data.String as String
import Collections
pattern [_] x = x ∷ []
pattern [_,_] x y = x ∷ y ∷ []
pattern [_,_,_] x y z = x ∷ y ∷ z ∷ []
pattern [_,_,_,_] x y z w = x ∷ y ∷ z ∷ w ∷ []
\end{code}
## DropWhile and TakeWhile for decidable predicates
\begin{code}
Head : ∀ {A : Set} → (A → Set) → List A → Set
Head P [] = ⊥
Head P (x ∷ xs) = P x
module TakeDrop {A : Set} {P : A → Set} (P? : Decidable P) where
takeWhile : List A → List A
takeWhile [] = []
takeWhile (x ∷ xs) with P? x
... | yes _ = x ∷ takeWhile xs
... | no _ = []
dropWhile : List A → List A
dropWhile [] = []
dropWhile (x ∷ xs) with P? x
... | yes _ = dropWhile xs
... | no _ = x ∷ xs
takeWhile-lemma : ∀ (xs : List A) → All P (takeWhile xs)
takeWhile-lemma [] = []
takeWhile-lemma (x ∷ xs) with P? x
... | yes px = px ∷ takeWhile-lemma xs
... | no _ = []
dropWhile-lemma : ∀ (xs : List A) → ¬ Head P (dropWhile xs)
dropWhile-lemma [] = λ()
dropWhile-lemma (x ∷ xs) with P? x
... | yes _ = dropWhile-lemma xs
... | no ¬px = ¬px
\end{code}
## Abstract operators prefix, suffix, and make
\begin{code}
Id : Set
Id = String
open Collections (Id) (String._≟_)
module IdBase
(P : Char → Set)
(P? : ∀ (c : Char) → Dec (P c))
(to : List Char → )
(from : → List Char)
(to∘from : ∀ (n : ) → to (from n) ≡ n)
(from∘to : ∀ (s : List Char) → (All P s) → from (to s) ≡ s)
where
open TakeDrop
isPrefix : String → Set
isPrefix s = ¬ Head P (reverse (toList s))
Prefix : Set
Prefix = ∃[ s ] (isPrefix s)
body : Prefix → String
body = proj₁
prop : (p : Prefix) → isPrefix (body p)
prop = proj₂
make : Prefix → → Id
make p n = fromList (toList (body p) ++ from n)
prefixS : Id → String
prefixS = fromList ∘ reverse ∘ dropWhile P? ∘ reverse ∘ toList
prefixS-lemma : ∀ (x : Id) → isPrefix (prefixS x)
prefixS-lemma x
rewrite toList∘fromList ((reverse ∘ dropWhile P? ∘ reverse ∘ toList) x)
| reverse-involutive ((dropWhile P? ∘ reverse ∘ toList) x)
= dropWhile-lemma P? ((reverse ∘ toList) x)
prefix : Id → Prefix
prefix x = ⟨ prefixS x , prefixS-lemma x ⟩
suffix : Id →
suffix = length ∘ takeWhile P? ∘ reverse ∘ toList
_≟Pr_ : ∀ (p q : Prefix) → Dec (body p ≡ body q)
p ≟Pr q = (body p) String.≟ (body q)
prefix-lemma : ∀ (p : Prefix) (n : ) → prefix (make p n) ≡ p
prefix-lemma p n = {! h (f p)!}
where
f : Prefix → List Char
f = reverse ∘ toList ∘ body
g : List Char → Prefix
g s = ⟨ (fromList ∘ reverse) s , prop p ⟩
h : ∀ (s : List Char) → prefix (make (g s) n) ≡ g s
h = ?
suffix-lemma : ∀ (p : Prefix) (n : ) → suffix (make p n) ≡ n
suffix-lemma = {!!}
make-lemma : ∀ (x : Id) → make (prefix x) (suffix x) ≡ x
make-lemma = {!!}
\end{code}
## Main lemmas
\begin{code}
module IdLemmas
(Prefix : Set)
(prefix : Id → Prefix)
(suffix : Id → )
(make : Prefix → → Id)
(body : Prefix → String)
(_≟Pr_ : ∀ (p q : Prefix) → Dec (body p ≡ body q))
(prefix-lemma : ∀ (p : Prefix) (n : ) → prefix (make p n) ≡ p)
(suffix-lemma : ∀ (p : Prefix) (n : ) → suffix (make p n) ≡ n)
(make-lemma : ∀ (x : Id) → make (prefix x) (suffix x) ≡ x)
where
bump : Prefix → Id →
bump p x with p ≟Pr prefix x
... | yes _ = suc (suffix x)
... | no _ = zero
next : Prefix → List Id →
next p = foldr _⊔_ 0 ∘ map (bump p)
fresh : Id → List Id → Id
fresh x xs = make p (next p xs)
where
p = prefix x
⊔-lemma : ∀ {p w xs} → w ∈ xs → bump p w ≤ next p xs
⊔-lemma {p} {_} {_ ∷ xs} here = m≤m⊔n _ (next p xs)
⊔-lemma {p} {w} {x ∷ xs} (there x∈) =
≤-trans (⊔-lemma {p} {w} x∈) (n≤m⊔n (bump p x) (next p xs))
bump-lemma : ∀ {p n} → bump p (make p n) ≡ suc n
bump-lemma {p} {n}
with p ≟Pr prefix (make p n)
... | yes eqn rewrite suffix-lemma p n = refl
... | no p≢ rewrite prefix-lemma p n = ⊥-elim (p≢ refl)
fresh-lemma : ∀ {w x xs} → w ∈ xs → w ≢ fresh x xs
fresh-lemma {w} {x} {xs} w∈ = h {prefix x}
where
h : ∀ {p} → w ≢ make p (next p xs)
h {p} refl
with ⊔-lemma {p} {make p (next p xs)} {xs} w∈
... | leq rewrite bump-lemma {p} {next p xs} = 1+n≰n leq
\end{code}
## Test cases
\begin{code}
prime : Char
prime = ''
isPrime : Char → Set
isPrime c = c ≡ prime
isPrime? : (c : Char) → Dec (isPrime c)
isPrime? c = c Char.≟ prime
to : List Char →
to s = length s
from : → List Char
from n = replicate n prime
to∘from : ∀ (n : ) → to (from n) ≡ n
to∘from = {!!}
from∘to : ∀ (s : List Char) → All isPrime s → from (to s) ≡ s
from∘to = {!!}
open IdBase (isPrime) (isPrime?) (to) (from) (to∘from) (from∘to)
open IdLemmas (Prefix) (prefix) (suffix) (make) (body) (_≟Pr_)
(prefix-lemma) (suffix-lemma) (make-lemma)
x0 = "x"
x1 = "x"
x2 = "x"
x3 = "x"
y0 = "y"
y1 = "y"
zs0 = "zs"
zs1 = "zs"
zs2 = "zs"
_ : fresh x0 [ x0 , x1 , x2 , zs2 ] ≡ x3
_ = refl
-- fresh "x" [ "x" , "x" , "x" , "y" ] ≡ "x"
_ : fresh zs0 [ x0 , x1 , x2 , zs1 ] ≡ zs2
_ = refl
\end{code}

View file

@ -1,78 +0,0 @@
---
title : "FreshIdConor: Generation of fresh names"
layout : page
permalink : /FreshIdConor
---
\begin{code}
module FreshIdConor where
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong; cong₂; _≢_)
open Eq.≡-Reasoning
open import Data.Empty using (⊥; ⊥-elim)
open import Data.List
using (List; []; _∷_; _++_; map; foldr; replicate; length; _∷ʳ_)
renaming (reverse to rev)
open import Data.List.Properties
using (++-assoc; ++-identityʳ)
renaming (unfold-reverse to revʳ;
reverse-++-commute to rev-++;
reverse-involutive to rev-inv)
open import Data.List.All using (All; []; _∷_)
open import Function using (_∘_)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Negation using (¬?)
open import Relation.Unary using (Decidable)
pattern [_] x = x ∷ []
pattern [_,_] x y = x ∷ y ∷ []
pattern [_,_,_] x y z = x ∷ y ∷ z ∷ []
pattern [_,_,_,_] x y z w = x ∷ y ∷ z ∷ w ∷ []
\end{code}
## Conor's Break works left-to-right
\begin{code}
module Break {A : Set} where
data Break (P : A → Set) : List A → Set where
none : ∀ {xs} → All P xs → Break P xs
some : ∀ {xs y zs} → All P xs → ¬ P y → Break P (xs ++ [ y ] ++ zs)
break : ∀ {P : A → Set} (P? : Decidable P) → (xs : List A) → Break P xs
break P? [] = none []
break P? (w ∷ ws) with P? w
... | no ¬Pw = some [] ¬Pw
... | yes Pw with break P? ws
... | none Pws = none (Pw ∷ Pws)
... | some Pws ¬Py = some (Pw ∷ Pws) ¬Py
\end{code}
## But we want to break lists right-to-left
\begin{code}
module RevBreak {A : Set} where
open Break {A}
data RevBreak (P : A → Set) : List A → Set where
rnone : ∀ {xs} → All P (rev xs) → RevBreak P xs
rsome : ∀ {zs y xs} → ¬ P y → All P (rev xs) → RevBreak P (zs ++ [ y ] ++ xs)
-- I'd like to do something along the following lines ...
revBreak : ∀ {P : A → Set} (P? : Decidable P) → (xs : List A) → RevBreak P xs
revBreak P? ws with break P? (rev ws)
... | none {xs} Pxs = ?
-- rewrite rev-inv ws
-- = rnone {xs = rev xs} Pxs
... | some {xs} {y} {zs} Pxs ¬Py = ?
-- rewrite rev-inv ?xs | rev-inv ?zs -- not clear how to bind ?xs and ?zs
-- = rsome {zs = rev zs} {y = y} {xs = rev xs} ¬Py Pxs
-- ... but even the pattern matching gets into trouble
-- It complains that it cannot be sure that
-- xs ++ [ y ] ++ zs = rev ws
-- Doesn't this property follow immediately from the fact that break typechecks?
\end{code}

View file

@ -1,99 +0,0 @@
---
title : "FreshUnstuck: Generation of fresh names with strings"
layout : page
permalink : /FreshUnstuck
---
Generation of fresh names, where names are string-integer pairs.
Fixed by James McKinna.
\begin{code}
module FreshUnstuck where
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong; cong₂; _≢_)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.List using (List; []; _∷_; _++_; map; foldr; filter)
open import Data.Nat using (; zero; suc; _+_; _∸_; _≤_; _⊔_)
open import Data.Nat.Properties using (≤-refl; ≤-trans; m≤m⊔n; n≤m⊔n; 1+n≰n)
open import Data.String using (String)
open import Data.Product using (_×_; proj₁; proj₂) renaming (_,_ to ⟨_,_⟩)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Function using (_∘_)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Negation using (¬?)
import Data.Nat as Nat
import Data.String as String
data Id : Set where
id : String → → Id
_≟_ : ∀ (x y : Id) → Dec (x ≡ y)
id s m ≟ id t n with s String.≟ t | m Nat.≟ n
... | yes refl | yes refl = yes refl
... | yes refl | no m≢n = no (λ {refl → m≢n refl})
... | no s≢t | _ = no (λ {refl → s≢t refl})
infix 4 _∈_
data _∈_ : Id → List Id → Set where
here : ∀ {x xs} →
----------
x ∈ x ∷ xs
there : ∀ {w x xs} →
w ∈ xs →
----------
w ∈ x ∷ xs
bump : String → Id →
bump s (id t n) with s String.≟ t
... | yes refl = suc n
... | no _ = 0
next : String → List Id →
next s = foldr _⊔_ 0 ∘ map (bump s)
⊔-lemma : ∀ {s w xs} → w ∈ xs → bump s w ≤ next s xs
⊔-lemma {s} {_} {_ ∷ xs} here = m≤m⊔n _ (next s xs)
⊔-lemma {s} {w} {x ∷ xs} (there x∈) = ≤-trans (⊔-lemma {s} {w} x∈) (n≤m⊔n (bump s x) (next s xs))
fresh : Id → List Id → Id
fresh (id s _) xs = id s (next s xs)
id-invert-str : ∀ {s t m n} → (id s m) ≡ (id t n) → t ≡ s
id-invert-str refl = refl
id-invert-nat : ∀ {s t m n} → (id s m) ≡ (id t n) → n ≡ m
id-invert-nat refl = refl
not-suc-le : ∀ {n} → ¬ (suc n ≤ n)
not-suc-le {zero} ()
not-suc-le {suc n} (Nat.s≤s sn≤n) = not-suc-le sn≤n
fresh-lemma : ∀ {w x xs} → w ∈ xs → w ≢ fresh x xs
fresh-lemma {w @ (id t n)} {x @ (id s _)} {xs} w∈ w≢fr
with s String.≟ t | ⊔-lemma {s} {w} {xs} w∈
... | yes refl | prf rewrite id-invert-nat w≢fr = not-suc-le prf
... | no ¬p | _ = ¬p (id-invert-str w≢fr)
pattern [_] x = x ∷ []
pattern [_,_] x y = x ∷ y ∷ []
pattern [_,_,_] x y z = x ∷ y ∷ z ∷ []
pattern [_,_,_,_] x y z w = x ∷ y ∷ z ∷ w ∷ []
x0 = id "x" 0
x1 = id "x" 1
x2 = id "x" 2
x3 = id "x" 3
y0 = id "y" 0
y1 = id "y" 1
z4 = id "z" 4
_ : fresh x0 [ x0 , x1 , x2 , z4 ] ≡ x3
_ = refl
_ : fresh y1 [ x0 , x1 , x2 , z4 ] ≡ y0
_ = refl
\end{code}

View file

@ -1,165 +0,0 @@
## A brief history of logic
Formulations of logic go back to Aristotle in the third century BCE,
but the modern approach to symbolic logic did not get started until
the 18th century with the work of Boole. Universal and existential
quantification were introduced by Frege and Pierce, and Peano
introduced the notations `(x)A` and `(∃x)A` to stand for them.
Peano's notation was adopted by Russell and Whitehead for use in
*Principia Mathematica*.
The formulation of logic most widely used today is *Natural
Deduction*, introduced by Gerhard Gentzen in 1935, in what was in
effect his doctoral dissertation. Gentzen's major insight was to
write the rules of logic in *introduction* and *elimination* pairs.
By the way, that same work of Gentzen also introduced Sequent
Calculus, the second most widely used formulation of logic, and the
symbol ∀ to mean *for all*---so there is a goal for you if you are
about to write your doctoral dissertation!
## Natural Deduction
Here are the inference rules for Natural Deduction annotated with Agda terms.
M : A N : B
---------------- ×-I
(M , N) : A × B
L : A × B
--------- ×-E₁
fst L : A
L : A × B
--------- ×-E₂
snd L : B
M : A
-------------- ⊎-I₁
inj₁ M : A ⊎ B
N : B
-------------- ⊎-I₂
inj₂ N : A ⊎ B
(x : A) (y : B)
L : A ⊎ B Px : C Qy : C
---------------------------------------- ⊎-E
(λ { inj₁ x → Px ; inj₂ y → Qy }) L : C
(x : A)
Nx : B
------------------- →-I
(λ x → Nx) : A → B
L : A → B M : A
------------------- →-E
L M : B
(x : A)
Nx : Bx
----------------------------- ∀-I
(λ x → Nx) : ∀ (x : A) → Bx
L : ∀ (x : A) → Bx M : A
---------------------------- ∀-E
L M : Bx [ x := M ]
M : A Nx [ x := M ] : Bx [ x := M ]
-------------------------------------- ∃-I
(M , Nx) : ∃ A (λ x → Bx)
(x : A, y : Bx)
L : ∃ A (λ x → Bx) Pxy : C
------------------------------------ ∃-E
(λ { (x , y) → Pxy }) L : C
[These rules---especially toward the end---are rather complicated.
Is this really the best way to explain this material? Maybe it
is better to give a less formal explanation for now, and introduce
the more formal rules when giving a model of Barendregt's generalised
lambda calculus toward the end of the book, if I get that far.]
These rules differ only slightly from Gentzen's original. We
have written `A × B` where Gentzen wrote `A & B`, for reasons
that will become clear later.
## Natural deduction as a logic (no terms)
We adopt an idea from Gentzen's sequent calculus, writing `Γ ⊢ A` to
make explicit the set of assumptions `Γ` from which proposition `A`
follows.
Γ ⊢ A
Γ ⊢ B
--------- ×-I
Γ ⊢ A × B
Γ ⊢ A × B
--------- ×-E₁
Γ ⊢ A
Γ ⊢ A × B
--------- ×-E₁₂
Γ ⊢ B
----- -I
Γ ⊢
Γ ⊢ A
--------- +-I₁
Γ ⊢ A ⊎ B
Γ ⊢ B
--------- +-I₂
Γ ⊢ A ⊎ B
Γ ⊢ A ⊎ B
Γ , A ⊢ C
Γ , B ⊢ C
----------- +-E
Γ ⊢ C
Γ ⊢ ⊥
----- ⊥-E
Γ ⊢ C
Γ , A ⊢ B
--------- →-I
Γ ⊢ A → B
Γ ⊢ A → B
Γ ⊢ A
--------- →-E
Γ ⊢ B
Γ , A ⊢ ⊥
--------- ¬-I
Γ ⊢ ¬ A
Γ ⊢ ¬ A
Γ ⊢ A
-------- ¬-E
Γ ⊢ ⊥
Γ , x : A ⊢ B
------------------ ∀-I (x does not appear free in Γ)
Γ ⊢ ∀ (x : A) → B
Γ ⊢ ∀ (x : A) → B
Γ ⊢ M : A
----------------- ∀-E
Γ ⊢ B [ x := M ]
Γ ⊢ M : A
Γ ⊢ B [ x := M ]
----------------- ∃-I
Γ ⊢ ∃ [ x : A ] B
Γ ⊢ ∃ [ x : A ] B
Γ , x : A ⊢ C
----------------- ∃-E (x does not appear free in Γ or C)
Γ ⊢ C

View file

@ -1,40 +0,0 @@
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong; cong₂; _≢_)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.List using (List; []; _∷_; dropWhile)
open import Data.Char using (Char)
open import Data.Bool using (Bool; true; false)
import Data.Char as Char using (_≟_)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Decidable using (⌊_⌋)
data Head {A : Set} (P : A Bool) : List A Set where
head : (c : A) (s : List A) P c true Head P (c s)
prime : Char
prime = ''
isPrime : Char Bool
isPrime c = c Char.≟ prime
head-lemma : (s : List Char) ¬ Head isPrime (dropWhile isPrime s)
head-lemma [] = λ()
head-lemma (c s) with isPrime c
... | true = head-lemma s
... | false = ¬h
where
¬h : ¬ Head isPrime (c s)
¬h (head c s eqn) = {!!}
{-
Goal:
————————————————————————————————————————————————————————————
s : List Char
c : Char
eqn : (c Char.≟ '' | .Agda.Builtin.Char.primCharEquality c '')
true
s : List Char
c : Char
-}

View file

@ -1,28 +0,0 @@
### Identifier maps
\begin{code}
_∈?_ : ∀ (x : Id) → (xs : List Id) → Dec (x ∈ xs)
x ∈? xs = {!!}
data IdMap : Set where
make : ∀ (xs : List Id) → (φ : ∀ {x} → x ∈ xs → Term) → IdMap
default : List Id → IdMap
default xs = make xs φ
where
φ : ∀ {x : Id} (x∈ : x ∈ xs) → Term
φ {x} x∈ = ` x
∅ : IdMap
∅ = make [] (λ())
infixl 5 _,_↦_
_,_↦_ : IdMap → Id → Term → IdMap
make xs φ , x ↦ M = make xs φ′
where
xs = x ∷ xs
φ′ : ∀ {x} → x ∈ xs → Term
φ′ here = M
φ′ (there x∈) = φ x∈
\end{code}

View file

@ -1,978 +0,0 @@
---
title : "Inference: Bidirectional type inference"
layout : page
permalink : /Inference/
---
\begin{code}
module plfa.Inference where
\end{code}
So far in our development, type derivations for the corresponding
term have been provided by fiat.
In Chapter [Lambda]({{ site.baseurl }}{% link out/plfa/Lambda.md %})
type derivations were given separately from the term, while
in Chapter [DeBruijn]({{ site.baseurl }}{% link out/plfa/DeBruijn.md %})
the type derivation was inherently part of the term.
In practice, one often writes down a term with a few decorations and
applies an algorithm to _infer_ the corresponding type derivation.
Indeed, this is exactly what happens in Agda: we specify the types for
top-level function declarations, and the remaining type information is
inferred from this. The style of inference used is descended from an
algorithm called _bidirectional_ type inference, which will be
presented in this chapter.
This chapter ties our previous developements together. We begin with
a term with some type annotations, quite close to the raw terms of
Chapter [Lambda]({{ site.baseurl }}{% link out/plfa/Lambda.md %}),
and from it we compute a term with inherent types, in the style of
Chapter [DeBruijn]({{ site.baseurl }}{% link out/plfa/DeBruijn.md %}).
## Introduction: Inference rules as algorithms {#algorithms}
In the calculus we have considered so far, a term may have more than
one type. For example,
(ƛ x ⇒ x) ⦂ (A ⇒ A)
for _every_ type `A`. We start by considering a small language for
lambda terms where every term has a unique type. All we need do
is decorate each abstraction term with the type of its argument.
This gives us the grammar:
L, M, N ::= decorated terms
x variable
ƛ x ⦂ A ⇒ N abstraction (decorated)
L · M application
Each of the associated type rules can be read as an algorithm for
type checking. For each typing judgment, we label each position
as either an _input_ or an _output_.
For the judgment
Γ ∋ x ⦂ A
we take the context `Γ` and the variable `x` as inputs, and the
type `A` as output. Consider the rules:
----------------- Z
Γ , x ⦂ A ∋ x ⦂ A
Γ ∋ y ⦂ B
----------------- S
Γ , x ⦂ A ∋ y ⦂ B
From the inputs we can determine which rule applies: if the last
variable in the context matches the given variable then the first
rule applies, else the second. (For de Bruijn indices, it is even
easier: zero matches the first rule and successor the second.)
For the first rule, the output type can be read off as the last
type in the input context. For the second rule, the inputs of the
conclusion determine the inputs of the hypothesis, and the ouptut
of the hypothesis determines the output of the conclusion.
For the judgment
Γ ⊢ M ⦂ A
we take the context `Γ` and term `M` as inputs, and the type `A`
as ouput. Consider the rules:
Γ ∋ x ⦂ A
-----------
Γ ⊢ ` x ⦂ A
Γ , x ⦂ A ⊢ N ⦂ B
---------------------------
Γ ⊢ (ƛ x ⦂ A ⇒ N) ⦂ (A ⇒ B)
Γ ⊢ L ⦂ A ⇒ B
Γ ⊢ M ⦂ A
A ≡ A
-------------
Γ ⊢ L · M ⦂ B
The term input determines which rule applies: variables use the first
rule, abstractions the second, and applications the third. In such a
situation, we say the rules are _syntax directed_. For the
variable rule, the inputs of the conclusion determine the inputs of
the hypothesis, and the output of the hypothesis determines the output
of the conclusion. Same for the abstraction rule — the bound variable
and argument type of the abstraction are carried into the context of
the hypothesis, and this is why we added the argument type to the
abstraction. For the application rule, we add a third hypothesis to
check whether domain of the function matches the type of the argument;
this judgment is decidable when both types are given as inputs. The
inputs of the conclusion determine the inputs of the first two
hypotheses, the outputs of the first two hypotheses determine the
inputs of the third hypothesis, and the output of the first hypothesis
determines the output of the conclusion.
Converting the above to an algorithm is straightforwart, as is adding
naturals and fixpoint. We omit the details. Instead, we consider a
detailed description of an approach that requires less obtrusive
decoration. The idea is to break the normal typing judgment into two
judgments, one that produces the type as an output (as above), and
another that takes it as an input.
## Synthesising and inheriting types
In addition to the lookup judgment for variables, which will remain
as before, we now have two judgments for the type of the term.
Γ ⊢ M ↑ A
Γ ⊢ M ↓ A
The first of these _synthesises_ the type of a term, as before,
while the second _inherits_ the type. In the first, the context
and term are inputs and the type is an output, while in the
second, all three of the context, term, and type are inputs.
Which terms use synthesis and which inheritance? Our approach will be
that the main term in a _deconstructor_ are typed via synthesis while
_constructors_ a typed via inheritance. For instance, the function in
an application is typed via synthesis, but an abstraction is typed via
inheritance. The inherited type in an abstraction term serves the
same purpose as the argument type decoration of the previous section.
Terms that deconstruct a value of a type always have a main term
(supplying an argument of the required type) and often have
side-terms. For application, the main term supplies the function and
the side term supplies the argument. For case terms, the main term
supplies a natural and the side terms are the two branches. In a
deconstructor, the main term will be typed using synthesis but the
side terms will be typed using inheritance. As we will see, this
leads naturally to an application as a whole being typed by synthesis,
while a case term as a whole will be typed by inheritance.
Variables are naturally typed by synthesis, since we can look up
the type in the input context. Fixed points will be naturally
typed by inheritance.
In order to get a syntax-directed type system we break terms into two
kinds, `Term⁺` and `Term⁻, which are typed by synthesis and
inheritance, respectively. At some points, we may expect a subterm to
be typed by synthesis when in fact it is typed by inheritance, or
vice-versa, and this gives rise to two new term forms.
For instance, we said above that the argument of an application is
typed by inheritance and that variables are typed by synthesis, giving
a mismatch if the argument of an application is a variable. Hence, we
need a way to treat a synthesized term as if it is inherited. We
introduce a new term form, `M ↑` for this purpose. The typing judgment
checks that the inherited and synthesised types match.
Similarly, we said above that the function of an application is typed
by synthesis and that abstractions are typed by inheritance, giving a
mismatch if the function of an application is a variable. Hence, we
need a way to treat an inherited term as if it is synthesised. We
introduce a new term form `M ↓ A` for this purpose. The typing
judgment returns `A` as the synthesized type of the term as a whole,
as well as using it as the inherited type for `M`.
The term form `M ↓ A` represents the only place terms need to
be decorated with types. It only appears when switching from
synthesis to inheritance, that is, when a term that _deconstructs_
a value of a type contains a term that _constructs_ a value of a
type, in other words, a place where a β reduction will occur.
Typically, we will find that such declarations are only required
on top level declarations.
We can extract the grammar for terms from the above:
L⁺, M⁺, N⁺ ::= terms with synthesized type
x variable
L⁺ · M- application
M⁻ ↓ A switch to inherited
L⁻, M⁻, N⁻ ::= terms with inherited type
ƛ x ⇒ N abstraction
`zero zero
`suc M⁻ successor
case L⁺ [zero⇒ M⁻ |suc x ⇒ N⁻ ] case
μ x ⇒ N fixpoint
M ↑ switch to synthesized
With the grammar in hand, we can begin the formal development.
## Imports
\begin{code}
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong; cong₂; _≢_)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.List using (List; []; _∷_; map; foldr; filter; length)
open import Data.Nat using (; zero; suc; _+_)
open import Data.String using (String; _≟_; _++_)
open import Data.Product
using (_×_; proj₁; proj₂; ∃; ∃-syntax)
renaming (_,_ to ⟨_,_⟩)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Function using (_∘_)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Negation using (¬?)
pattern [_] w = w ∷ []
pattern [_,_] w x = w ∷ x ∷ []
pattern [_,_,_] w x y = w ∷ x ∷ y ∷ []
pattern [_,_,_,_] w x y z = w ∷ x ∷ y ∷ z ∷ []
\end{code}
Once we have a type derivation, it will be easy to construct
from it the inherently typed representation. In order that we
can compare with our previous development, we import
module `pfla.DeBruijn`.
\begin{code}
open import plfa.DeBruijn as DB using (Type; `; _⇒_)
\end{code}
The phrase `as DB` allows us to refer to definitions
from that module as, for instance, `DB._⊢_`, which is
invoked as `Γ DB.⊢ A`, where `Γ` has type
`DB.Context` and `A` has type `DB.Type`. We also import
`Type` and its constructors directly, so the latter may
also be referred to as just `Type`.
## Syntax
First, we get all our infix declarations out of the way.
We list separately operators for judgments and terms.
\begin{code}
infix 4 _∋_⦂_
infix 4 _⊢_↑_
infix 4 _⊢_↓_
infixl 5 _,_⦂_
infix 5 ƛ_⇒_
infix 5 μ_⇒_
infix 6 _↑
infix 6 _↓_
infixl 7 _·_
infix 8 `suc_
infix 9 `_
\end{code}
Identifiers are as before.
\begin{code}
Id : Set
Id = String
\end{code}
And so are contexts. (Recall that `Type` is imported from
[DeBruijn]({{ site.baseurl }}{% link out/plfa/DeBruijn.md %}).)
\begin{code}
data Context : Set where
∅ : Context
_,_⦂_ : Context → Id → Type → Context
\end{code}
The syntax of terms is defined by mutual recursion.
We use `Term⁺` and `Term⁻`
for terms with synthesized and inherited types, respectively.
Note the inclusion of the switching forms,
`M ↓ A` and `M ↑`.
\begin{code}
data Term⁺ : Set
data Term⁻ : Set
data Term⁺ where
`_ : Id → Term⁺
_·_ : Term⁺ → Term⁻ → Term⁺
_↓_ : Term⁻ → Type → Term⁺
data Term⁻ where
ƛ_⇒_ : Id → Term⁻ → Term⁻
`zero : Term⁻
`suc_ : Term⁻ → Term⁻
`case_[zero⇒_|suc_⇒_] : Term⁺ → Term⁻ → Id → Term⁻ → Term⁻
μ_⇒_ : Id → Term⁻ → Term⁻
_↑ : Term⁺ → Term⁻
\end{code}
The choice as to whether each term is synthesized or
inherited follows the discussion above, and can be read
off from the preceding (informal) grammar. Main terms in
deconstructors synthesise, constructors and side terms
in deconstructors inherit.
## Example terms
We can recreate the examples from preceding chapters.
First, computing two plus two on naturals.
\begin{code}
two : Term⁻
two = `suc (`suc `zero)
plus : Term⁺
plus = (μ "p" ⇒ ƛ "m" ⇒ ƛ "n" ⇒
`case (` "m") [zero⇒ ` "n" ↑
|suc "m" ⇒ `suc (` "p" · (` "m" ↑) · (` "n" ↑) ↑) ])
↓ ` ⇒ ` ⇒ `
2+2 : Term⁺
2+2 = plus · two · two
\end{code}
The only change is to decorate with down and up arrows as required.
The only type decoration required is for `plus`.
Next, computing two plus two with Church numerals.
\begin{code}
Ch : Type
Ch = (` ⇒ `) ⇒ ` ⇒ `
twoᶜ : Term⁻
twoᶜ = (ƛ "s" ⇒ ƛ "z" ⇒ ` "s" · (` "s" · (` "z" ↑) ↑) ↑)
plusᶜ : Term⁺
plusᶜ = (ƛ "m" ⇒ ƛ "n" ⇒ ƛ "s" ⇒ ƛ "z" ⇒
` "m" · (` "s" ↑) · (` "n" · (` "s" ↑) · (` "z" ↑) ↑) ↑)
↓ Ch ⇒ Ch ⇒ Ch
sucᶜ : Term⁻
sucᶜ = ƛ "x" ⇒ `suc (` "x" ↑)
2+2ᶜ : Term⁺
2+2ᶜ = plusᶜ · twoᶜ · twoᶜ · sucᶜ · `zero
\end{code}
The only type decoration required is for `plusᶜ`. One is not even
required for `sucᶜ`, which inherits its type as an argument of `plusᶜ`.
## Bidirectional type checking
The typing rules for variables are as in
[Lambda]({{ site.baseurl }}{% link out/plfa/Lambda.md %}).
\begin{code}
data _∋_⦂_ : Context → Id → Type → Set where
Z : ∀ {Γ x A}
--------------------
→ Γ , x ⦂ A ∋ x ⦂ A
S : ∀ {Γ x y A B}
→ x ≢ y
→ Γ ∋ x ⦂ A
-----------------
→ Γ , y ⦂ B ∋ x ⦂ A
\end{code}
As with syntax, the judgments for synthesizing
and inheriting types are mutually recursive.
\begin{code}
data _⊢_↑_ : Context → Term⁺ → Type → Set
data _⊢_↓_ : Context → Term⁻ → Type → Set
data _⊢_↑_ where
Ax : ∀ {Γ A x}
→ Γ ∋ x ⦂ A
-----------
→ Γ ⊢ ` x ↑ A
_·_ : ∀ {Γ L M A B}
→ Γ ⊢ L ↑ A ⇒ B
→ Γ ⊢ M ↓ A
-------------
→ Γ ⊢ L · M ↑ B
⊢↓ : ∀ {Γ M A}
→ Γ ⊢ M ↓ A
---------------
→ Γ ⊢ (M ↓ A) ↑ A
data _⊢_↓_ where
⊢ƛ : ∀ {Γ x N A B}
→ Γ , x ⦂ A ⊢ N ↓ B
-------------------
→ Γ ⊢ ƛ x ⇒ N ↓ A ⇒ B
⊢zero : ∀ {Γ}
--------------
→ Γ ⊢ `zero ↓ `
⊢suc : ∀ {Γ M}
→ Γ ⊢ M ↓ `
---------------
→ Γ ⊢ `suc M ↓ `
⊢case : ∀ {Γ L M x N A}
→ Γ ⊢ L ↑ `
→ Γ ⊢ M ↓ A
→ Γ , x ⦂ ` ⊢ N ↓ A
-------------------------------------
→ Γ ⊢ `case L [zero⇒ M |suc x ⇒ N ] ↓ A
⊢μ : ∀ {Γ x N A}
→ Γ , x ⦂ A ⊢ N ↓ A
-----------------
→ Γ ⊢ μ x ⇒ N ↓ A
⊢↑ : ∀ {Γ M A B}
→ Γ ⊢ M ↑ A
→ A ≡ B
-------------
→ Γ ⊢ (M ↑) ↓ B
\end{code}
We follow the same convention as
Chapter [Lambda]({{ site.baseurl }}{% link out/plfa/Lambda.md %}),
prefacing the constructor with `⊢` to derive the name of the
corresponding type rule.
The most interesting rules are those for `⊢↑` and `⊢↓`.
The former both passes the type decoration as the inherited type and returns
it as the synthesised type. The latter takes the synthesised type and the
inherited type and confirms they are identical. (It should remind you of
the equality test in the application rule in the first
[section]({{ site.baseurl }}{% link out/plfa/Inference.md %}/#algorithms).)
## Type equality
The rule for `M ↑` requires the ability to decide whether two types
are equal. It is straightforward to code.
\begin{code}
_≟Tp_ : (A B : Type) → Dec (A ≡ B)
` ≟Tp ` = yes refl
` ≟Tp (A ⇒ B) = no λ()
(A ⇒ B) ≟Tp ` = no λ()
(A ⇒ B) ≟Tp (A ⇒ B)
with A ≟Tp A | B ≟Tp B
... | no A≢ | _ = no λ{refl → A≢ refl}
... | yes _ | no B≢ = no λ{refl → B≢ refl}
... | yes refl | yes refl = yes refl
\end{code}
## Type inference monad
One construct you will find in the functional programmer's toolbox
is the _monad_, which can describe error handling, state, and
many other computational effects. Here we introduce a monad to
manage error messages in our inferencer.
Type inference will either yield a value (such as a synthesized type)
or an error message (for instance, when inherited and synthesized
types differ). An error message is given by a string.
\begin{code}
Message : Set
Message = String
\end{code}
The type `I A` represents the result of inference, where `A` is an
arbitrary Agda set representing the type of the result returned;
in our case, we will return evidence for type judgments.
Note here `A` ranges over
Agda sets rather than types of our target lambda calculus.
\begin{code}
data I (A : Set) : Set where
error⁺ : Message → Term⁺ → List Type → I A
error⁻ : Message → Term⁻ → List Type → I A
return : A → I A
\end{code}
There are three possible constructors, two for errors and one to
return a value. An error also takes a message, a term, and a list of
types relevant to the error; there is one variant for each sort of
term. Return embeds values of type `A` into the type `I A`.
We need a way to compose functions that may return error messages,
and monads provide the required structure.
A monad is equipped with an operation, usually written `_>>=_`
and pronounced _bind_.
\begin{code}
_>>=_ : ∀ {A B : Set} → I A → (A → I B) → I B
error⁺ msg M As >>= k = error⁺ msg M As
error⁻ msg M As >>= k = error⁻ msg M As
return x >>= k = k x
\end{code}
If the left argument raises an error, the bind term raises
the same error. If the right argument returns a value, the
bind term applies its left argument to that value.
There is a conflict in our conventions: here `A` ranges over Agda
sets, while `As` ranges over types of our target lambda calculus.
A monad is a bit like a monoid, in that it should satisfy something
akin to a left and right identity law and an associativity law. The
role of the identity is played by `return`. In our case,
all three laws are trivial to prove.
\begin{code}
identityˡ : ∀ {A B : Set} (x : A) (k : A → I B) → return x >>= k ≡ k x
identityˡ x k = refl
identityʳ : ∀ {A B : Set} (m : I A) → m >>= (λ x → return x) ≡ m
identityʳ (error⁺ _ _ _) = refl
identityʳ (error⁻ _ _ _) = refl
identityʳ (return _) = refl
assoc : ∀ {X Y Z : Set} (m : I X) (k : X → I Y) (h : Y → I Z) →
(m >>= λ x → k x) >>= (λ y → h y) ≡ m >>= (λ x → k x >>= (λ y → h y))
assoc (error⁺ _ _ _) k h = refl
assoc (error⁻ _ _ _) k h = refl
assoc (return _) k h = refl
\end{code}
The left-hand side of the associativity law can be abbreviated to
`(m >>= k) >>= h`, but it is written as above to make clear that
the law is about re-arranging parentheses.
## Syntactic sugar for monads
Agda has built-in syntax to support the use of monads, which
translates into applications of the binding operator `_>>=_`. Such
translation of one construct into another is referred to as _syntactic
sugar_, and we will apply it to sweeten our subsequent presentation.
Writing
do x ← M
N
translates to
M >>= λ x → N
Here `x` is an Agda variable and `M` and `N` are terms of Agda
(rather than of our target lambda calculus). Applying the notations
we have learned to Agda itself, we can write
Γ ⊢ M : I A
Γ , x : A ⊢ N : I B
-------------------
Γ ⊢ (do x ← M
N) : I B
That is, term `M` has type `I A`, variable `x` has type `A`, and term
`N` has type `I B` and may contain `x` as a free variable, and the
whole term has type `I B`. One can read this as follows:
Evaluate `M`; if it fails, yield the error message; if it succeeds,
bind `x` to the value returned and evaluate `N`.
Similarly, writing
do x ← L
y ← M
N
translates to
L >>= λ x → (M >>= λ y → N)
If `x` does not appear free in `N`, then by the associative law we
can parenthesise either way; though `x` may appear free in `N`.
We can describe the types as before:
Γ ⊢ L : I A
Γ , x : A ⊢ M : I B
Γ , x : A , y : B ⊢ N : I C
---------------------------
Γ ⊢ (do x ← L
y ← M
N) : I C
We can read this as: Evaluate `L`; if it fails, yield the error
message; if it succeeds, bind `x` the the value returned and
evaluate `M`; if it fails, yield the error message; if it
succeeds, bind `y` to the value returned and evaluate `N`.
Additionally, writing
do P ← L
where Q → M
N
translates to
L >>= λ{ P → N ; Q → M }
where `P`, `Q` are Agda patterns, and `L`, `M`, `N` are Agda terms.
Extending our notation to allow a pattern to the left of a turnstyle, we have:
Γ ⊢ L : I A
Γ , P : A ⊢ N : I B
Γ , Q : A ⊢ M : I B
---------------------------
Γ ⊢ (do P ← L
where Q → M
N) : I B
One can read this form as follows: Evaluate `M`; if it fails, yield
the error message; if it succeeds, match `P` to the value returned and
evaluate `N` (which may contain variables matched by `P`); otherwise
match `Q` to the value returned and evaluate `M` (which may contain
variables matched by `Q`); one of `P` and `Q` must match.
The notations extend to any number of bindings or patterns. Thus,
do x₁ ← M₁
...
xₙ ← Mₙ
N
translates to
M₁ >>= (λ x₁ → ... Mₙ >>= (λ xₙ → N)...)
and
do P ← L
where Q₁ → M₁
...
Qₙ → Mₙ
N
translates to
L >>= λ{ P → N ; Q₁ → M₁ ; ... ; Qₙ → Mₙ }
We will apply this sugar to sweeten our subsequent presentation.
## Lookup type of a variable in the context
Given a context `Γ` and a variable `x`, we return a type `A` and
evidence that `Γ ∋ x ⦂ A`. If `x` does not appear in `Γ`, then
we raise an error.
\begin{code}
lookup : ∀ (Γ : Context) (x : Id) → I (∃[ A ](Γ ∋ x ⦂ A))
lookup ∅ x =
error⁺ "variable not bound" (` x) []
lookup (Γ , y ⦂ B) x with x ≟ y
... | yes refl =
return ⟨ B , Z ⟩
... | no x≢y =
do ⟨ A , ⊢x ⟩ ← lookup Γ x
return ⟨ A , S x≢y ⊢x ⟩
\end{code}
There are three cases.
* If the context is empty, we raise an error.
* If the variable appears in the most recent binding, we
return its corresponding type.
* If the variable does not appear in the most recent binding,
we recurse.
## Synthesize and inherit types
The table has been set, the starters consumed, and we are ready
for the main course. We have two mutually recursive functions,
one for synthesis and one for inheritance. Synthesis is given
a context `Γ` and a synthesis term `M` and
returns a type `A` and evidence that `Γ ⊢ M ↑ A`.
Inheritance is given a context `Γ`, an inheritance term `M`,
and a type `A` and reuturns evidence that `Γ ⊢ M ↓ A`.
An error is raised when appropriate.
\begin{code}
synthesize : ∀ (Γ : Context) (M : Term⁺) → I (∃[ A ](Γ ⊢ M ↑ A))
inherit : ∀ (Γ : Context) (M : Term⁻) (A : Type) → I (Γ ⊢ M ↓ A)
\end{code}
We first consider the code for synthesis.
\begin{code}
synthesize Γ (` x) =
do ⟨ A , ⊢x ⟩ ← lookup Γ x
return ⟨ A , Ax ⊢x ⟩
synthesize Γ (L · M) =
do ⟨ A ⇒ B , ⊢L ⟩ ← synthesize Γ L
where ⟨ ` , _ ⟩ → error⁺ "must apply function" (L · M) []
⊢M ← inherit Γ M A
return ⟨ B , ⊢L · ⊢M ⟩
synthesize Γ (M ↓ A) =
do ⊢M ← inherit Γ M A
return ⟨ A , ⊢↓ ⊢M ⟩
\end{code}
There are three cases.
* If the term is a variable, we use lookup as defined above.
* If the term is an application, we recurse to synthesize the type of
the function. We check that the synthesied type is a function of
the form `A ⇒ B`. If it is not (e.g., it is of type `` ` ``), then
we report an error. The argument is typed by inheriting `A`, and
type `B` is returned as the synthesised type of the term as a whole.
* If the term switches from synthesized to inherited, then the type
decoration `A` in the contained term is typed by inheriting `A`, and
`A` is also returned as the synthesized type of the term as a whole.
We next consider the code for inheritance.
\begin{code}
inherit Γ (ƛ x ⇒ N) (A ⇒ B) =
do ⊢N ← inherit (Γ , x ⦂ A) N B
return (⊢ƛ ⊢N)
inherit Γ (ƛ x ⇒ N) ` =
error⁻ "lambda cannot be of type natural" (ƛ x ⇒ N) []
inherit Γ `zero ` =
return ⊢zero
inherit Γ `zero (A ⇒ B) =
error⁻ "zero cannot be function" `zero [ A ⇒ B ]
inherit Γ (`suc M) ` =
do ⊢M ← inherit Γ M `
return (⊢suc ⊢M)
inherit Γ (`suc M) (A ⇒ B) =
error⁻ "suc cannot be function" (`suc M) [ A ⇒ B ]
inherit Γ (`case L [zero⇒ M |suc x ⇒ N ]) A =
do ⟨ ` , ⊢L ⟩ ← synthesize Γ L
where ⟨ B ⇒ C , _ ⟩ → error⁻ "cannot case on function"
(`case L [zero⇒ M |suc x ⇒ N ])
[ B ⇒ C ]
⊢M ← inherit Γ M A
⊢N ← inherit (Γ , x ⦂ `) N A
return (⊢case ⊢L ⊢M ⊢N)
inherit Γ (μ x ⇒ M) A =
do ⊢M ← inherit (Γ , x ⦂ A) M A
return (⊢μ ⊢M)
inherit Γ (M ↑) B =
do ⟨ A , ⊢M ⟩ ← synthesize Γ M
yes A≡B ← return (A ≟Tp B)
where no _ → error⁻ "inheritance and synthesis conflict" (M ↑) [ A , B ]
return (⊢↑ ⊢M A≡B)
\end{code}
There are nine cases. We consider those for abstraction
and for switching from inherited to synthesized.
* If the term is an abstraction and the inherited type is of the form `A ⇒ B`
then we extend the context by giving the variable type `A` and
recuse to type the body by inheriting type `B`.
* If the term is an abstraction and the inherited type is not a function
(e.g., of the form `` ` ``), then we report an error.
* If the term switches from inherited to synthesised, then
we synthesise the type of the contained term and compare it
to the inherited type. If they are not equal, we raise an error.
The remaining cases are similar, and their code can pretty much be
read directly from the corresponding typing rules.
## Testing the example terms
First, we copy a function introduced ealier that makes it easy to
compute the evidence that two variable names are distinct.
\begin{code}
_≠_ : ∀ (x y : Id) → x ≢ y
x ≠ y with x ≟ y
... | no x≢y = x≢y
... | yes _ = ⊥-elim impossible
where postulate impossible : ⊥
\end{code}
Here is the result of typing two plus two on naturals.
\begin{code}
⊢2+2 : ∅ ⊢ 2+2 ↑ `
⊢2+2 =
(⊢↓
(⊢μ
(⊢ƛ
(⊢ƛ
(⊢case (Ax (S ("m" ≠ "n") Z)) (⊢↑ (Ax Z) refl)
(⊢suc
(⊢↑
(Ax
(S ("p" ≠ "m")
(S ("p" ≠ "n")
(S ("p" ≠ "m") Z)))
· ⊢↑ (Ax Z) refl
· ⊢↑ (Ax (S ("n" ≠ "m") Z)) refl)
refl))))))
· ⊢suc (⊢suc ⊢zero)
· ⊢suc (⊢suc ⊢zero))
\end{code}
We confirm that synthesis on the relevant term returns
natural as the type and the above derivation.
\begin{code}
_ : synthesize ∅ 2+2 ≡ return ⟨ ` , ⊢2+2 ⟩
_ = refl
\end{code}
Indeed, the above derivation was computed by evaluating the
term on the left, and editing. The only editing required is to
replace Agda's representation of the evidence that two strings are
unequal (which it can print not read) by equivalent calls to `≠`.
Here is the result of typing two plus two with Church numerals.
\begin{code}
⊢2+2ᶜ : ∅ ⊢ 2+2ᶜ ↑ `
⊢2+2ᶜ =
⊢↓
(⊢ƛ
(⊢ƛ
(⊢ƛ
(⊢ƛ
(⊢↑
(Ax
(S ("m" ≠ "z")
(S ("m" ≠ "s")
(S ("m" ≠ "n") Z)))
· ⊢↑ (Ax (S ("s" ≠ "z") Z)) refl
·
⊢↑
(Ax
(S ("n" ≠ "z")
(S ("n" ≠ "s") Z))
· ⊢↑ (Ax (S ("s" ≠ "z") Z)) refl
· ⊢↑ (Ax Z) refl)
refl)
refl)))))
·
⊢ƛ
(⊢ƛ
(⊢↑
(Ax (S ("s" ≠ "z") Z) ·
⊢↑ (Ax (S ("s" ≠ "z") Z) · ⊢↑ (Ax Z) refl)
refl)
refl))
·
⊢ƛ
(⊢ƛ
(⊢↑
(Ax (S ("s" ≠ "z") Z) ·
⊢↑ (Ax (S ("s" ≠ "z") Z) · ⊢↑ (Ax Z) refl)
refl)
refl))
· ⊢ƛ (⊢suc (⊢↑ (Ax Z) refl))
· ⊢zero
\end{code}
We confirm that synthesis on the relevant term returns
natural as the type and the above derivation.
\begin{code}
_ : synthesize ∅ 2+2ᶜ ≡ return ⟨ ` , ⊢2+2ᶜ ⟩
_ = refl
\end{code}
Again, the above derivation was computed by evaluating the
term on the left, and editing.
## Testing the error cases
It is important not just to check that code works as intended,
but also that it fails as intended. Here is one test case to
exercise each of the possible error messages.
\begin{code}
_ : synthesize ∅ ((ƛ "x" ⇒ ` "y" ↑) ↓ (` ⇒ `)) ≡
error⁺ "variable not bound" (` "y") []
_ = refl
_ : synthesize ∅ ((two ↓ `) · two) ≡
error⁺ "must apply function"
((`suc (`suc `zero) ↓ `) · `suc (`suc `zero)) []
_ = refl
_ : synthesize ∅ (twoᶜ ↓ `) ≡
error⁻ "lambda cannot be of type natural"
(ƛ "s" ⇒ (ƛ "z" ⇒ ` "s" · (` "s" · (` "z" ↑) ↑) ↑)) []
_ = refl
_ : synthesize ∅ (`zero ↓ ` ⇒ `) ≡
error⁻ "zero cannot be function" `zero [ ` ⇒ ` ]
_ = refl
_ : synthesize ∅ (two ↓ ` ⇒ `) ≡
error⁻ "suc cannot be function" (`suc (`suc `zero)) [ ` ⇒ ` ]
_ = refl
_ : synthesize ∅
((`case (twoᶜ ↓ Ch) [zero⇒ `zero |suc "x" ⇒ ` "x" ↑ ] ↓ `) ) ≡
error⁻ "cannot case on function"
`case (ƛ "s" ⇒ (ƛ "z" ⇒ ` "s" · (` "s" · (` "z" ↑) ↑) ↑))
↓ (` ⇒ `) ⇒ ` ⇒ ` [zero⇒ `zero |suc "x" ⇒ ` "x" ↑ ]
[ (` ⇒ `) ⇒ ` ⇒ ` ]
_ = refl
_ : synthesize ∅ (((ƛ "x" ⇒ ` "x" ↑) ↓ ` ⇒ (` ⇒ `))) ≡
error⁻ "inheritance and synthesis conflict" (` "x" ↑) [ ` , ` ⇒ ` ]
_ = refl
\end{code}
## Erasure
From the evidence that a decorated term has the correct type it is
easy to extract the corresponding inherently typed term. We use the
name `DB` to refer to the code in
Chapter [DeBruijn]({{ site.baseurl }}{% link out/plfa/DeBruijn.md %}).
It is easy to define an _erasure_ function that takes evidence of a
type judgment into the corresponding inherently typed term.
First, we give code to erase a context.
\begin{code}
∥_∥Γ : Context → DB.Context
∥ ∅ ∥Γ = DB.∅
∥ Γ , x ⦂ A ∥Γ = ∥ Γ ∥Γ DB., A
\end{code}
It simply drops the variable names.
Next, we give code to erase a lookup judgment.
\begin{code}
∥_∥∋ : ∀ {Γ x A} → Γ ∋ x ⦂ A → ∥ Γ ∥Γ DB.∋ A
∥ Z ∥∋ = DB.Z
∥ S x≢ ⊢x ∥∋ = DB.S ∥ ⊢x ∥∋
\end{code}
It just drops the evidence that variable names are distinct.
Finally, we give the code to erase a typing judgment.
Just as there are two mutually recursive typing judgments,
there are two mutually recursive erasure functions.
\begin{code}
∥_∥⁺ : ∀ {Γ M A} → Γ ⊢ M ↑ A → ∥ Γ ∥Γ DB.⊢ A
∥_∥⁻ : ∀ {Γ M A} → Γ ⊢ M ↓ A → ∥ Γ ∥Γ DB.⊢ A
∥ Ax ⊢x ∥⁺ = DB.` ∥ ⊢x ∥∋
∥ ⊢L · ⊢M ∥⁺ = ∥ ⊢L ∥⁺ DB.· ∥ ⊢M ∥⁻
∥ ⊢↓ ⊢M ∥⁺ = ∥ ⊢M ∥⁻
∥ ⊢ƛ ⊢N ∥⁻ = DB.ƛ ∥ ⊢N ∥⁻
∥ ⊢zero ∥⁻ = DB.`zero
∥ ⊢suc ⊢M ∥⁻ = DB.`suc ∥ ⊢M ∥⁻
∥ ⊢case ⊢L ⊢M ⊢N ∥⁻ = DB.case ∥ ⊢L ∥⁺ ∥ ⊢M ∥⁻ ∥ ⊢N ∥⁻
∥ ⊢μ ⊢M ∥⁻ = DB.μ ∥ ⊢M ∥⁻
∥ ⊢↑ ⊢M refl ∥⁻ = ∥ ⊢M ∥⁺
\end{code}
Erasure replaces constructors for each typing judgment
by the corresponding term constructor from `DB`. The
constructors that correspond to switching from synthesized
to inherited or vice versa are dropped.
We confirm that the erasure of the type derivations in
this chapter yield the corresponding inherently typed terms
from the earlier chapter.
\begin{code}
_ : ∥ ⊢2+2 ∥⁺ ≡ DB.2+2
_ = refl
_ : ∥ ⊢2+2ᶜ ∥⁺ ≡ DB.2+2ᶜ
_ = refl
\end{code}
Thus, we have confirmed that bidirectional type inference to
convert decorated versions of the lambda terms from
Chapter [Lambda]({{ site.baseurl }}{% link out/plfa/Lambda.md %})
to the inherently typed terms of
Chapter [DeBruijn]({{ site.baseurl }}{% link out/plfa/DeBruijn.md %}).
#### Exercise (`decoration`)
Extend bidirectional inference to include each of the constructs in
Chapter [More]({{ site.baseurl }}{% link out/plfa/More.md %}).
## Bidirectional inference in Agda
Agda itself uses bidirectional inference. This explains why
constructors can be overloaded while other defined names cannot — here
by _overloaded_ we mean that the same name can be used for
constructors of different types. Constructors are typed by
inheritance, and so the name is available when resolving the
constructor, whereas variables are typed by synthesis, and so each
variable must have a unique type.
## Unicode
This chapter uses the following unicode
↓ U+2193: DOWNWARDS ARROW (\d)
↑ U+2191: UPWARDS ARROW (\u)
← U+2190: LEFTWARDS ARROW (\l)
∥ U+2225: PARALLEL TO (\||)

View file

@ -1,18 +0,0 @@
Extensionality of a function of two arguments
\begin{code}
extensionality2 : {A B C : Set} {f g : A B C} ( (x : A) (y : B) f x y g x y) f g
extensionality2 fxy≡gxy = extensionality (λ x extensionality (λ y fxy≡gxy x y))
\end{code}
Isomorphism of all and exists.
\begin{code}
¬∃∀ : {A : Set} {B : A Set} (¬ (λ (x : A) B x)) (x : A) ¬ B x
¬∃∀ =
record
{ to = λ { ¬∃bx x bx ¬∃bx (x , bx) }
; fro = λ { ¬bx (x , bx) ¬bx x bx }
; invˡ = λ { ¬∃bx extensionality (λ { (x , bx) refl }) }
; invʳ = λ { ¬bx refl }
}
\end{code}

File diff suppressed because it is too large Load diff

View file

@ -1,18 +0,0 @@
infix 6 ƛ`_⇒_
ƛ`_⇒_ : Term → Term → Term
ƛ`_⇒_ (` x) N = ƛ x ⇒ N
ƛ`_⇒_ _ _ = ⊥-elim impossible
where postulate impossible : ⊥
plusᶜ : Term
plusᶜ = ƛ` m ⇒ ƛ` n ⇒ ƛ` s ⇒ ƛ` z ⇒ (m · s · (n · s · z))
where
m = ` "m"
n = ` "n"
s = ` "s"
z = ` "z"
_ : plusᶜ ≡ plusᶜ
_ = refl

View file

@ -1,59 +0,0 @@
## Lexical order
\begin{code}
Rel : Set → Set₁
Rel A = A → A → Set
Reflexive : ∀ {A : Set} → Rel A → Set
Reflexive {A} _≺_ = ∀ {x : A}
-----
→ x ≺ x
Trans : ∀ {A : Set} → Rel A → Set
Trans {A} _≺_ = ∀ {x y z : A}
→ x ≺ y
→ y ≺ z
-----
→ x ≺ z
Antirefl : ∀ {A : Set} → Rel A → Set
Antirefl {A} _≺_ = ∀ {x y : A}
→ x ≺ y
---------
→ ¬ (x ≡ y)
module Lexical (A : Set) (_≺_ : Rel A) (≺-trans : Trans _≺_) where
infix 4 _≪_
data _≪_ : Rel (List A) where
halt : ∀ {x : A} {xs : List A}
-------
→ [] ≪ x ∷ xs
this : ∀ {x y : A} {xs ys : List A}
→ x ≺ y
----------------
→ x ∷ xs ≪ y ∷ ys
next : ∀ {x : A} {xs ys : List A}
→ xs ≪ ys
---------------
→ x ∷ xs ≪ x ∷ ys
≪-trans : Trans _≪_
≪-trans halt (this _) = halt
≪-trans halt (next _) = halt
≪-trans (this x≺y) (this y≺z) = this (≺-trans x≺y y≺z)
≪-trans (this x≺y) (next ys≪zs) = this x≺y
≪-trans (next xs≪ys) (this x≺y) = this x≺y
≪-trans (next xs≪ys) (next ys≪zs) = next (≪-trans xs≪ys ys≪zs)
≪-antirefl : Antirefl _≺_ → Antirefl _≪_
≪-antirefl ≺-antirefl halt ()
≪-antirefl ≺-antirefl (this x≺y) refl = ⊥-elim (≺-antirefl x≺y refl)
≪-antirefl ≺-antirefl (next xs≪ys) refl = ⊥-elim (≪-antirefl ≺-antirefl xs≪ys refl)
\end{code}

View file

@ -1,167 +0,0 @@
open import Function
open import Relation.Nullary
open import Relation.Binary hiding (_⇒_)
open import Relation.Binary.PropositionalEquality hiding ([_])
open import Data.Sum
open import Data.Product
delim : {α β} {A : Set α} {B : Dec A -> Set β}
-> (d : Dec A) -> ( x -> B (yes x)) -> ( c -> B (no c)) -> B d
delim (yes x) f g = f x
delim (no c) f g = g c
drec = λ {α β} {A : Set α} {B : Set β} -> delim {A = A} {B = λ _ -> B}
dcong₂ : {α β γ} {A : Set α} {B : Set β} {C : Set γ} {x y v w}
-> (f : A -> B -> C)
-> ( {x y} -> f x v f y w -> x y × v w)
-> Dec (x y)
-> Dec (v w)
-> Dec (f x v f y w)
dcong₂ f inj d₁ d₂ = drec d₁
(λ p₁ -> drec d₂
(λ p₂ -> yes (cong₂ f p₁ p₂))
(λ c -> no (c proj₂ inj)))
(λ c -> no (c proj₁ inj))
infixl 5 _▻_
infixr 6 _⇒_
infix 4 _≟ᵗ_ _≟ᶜ_ _∈_ _⊂[_]_ _⊂?_ _⊢_
infixr 6 vs_
infixr 5 ƛ_
infixl 7 _·_
data Type : Set where
: Type
_⇒_ : Type -> Type -> Type
data Con : Set where
ε : Con
_▻_ : Con -> Type -> Con
data _∈_ σ : Con -> Set where
vz : {Γ} -> σ Γ σ
vs_ : {Γ τ} -> σ Γ -> σ Γ τ
data _⊢_ Γ : Type -> Set where
var : {σ} -> σ Γ -> Γ σ
ƛ_ : {σ τ} -> Γ σ τ -> Γ σ τ
_·_ : {σ τ} -> Γ σ τ -> Γ σ -> Γ τ
⇒-inj : {σ₁ σ₂ τ₁ τ₂} -> σ₁ τ₁ σ₂ τ₂ -> σ₁ σ₂ × τ₁ τ₂
⇒-inj refl = refl , refl
▻-inj : {Γ₁ Γ₂ σ₁ σ₂} -> Γ₁ σ₁ Γ₂ σ₂ -> Γ₁ Γ₂ × σ₁ σ₂
▻-inj refl = refl , refl
_≟ᵗ_ : Decidable (_≡_ {A = Type})
≟ᵗ = yes refl
(σ₁ τ₁) ≟ᵗ (σ₂ τ₂) = dcong₂ _⇒_ ⇒-inj (σ₁ ≟ᵗ σ₂) (τ₁ ≟ᵗ τ₂)
≟ᵗ (σ₂ τ₂) = no λ()
(σ₁ τ₁) ≟ᵗ = no λ()
_≟ᶜ_ : Decidable (_≡_ {A = Con})
ε ≟ᶜ ε = yes refl
Γ σ ≟ᶜ Δ τ = dcong₂ _▻_ ▻-inj (Γ ≟ᶜ Δ) (σ ≟ᵗ τ)
ε ≟ᶜ Δ τ = no λ()
Γ σ ≟ᶜ ε = no λ()
data _⊂[_]_ : Con -> Type -> Con -> Set where
stop : {Γ σ} -> Γ ⊂[ σ ] Γ σ
skip : {Γ Δ σ τ} -> Γ ⊂[ σ ] Δ -> Γ ⊂[ σ ] Δ τ
sub : {Γ Δ σ} -> Γ ⊂[ σ ] Δ -> σ Δ
sub stop = vz
sub (skip p) = vs (sub p)
⊂-inj : {Γ Δ σ τ} -> Γ ⊂[ σ ] Δ τ -> Γ ⊂[ σ ] Δ Γ Δ × σ τ
⊂-inj stop = inj₂ (refl , refl)
⊂-inj (skip p) = inj₁ p
_⊂?_ : {σ} -> Decidable _⊂[ σ ]_
_⊂?_ Γ ε = no λ()
_⊂?_ {σ} Γ (Δ τ) with λ c₁ -> drec (Γ ⊂? Δ) (yes skip) (λ c₂ -> no ([ c₂ , c₁ ] ⊂-inj))
... | r with σ ≟ᵗ τ
... | no c₁ = r (c₁ proj₂)
... | yes p₁ rewrite p₁ with Γ ≟ᶜ Δ
... | no c₁ = r (c₁ proj₁)
... | yes p₂ rewrite p₂ = yes stop
⊢_ : Type -> Set
σ = {Γ} -> Γ σ
⟦_⟧ᵗ : Type -> Set
⟧ᵗ =
σ τ ⟧ᵗ = σ ⟧ᵗ -> τ ⟧ᵗ
mutual
: {σ} -> σ -> σ ⟧ᵗ
{} t = t
{σ τ} f = λ x -> (f · x)
: {σ} -> σ ⟧ᵗ -> σ
{} t = t
{σ τ} f = λ {Γ} -> ƛ ( (f (varˢ Γ σ)))
varˢ : Γ σ -> σ ⟧ᵗ
varˢ Γ σ = (λ {Δ} -> var (diff Δ Γ σ)) where
diff : Δ Γ σ -> σ Δ
diff Δ Γ σ = drec (Γ ⊂? Δ) sub where postulate : _
data ⟦_⟧ᶜ : Con -> Set where
Ø : ε ⟧ᶜ
_▷_ : {Γ σ} -> Γ ⟧ᶜ -> σ ⟧ᵗ -> Γ σ ⟧ᶜ
lookupᵉ : {Γ σ} -> σ Γ -> Γ ⟧ᶜ -> σ ⟧ᵗ
lookupᵉ vz (ρ x) = x
lookupᵉ (vs v) (ρ x) = lookupᵉ v ρ
idᵉ : {Γ} -> Γ ⟧ᶜ
idᵉ {ε} = Ø
idᵉ {Γ σ} = idᵉ varˢ Γ σ
⟦_⟧ : {Γ σ} -> Γ σ -> Γ ⟧ᶜ -> σ ⟧ᵗ
var v ρ = lookupᵉ v ρ
ƛ b ρ = λ x -> b (ρ x)
f · x ρ = f ρ ( x ρ)
eval : {Γ σ} -> Γ σ -> σ ⟧ᵗ
eval t = t idᵉ
norm : {Γ σ} -> Γ σ -> Γ σ
norm t = (eval t)
Term : Type -> Set
Term σ = ε σ
I : Term ( )
I = id
K : Term ( )
K = const
S : Term (( ) ( ) )
S = _ˢ_
B : Term (( ) ( ) )
B = _∘_
C : Term (( ) )
C = flip
W : Term (( ) )
W = λ f x -> f x x
P : Term (( ) ( ) )
P = _on_
O : Term ((( ) ) ( ) )
O = λ g f -> f (g f)
test₁ : norm (ε (ƛ var (vs vs vz) · var vz) · var vz) var (vs vz) · var vz
test₁ = refl
test₂ : S ƛ ƛ ƛ var (vs vs vz) · var vz · (var (vs vz) · var vz)
test₂ = refl

View file

@ -1,896 +0,0 @@
---
title : "Lists: Lists and higher-order functions"
layout : page
permalink : /Lists
---
This chapter discusses the list data type. It gives further examples
of many of the techniques we have developed so far, and provides
examples of polymorphic types and higher-order functions.
## Imports
\begin{code}
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong)
open Eq.≡-Reasoning
open import Data.Nat using (; zero; suc; _+_; _*_; _∸_; _≤_; s≤s; z≤n)
open import Data.Nat.Properties using
(+-assoc; +-identityˡ; +-identityʳ; *-assoc; *-identityˡ; *-identityʳ)
open import Relation.Nullary using (¬_)
open import Data.Product using (_×_) renaming (_,_ to ⟨_,_⟩)
open import Isomorphism using (_≃_)
open import Function using (_∘_)
open import Level using (Level)
\end{code}
We assume [extensionality][extensionality].
\begin{code}
postulate
extensionality : ∀ {A B : Set} {f g : A → B} → (∀ (x : A) → f x ≡ g x) → f ≡ g
\end{code}
[extensionality]: Equality#extensionality
## Lists
Lists are defined in Agda as follows.
\begin{code}
data List (A : Set) : Set where
[] : List A
_∷_ : A → List A → List A
infixr 5 _∷_
\end{code}
Let's unpack this definition. If `A` is a set, then `List A` is a set.
The next two lines tell us that `[]` (pronounced *nil*) is a list of
type `A` (often called the *empty* list), and that `_∷_` (pronounced
*cons*, short for *constructor*) takes a value of type `A` and a `List
A` and returns a `List A`. Operator `_∷_` has precedence level 5 and
associates to the right.
For example,
\begin{code}
_ : List
_ = 0 ∷ 1 ∷ 2 ∷ []
\end{code}
denotes the list of the first three natural numbers. Since `_::_`
associates to the right, the term parses as `0 ∷ (1 ∷ (2 ∷ []))`.
Here `0` is the first element of the list, called the *head*,
and `1 ∷ (2 ∷ [])` is a list of the remaining elements, called the
*tail*. Lists are a rather strange beast: they have a head and a tail,
nothing in between, and the tail is itself another list!
As we've seen, parameterised types can be translated to
indexed types. The definition above is equivalent to the following.
\begin{code}
data List : Set → Set where
[] : ∀ {A : Set} → List A
_∷_ : ∀ {A : Set} → A → List A → List A
\end{code}
Each constructor takes the parameter as an implicit argument.
Thus, our example list could also be written
\begin{code}
_ : List
_ = _∷_ {} 0 (_∷_ {} 1 (_∷_ {} 2 ([] {})))
\end{code}
where here we have made the implicit parameters explicit.
Including the lines
{-# BUILTIN LIST List #-}
tells Agda that the type `List` corresponds to the Haskell type
list, and the constructors `[]` and `_∷_` correspond to nil and
cons respectively, allowing a more efficient representation of lists.
## List syntax
We can write lists more conveniently by introducing the following definitions.
\begin{code}
pattern [_] z = z ∷ []
pattern [_,_] y z = y ∷ z ∷ []
pattern [_,_,_] x y z = x ∷ y ∷ z ∷ []
pattern [_,_,_,_] w x y z = w ∷ x ∷ y ∷ z ∷ []
pattern [_,_,_,_,_] v w x y z = v ∷ w ∷ x ∷ y ∷ z ∷ []
pattern [_,_,_,_,_,_] u v w x y z = u ∷ v ∷ w ∷ x ∷ y ∷ z ∷ []
\end{code}
This is our first use of pattern declarations. For instance,
the third line tells us that `[ x , y , z ]` is equivalent to
`x ∷ y ∷ z ∷ []`, and permits the former to appear either in
a pattern on the left-hand side of an equation, or a term
on the right-hand side of an equation.
## Append
Our first function on lists is written `_++_` and pronounced
*append*.
\begin{code}
infixr 5 _++_
_++_ : ∀ {A : Set} → List A → List A → List A
[] ++ ys = ys
(x ∷ xs) ++ ys = x ∷ (xs ++ ys)
\end{code}
The type `A` is an implicit argument to append, making it
a *polymorphic* function (one that can be used at many types).
The empty list appended to another list yields the other list.
A non-empty list appended to another list yields a list with
head the same as the head of the first list and
tail the same as the tail of the first list appended to the second list.
Here is an example, showing how to compute the result
of appending two lists.
\begin{code}
_ : [ 0 , 1 , 2 ] ++ [ 3 , 4 ] ≡ [ 0 , 1 , 2 , 3 , 4 ]
_ =
begin
0 ∷ 1 ∷ 2 ∷ [] ++ 3 ∷ 4 ∷ []
≡⟨⟩
0 ∷ (1 ∷ 2 ∷ [] ++ 3 ∷ 4 ∷ [])
≡⟨⟩
0 ∷ 1 ∷ (2 ∷ [] ++ 3 ∷ 4 ∷ [])
≡⟨⟩
0 ∷ 1 ∷ 2 ∷ ([] ++ 3 ∷ 4 ∷ [])
≡⟨⟩
0 ∷ 1 ∷ 2 ∷ 3 ∷ 4 ∷ []
\end{code}
Appending two lists requires time linear in the
number of elements in the first list.
## Reasoning about append
We can reason about lists in much the same way that we reason
about numbers. Here is the proof that append is associative.
\begin{code}
++-assoc : ∀ {A : Set} (xs ys zs : List A) → (xs ++ ys) ++ zs ≡ xs ++ (ys ++ zs)
++-assoc [] ys zs =
begin
([] ++ ys) ++ zs
≡⟨⟩
ys ++ zs
≡⟨⟩
[] ++ (ys ++ zs)
++-assoc (x ∷ xs) ys zs =
begin
(x ∷ xs ++ ys) ++ zs
≡⟨⟩
x ∷ ((xs ++ ys) ++ zs)
≡⟨ cong (x ∷_) (++-assoc xs ys zs) ⟩
x ∷ (xs ++ (ys ++ zs))
≡⟨⟩
x ∷ xs ++ (ys ++ zs)
\end{code}
The proof is by induction on the first argument. The base case instantiates
to `[]`, and follows by straightforward computation.
The inductive case instantiates to `x ∷ xs`,
and follows by straightforward computation combined with the
inductive hypothesis. As usual, the inductive hypothesis is indicated by a recursive
invocation of the proof, in this case `++-assoc xs ys zs`.
Agda supports a variant of the *section* notation introduced by Richard Bird.
If `_⊕_` is an arbitrary binary operator, we
write `(x ⊕_)` for the function which applied to `y` returns `x ⊕ y`, and
we write `(_⊕ y)` for the function which applied to `x` also returns `x ⊕ y`.
Applying the congruence `cong (x ∷_)` promotes the inductive hypothesis
xs ++ (ys ++ zs) ≡ (xs ++ ys) ++ zs
to the equality
x ∷ (xs ++ (ys ++ zs)) ≡ x ∷ ((xs ++ ys) ++ zs)
which is needed in the proof.
It is also easy to show that `[]` is a left and right identity for `_++_`.
That it is a left identity is immediate from the definition.
\begin{code}
++-identityˡ : ∀ {A : Set} (xs : List A) → [] ++ xs ≡ xs
++-identityˡ xs =
begin
[] ++ xs
≡⟨⟩
xs
\end{code}
That it is a right identity follows by simple induction.
\begin{code}
++-identityʳ : ∀ {A : Set} (xs : List A) → xs ++ [] ≡ xs
++-identityʳ [] =
begin
[] ++ []
≡⟨⟩
[]
++-identityʳ (x ∷ xs) =
begin
(x ∷ xs) ++ []
≡⟨⟩
x ∷ (xs ++ [])
≡⟨ cong (x ∷_) (++-identityʳ xs) ⟩
x ∷ xs
\end{code}
As we will see later,
these three properties establish that `_++_` and `[]` form
a *monoid* over lists.
## Length
Our next function finds the length of a list.
\begin{code}
length : ∀ {A : Set} → List A →
length [] = zero
length (x ∷ xs) = suc (length xs)
\end{code}
Again, it takes an implicit parameter `A`.
The length of the empty list is zero.
The length of a non-empty list
is one greater than the length of the tail of the list.
Here is an example showing how to compute the length of a list.
\begin{code}
_ : length [ 0 , 1 , 2 ] ≡ 3
_ =
begin
length (0 ∷ 1 ∷ 2 ∷ [])
≡⟨⟩
suc (length (1 ∷ 2 ∷ []))
≡⟨⟩
suc (suc (length (2 ∷ [])))
≡⟨⟩
suc (suc (suc (length {} [])))
≡⟨⟩
suc (suc (suc zero))
\end{code}
Computing the length of a list requires time
linear in the number of elements in the list.
In the second-to-last line, we cannot write simply `length []` but
must instead write `length {} []`. Since `[]` has no elements, Agda
has insufficient information to infer the implicit parameter.
## Reasoning about length
The length of one list appended to another is the
sum of the lengths of the lists.
\begin{code}
length-++ : ∀ {A : Set} (xs ys : List A) → length (xs ++ ys) ≡ length xs + length ys
length-++ {A} [] ys =
begin
length ([] ++ ys)
≡⟨⟩
length ys
≡⟨⟩
length {A} [] + length ys
length-++ (x ∷ xs) ys =
begin
length ((x ∷ xs) ++ ys)
≡⟨⟩
suc (length (xs ++ ys))
≡⟨ cong suc (length-++ xs ys) ⟩
suc (length xs + length ys)
≡⟨⟩
length (x ∷ xs) + length ys
\end{code}
The proof is by induction on the first arugment. The base case instantiates
to `[]`, and follows by straightforward computation.
As before, Agda cannot infer the implicit type parameter to `length`,
and it must be given explicitly.
The inductive case instantiates to `x ∷ xs`,
and follows by straightforward computation combined with the
inductive hypothesis. As usual, the inductive hypothesis is indicated by a recursive
invocation of the proof, in this case `length-++ xs ys`, and it is promoted
by the congruence `cong suc`.
## Reverse
Using append, it is easy to formulate a function to reverse a list.
\begin{code}
reverse : ∀ {A : Set} → List A → List A
reverse [] = []
reverse (x ∷ xs) = reverse xs ++ [ x ]
\end{code}
The reverse of the empty list is the empty list.
The reverse of a non-empty list
is the reverse of its tail appended to a unit list
containing its head.
Here is an example showing how to reverse a list.
\begin{code}
_ : reverse [ 0 , 1 , 2 ] ≡ [ 2 , 1 , 0 ]
_ =
begin
reverse (0 ∷ 1 ∷ 2 ∷ [])
≡⟨⟩
reverse (1 ∷ 2 ∷ []) ++ [ 0 ]
≡⟨⟩
(reverse (2 ∷ []) ++ [ 1 ]) ++ [ 0 ]
≡⟨⟩
((reverse [] ++ [ 2 ]) ++ [ 1 ]) ++ [ 0 ]
≡⟨⟩
(([] ++ [ 2 ]) ++ [ 1 ]) ++ [ 0 ]
≡⟨⟩
(([] ++ 2 ∷ []) ++ 1 ∷ []) ++ 0 ∷ []
≡⟨⟩
(2 ∷ [] ++ 1 ∷ []) ++ 0 ∷ []
≡⟨⟩
2 ∷ ([] ++ 1 ∷ []) ++ 0 ∷ []
≡⟨⟩
(2 ∷ 1 ∷ []) ++ 0 ∷ []
≡⟨⟩
2 ∷ (1 ∷ [] ++ 0 ∷ [])
≡⟨⟩
2 ∷ 1 ∷ ([] ++ 0 ∷ [])
≡⟨⟩
2 ∷ 1 ∷ 0 ∷ []
≡⟨⟩
[ 2 , 1 , 0 ]
\end{code}
Reversing a list in this way takes time *quadratic* in the length of
the list. This is because reverse ends up appending lists of lengths
`1`, `2`, up to `n - 1`, where `n` is the length of the list being
reversed, append takes time linear in the length of the first
list, and the sum of the numbers up to `n - 1` is `n * (n - 1) / 2`.
(We will validate that last fact in an exercise later in this chapter.)
### Exercise (`reverse-++-commute`)
Show that the reverse of one list appended to another is the
reverse of the second appended to the reverse of the first.
reverse (xs ++ ys) ≡ reverse ys ++ reverse xs
### Exercise (`reverse-involutive`)
A function is an *involution* if when applied twice it acts
as the identity function. Show that reverse is an involution.
reverse (reverse xs) ≡ xs
## Faster reverse
The definition above, while easy to reason about, is less efficient than
one might expect since it takes time quadratic in the length of the list.
The idea is that we generalise reverse to take an additional argument.
\begin{code}
shunt : ∀ {A : Set} → List A → List A → List A
shunt [] ys = ys
shunt (x ∷ xs) ys = shunt xs (x ∷ ys)
\end{code}
The definition is by recursion on the first argument. The second argument
actually becomes *larger*, but this is not a problem because the argument
on which we recurse becomes *smaller*.
Shunt is related to reverse as follows.
\begin{code}
shunt-reverse : ∀ {A : Set} (xs ys : List A) → shunt xs ys ≡ reverse xs ++ ys
shunt-reverse [] ys =
begin
shunt [] ys
≡⟨⟩
ys
≡⟨⟩
reverse [] ++ ys
shunt-reverse (x ∷ xs) ys =
begin
shunt (x ∷ xs) ys
≡⟨⟩
shunt xs (x ∷ ys)
≡⟨ shunt-reverse xs (x ∷ ys) ⟩
reverse xs ++ (x ∷ ys)
≡⟨⟩
reverse xs ++ ([ x ] ++ ys)
≡⟨ sym (++-assoc (reverse xs) [ x ] ys) ⟩
(reverse xs ++ [ x ]) ++ ys
≡⟨⟩
reverse (x ∷ xs) ++ ys
\end{code}
The proof is by induction on the first argument.
The base case instantiates to `[]`, and follows by straightforward computation.
The inductive case instantiates to `x ∷ xs` and follows by the inductive
hypothesis and associativity of append. When we invoke the inductive hypothesis,
the second argument actually becomes *larger*, but this is not a problem because
the argument on which we induct becomes *smaller*.
Generalising on an auxiliary argument, which becomes larger as the argument on
which we recurse or induct becomes smaller, is a common trick. It belongs in
you sling of arrows, ready to slay the right problem.
Having defined shunt be generalisation, it is now easy to respecialise to
give a more efficient definition of reverse.
\begin{code}
reverse : ∀ {A : Set} → List A → List A
reverse xs = shunt xs []
\end{code}
Given our previous lemma, it is straightforward to show
the two definitions equivalent.
\begin{code}
reverses : ∀ {A : Set} (xs : List A) → reverse xs ≡ reverse xs
reverses xs =
begin
reverse xs
≡⟨⟩
shunt xs []
≡⟨ shunt-reverse xs [] ⟩
reverse xs ++ []
≡⟨ ++-identityʳ (reverse xs) ⟩
reverse xs
\end{code}
Here is an example showing fast reverse of the list `[ 0 , 1 , 2 ]`.
\begin{code}
_ : reverse [ 0 , 1 , 2 ] ≡ [ 2 , 1 , 0 ]
_ =
begin
reverse (0 ∷ 1 ∷ 2 ∷ [])
≡⟨⟩
shunt (0 ∷ 1 ∷ 2 ∷ []) []
≡⟨⟩
shunt (1 ∷ 2 ∷ []) (0 ∷ [])
≡⟨⟩
shunt (2 ∷ []) (1 ∷ 0 ∷ [])
≡⟨⟩
shunt [] (2 ∷ 1 ∷ 0 ∷ [])
≡⟨⟩
2 ∷ 1 ∷ 0 ∷ []
\end{code}
Now the time to reverse a list is linear in the length of the list.
## Map {#Map}
Map applies a function to every element of a list to generate a corresponding list.
Map is an example of a *higher-order function*, one which takes a function as an
argument and returns a function as a result.
\begin{code}
map : ∀ {A B : Set} → (A → B) → List A → List B
map f [] = []
map f (x ∷ xs) = f x ∷ map f xs
\end{code}
Map of the empty list is the empty list.
Map of a non-empty list yields a list
with head the same as the function applied to the head of the given list,
and tail the same as map of the function applied to the tail of the given list.
Here is an example showing how to use map to increment every element of a list.
\begin{code}
_ : map suc [ 0 , 1 , 2 ] ≡ [ 1 , 2 , 3 ]
_ =
begin
map suc (0 ∷ 1 ∷ 2 ∷ [])
≡⟨⟩
suc 0 ∷ map suc (1 ∷ 2 ∷ [])
≡⟨⟩
suc 0 ∷ suc 1 ∷ map suc (2 ∷ [])
≡⟨⟩
suc 0 ∷ suc 1 ∷ suc 2 ∷ map suc []
≡⟨⟩
suc 0 ∷ suc 1 ∷ suc 2 ∷ []
\end{code}
Map requires time linear in the length of the list.
It is often convenient to exploit currying by applying
map to a function to yield a new function, and at a later
point applying the resulting function.
\begin{code}
sucs : List → List
sucs = map suc
_ : sucs [ 0 , 1 , 2 ] ≡ [ 1 , 2 , 3 ]
_ =
begin
sucs [ 0 , 1 , 2 ]
≡⟨⟩
map suc [ 0 , 1 , 2 ]
≡⟨⟩
[ 1 , 2 , 3 ]
\end{code}
Any type that is parameterised on another type, such as lists, has a
corresponding map, which accepts a function and returns a function
from the type parameterised on the domain of the function to the type
parameterised on the range of the function. Further, a type that is
parameterised on *n* types will have a map that is parameterised on
*n* functions.
### Exercise (`map-compose`)
Prove that the map of a composition is equal to the composition of two maps.
map (f ∘ g) ≡ map f ∘ map g
The last step of the proof requires extensionality.
*Exercise* `map-++-commute`
Prove the following relationship between map and append.
map f (xs ++ ys) ≡ map f xs ++ map f ys
## Fold {#Fold}
Fold takes an operator and a value, and uses the operator to combine
each of the elements of the list, taking the given value as the result
for the empty list.
\begin{code}
foldr : ∀ {A B : Set} → (A → B → B) → B → List A → B
foldr _⊗_ e [] = e
foldr _⊗_ e (x ∷ xs) = x ⊗ foldr _⊗_ e xs
\end{code}
Fold of the empty list is the given value.
Fold of a non-empty list uses the operator to combine
the head of the list and the fold of the tail of the list.
Here is an example showing how to use fold to find the sum of a list.
\begin{code}
_ : foldr _+_ 0 [ 1 , 2 , 3 , 4 ] ≡ 10
_ =
begin
foldr _+_ 0 (1 ∷ 2 ∷ 3 ∷ 4 ∷ [])
≡⟨⟩
1 + foldr _+_ 0 (2 ∷ 3 ∷ 4 ∷ [])
≡⟨⟩
1 + (2 + foldr _+_ 0 (3 ∷ 4 ∷ []))
≡⟨⟩
1 + (2 + (3 + foldr _+_ 0 (4 ∷ [])))
≡⟨⟩
1 + (2 + (3 + (4 + foldr _+_ 0 [])))
≡⟨⟩
1 + (2 + (3 + (4 + 0)))
\end{code}
Fold requires time linear in the length of the list.
It is often convenient to exploit currying by applying
fold to an operator and a value to yield a new function,
and at a later point applying the resulting function.
\begin{code}
sum : List
sum = foldr _+_ 0
_ : sum [ 1 , 2 , 3 , 4 ] ≡ 10
_ =
begin
sum [ 1 , 2 , 3 , 4 ]
≡⟨⟩
foldr _+_ 0 [ 1 , 2 , 3 , 4 ]
≡⟨⟩
10
\end{code}
Just as the list type has two constructors, `[]` and `_∷_`,
so the fold function takes two arguments, `e` and `_⊕_`
(in addition to the list argument).
In general, a data type with *n* constructors will have
a corresponding fold function that takes *n* arguments.
## Exercise (`product`)
Use fold to define a function to find the product of a list of numbers.
product [ 1 , 2 , 3 , 4 ] ≡ 24
### Exercise (`foldr-++`)
Show that fold and append are related as follows.
\begin{code}
postulate
foldr-++ : ∀ {A B : Set} (_⊗_ : A → B → B) (e : B) (xs ys : List A) →
foldr _⊗_ e (xs ++ ys) ≡ foldr _⊗_ (foldr _⊗_ e ys) xs
\end{code}
### Exercise (`map-is-foldr`)
Show that map can be defined using fold.
\begin{code}
postulate
map-is-foldr : ∀ {A B : Set} {f : A → B} →
map f ≡ foldr (λ x xs → f x ∷ xs) []
\end{code}
This requires extensionality.
### Exercise (`sum-downFrom`)
Define a function that counts down as follows.
\begin{code}
downFrom : → List
downFrom zero = []
downFrom (suc n) = n ∷ downFrom n
\end{code}
For example,
\begin{code}
_ : downFrom 3 ≡ [ 2 , 1 , 0 ]
_ = refl
\end{code}
Prove that the sum of the numbers `(n - 1) + ⋯ + 0` is
equal to `n * (n - 1) / 2`.
\begin{code}
postulate
sum-downFrom : ∀ (n : ) → sum (downFrom n) * 2 ≡ n * (n ∸ 1)
\end{code}
<!-- `mapIsFold` in Data.List.Properties -->
## Monoids
Typically when we use a fold the operator is associative and the
value is a left and right identity for the value, meaning that the
operator and the value form a *monoid*.
We can define a monoid as a suitable record type.
\begin{code}
record IsMonoid {A : Set} (_⊗_ : A → A → A) (e : A) : Set where
field
assoc : ∀ (x y z : A) → (x ⊗ y) ⊗ z ≡ x ⊗ (y ⊗ z)
identityˡ : ∀ (x : A) → e ⊗ x ≡ x
identityʳ : ∀ (x : A) → x ⊗ e ≡ x
open IsMonoid
\end{code}
As examples, sum and zero, multiplication and one, and append and the empty
list, are all examples of monoids.
\begin{code}
+-monoid : IsMonoid _+_ 0
+-monoid =
record
{ assoc = +-assoc
; identityˡ = +-identityˡ
; identityʳ = +-identityʳ
}
*-monoid : IsMonoid _*_ 1
*-monoid =
record
{ assoc = *-assoc
; identityˡ = *-identityˡ
; identityʳ = *-identityʳ
}
++-monoid : ∀ {A : Set} → IsMonoid {List A} _++_ []
++-monoid =
record
{ assoc = ++-assoc
; identityˡ = ++-identityˡ
; identityʳ = ++-identityʳ
}
\end{code}
If `_⊕_` and `e` form a monoid, then we can re-express fold on the
same operator and an arbitrary value.
\begin{code}
foldr-monoid : ∀ {A : Set} (_⊗_ : A → A → A) (e : A) → IsMonoid _⊗_ e →
∀ (xs : List A) (y : A) → foldr _⊗_ y xs ≡ foldr _⊗_ e xs ⊗ y
foldr-monoid _⊗_ e ⊗-monoid [] y =
begin
foldr _⊗_ y []
≡⟨⟩
y
≡⟨ sym (identityˡ ⊗-monoid y) ⟩
(e ⊗ y)
≡⟨⟩
foldr _⊗_ e [] ⊗ y
foldr-monoid _⊗_ e ⊗-monoid (x ∷ xs) y =
begin
foldr _⊗_ y (x ∷ xs)
≡⟨⟩
x ⊗ (foldr _⊗_ y xs)
≡⟨ cong (x ⊗_) (foldr-monoid _⊗_ e ⊗-monoid xs y) ⟩
x ⊗ (foldr _⊗_ e xs ⊗ y)
≡⟨ sym (assoc ⊗-monoid x (foldr _⊗_ e xs) y) ⟩
(x ⊗ foldr _⊗_ e xs) ⊗ y
≡⟨⟩
foldr _⊗_ e (x ∷ xs) ⊗ y
\end{code}
As a consequence, using a previous exercise, we have the following.
\begin{code}
foldr-monoid-++ : ∀ {A : Set} (_⊗_ : A → A → A) (e : A) → IsMonoid _⊗_ e →
∀ (xs ys : List A) → foldr _⊗_ e (xs ++ ys) ≡ foldr _⊗_ e xs ⊗ foldr _⊗_ e ys
foldr-monoid-++ _⊗_ e monoid-⊗ xs ys =
begin
foldr _⊗_ e (xs ++ ys)
≡⟨ foldr-++ _⊗_ e xs ys ⟩
foldr _⊗_ (foldr _⊗_ e ys) xs
≡⟨ foldr-monoid _⊗_ e monoid-⊗ xs (foldr _⊗_ e ys) ⟩
foldr _⊗_ e xs ⊗ foldr _⊗_ e ys
\end{code}
## All {#All}
We can also define predicates over lists. Two of the most important
are `All` and `Any`.
Predicate `All P` holds if predicate `P` is satisfied by every element of a list.
\begin{code}
data All {A : Set} (P : A → Set) : List A → Set where
[] : All P []
_∷_ : {x : A} {xs : List A} → P x → All P xs → All P (x ∷ xs)
\end{code}
The type has two constructors, reusing the names of the same constructors for lists.
The first asserts that `P` holds for ever element of the empty list.
The second asserts that if `P` holds of the head of a list and for every
element of the tail of a list, then `P` holds for every element of the list.
Agda uses types to disambiguate whether the constructor is building
a list or evidence that `All P` holds.
For example, `All (_≤ 2)` holds of a list where every element is less
than or equal to two. Recall that `z≤n` proves `zero ≤ n` for any
`n`, and that if `m≤n` proves `m ≤ n` then `s≤s m≤n` proves `suc m ≤
suc n`, for any `m` and `n`.
\begin{code}
_ : All (_≤ 2) [ 0 , 1 , 2 ]
_ = z≤n ∷ (s≤s z≤n) ∷ (s≤s (s≤s z≤n)) ∷ []
\end{code}
Here `_∷_` and `[]` are the constructors of `All P` rather than of `List A`.
The three items are proofs of `0 ≤ 2`, `1 ≤ 2`, and `2 ≤ 2`, respectively.
## Any
Predicate `Any P` holds if predicate `P` is satisfied by some element of a list.
\begin{code}
data Any {A : Set} (P : A → Set) : List A → Set where
here : {x : A} {xs : List A} → P x → Any P (x ∷ xs)
there : {x : A} {xs : List A} → Any P xs → Any P (x ∷ xs)
\end{code}
The first constructor provides evidence that the head of the list
satisfies `P`, while the second provides evidence that some element of
the tail of the list satisfies `P`. For example, we can define list
membership as follows.
\begin{code}
infix 4 _∈_
_∈_ : ∀ {A : Set} (x : A) (xs : List A) → Set
x ∈ xs = Any (x ≡_) xs
_∉_ : ∀ {A : Set} (x : A) (xs : List A) → Set
x ∉ xs = ¬ (x ∈ xs)
\end{code}
For example, zero is an element of the list `[ 0 , 1 , 0 , 2 ]`. Indeed, we can demonstrate
this fact in two different ways, corresponding to the two different
occurrences of zero in the list, as the first element and as the third element.
\begin{code}
_ : 0 ∈ [ 0 , 1 , 0 , 2 ]
_ = here refl
_ : 0 ∈ [ 0 , 1 , 0 , 2 ]
_ = there (there (here refl))
\end{code}
Further, we can demonstrate that three is not in the list, because
any possible proof that it is in the list leads to contradiction.
\begin{code}
not-in : 3 ∉ [ 0 , 1 , 0 , 2 ]
not-in (here ())
not-in (there (here ()))
not-in (there (there (here ())))
not-in (there (there (there (here ()))))
not-in (there (there (there (there ()))))
\end{code}
The five occurrences of `()` attest to the fact that there is no
possible evidence for `3 ≡ 0`, `3 ≡ 1`, `3 ≡ 0`, `3 ≡ 2`, and
`3 ∈ []`, respectively.
## All and append
A predicate holds for every element of one list appended to another if and
only if it holds for every element of each list. Indeed, an even stronger
result is true, as we can show that the two types are isomorphic.
\begin{code}
All-++ : ∀ {A : Set} {P : A → Set} (xs ys : List A) →
All P (xs ++ ys) ≃ (All P xs × All P ys)
All-++ xs ys =
record
{ to = to xs ys
; from = from xs ys
; from∘to = from∘to xs ys
; to∘from = to∘from xs ys
}
where
to : ∀ {A : Set} {P : A → Set} (xs ys : List A) →
All P (xs ++ ys) → (All P xs × All P ys)
to [] ys ∀Pys = ⟨ [] , ∀Pys ⟩
to (x ∷ xs) ys (Px ∷ ∀Pxs++ys) with to xs ys ∀Pxs++ys
... | ⟨ ∀Pxs , ∀Pys ⟩ = ⟨ Px ∷ ∀Pxs , ∀Pys ⟩
from : ∀ { A : Set} {P : A → Set} (xs ys : List A) →
All P xs × All P ys → All P (xs ++ ys)
from [] ys ⟨ [] , ∀Pys ⟩ = ∀Pys
from (x ∷ xs) ys ⟨ Px ∷ ∀Pxs , ∀Pys ⟩ = Px ∷ from xs ys ⟨ ∀Pxs , ∀Pys ⟩
from∘to : ∀ { A : Set} {P : A → Set} (xs ys : List A) →
∀ (u : All P (xs ++ ys)) → from xs ys (to xs ys u) ≡ u
from∘to [] ys ∀Pys = refl
from∘to (x ∷ xs) ys (Px ∷ ∀Pxs++ys) = cong (Px ∷_) (from∘to xs ys ∀Pxs++ys)
to∘from : ∀ { A : Set} {P : A → Set} (xs ys : List A) →
∀ (v : All P xs × All P ys) → to xs ys (from xs ys v) ≡ v
to∘from [] ys ⟨ [] , ∀Pys ⟩ = refl
to∘from (x ∷ xs) ys ⟨ Px ∷ ∀Pxs , ∀Pys ⟩ rewrite to∘from xs ys ⟨ ∀Pxs , ∀Pys ⟩ = refl
\end{code}
### Exercise (`Any-++`)
Prove a result similar to `All-++`, but with `Any` in place of `All`, and a suitable
replacement for `_×_`. As a consequence, demonstrate an isomorphism relating
`_∈_` and `_++_`.
### Exercise (`¬Any≃All¬`)
First generalise composition to arbitrary levels, using
[universe polymorphism][unipoly].
\begin{code}
_∘_ : ∀ {ℓ₁ ℓ₂ ℓ₃ : Level} {A : Set ℓ₁} {B : Set ℓ₂} {C : Set ℓ₃} → (B → C) → (A → B) → A → C
(g ∘′ f) x = g (f x)
\end{code}
[unipoly]: Equality/index.html#unipoly
Show that `Any` and `All` satisfy a version of De Morgan's Law.
\begin{code}
postulate
¬Any≃All¬ : ∀ {A : Set} (P : A → Set) (xs : List A) → (¬_ ∘′ Any P) xs ≃ All (¬_ ∘′ P) xs
\end{code}
Do we also have the following?
(¬_ ∘′ All P) xs ≃ Any (¬_ ∘′ P) xs
If so, prove; if not, explain why.
## Standard Library
Definitions similar to those in this chapter can be found in the standard library.
\begin{code}
import Data.List using (List; _++_; length; reverse; map; foldr; downFrom)
import Data.List.All using (All; []; _∷_)
import Data.List.Any using (Any; here; there)
import Data.List.Any.Membership.Propositional using (_∈_)
import Algebra.Structures using (IsMonoid)
\end{code}
The standard library version of `IsMonoid` differs from the
one given here, in that it is also parameterised on an equivalence relation.
## Unicode
This chapter uses the following unicode.
∷ U+2237 PROPORTION (\::)
⊗ U+2297 CIRCLED TIMES (\otimes)
∈ U+2208 ELEMENT OF (\in)
∉ U+2209 NOT AN ELEMENT OF (\inn)

File diff suppressed because it is too large Load diff

View file

@ -1,15 +0,0 @@
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Data.List using (List; []; _∷_; [_]; _++_)
open import Data.List.Any using (Any; here; there)
open import Data.List.Any.Membership.Propositional using (_∈_)
open import Data.Nat using ()
open import Relation.Binary.PropositionalEquality using (_≡_; refl)
-- open import Data.List.Any.Membership.Propositional.Properties using (∈-++⁺ˡ; ∈-++⁺ʳ; ∈-++⁻)
Id =
_⊆_ : List Id List Id Set
xs ys = {w} w xs w ys
lemma : {x : Id} x [ x ]
lemma = here refl

View file

@ -1,11 +0,0 @@
module Mendler (F : Set Set) where
open import Data.Product using (_×_)
Alg : Set Set
Alg X = (R : Set) (R X) F R X
test : Set Set
test A = A × A
test : (R : Set) Set
test A = A × A

View file

@ -1,12 +0,0 @@
module Module where
data : Set where
zero :
suc :
_+_ :
zero + n = zero
suc m + n = suc (m + n)
import Data.Nat using (; zero; suc; _+_)

View file

@ -1,19 +0,0 @@
module ModuleInfix where
open import Data.List using (List; _∷_; [])
open import Data.Bool using (Bool; true; false)
module Sort(A : Set)(_≤_ : A A Bool)(_⊝_ : A A A)(zero : A) where
infix 1 _≤_
infix 2 _⊝_
insert : A List A List A
insert x [] = x []
insert x (y ys) with zero (y x)
insert x (y ys) | true = x y ys
insert x (y ys) | false = y insert x ys
sort : List A List A
sort [] = []
sort (x xs) = insert x (sort xs)

View file

@ -1,9 +0,0 @@
open import Data.Nat using (; zero; suc; _+_; _∸_; _≥_; _≤_; z≤n; s≤s)
open import Function.Equivalence using (_⇔_)
open import Relation.Binary.PropositionalEquality using (-to-⟶)
postulate
adjoint : {x y z} x + y z x z y
unit : {x y} x (x + y) y
apply : {x y} (x y) + y x

View file

@ -1,24 +0,0 @@
open import Data.Nat using (; zero; suc)
open import Data.Bool using (Bool; true; false)
data even : Set
data odd : Set
data even where
zero : even zero
suc : {n : } odd n even (suc n)
data odd where
suc : {n : } even n odd (suc n)
mutual
data even : Set where
zero : even zero
suc : {n : } odd n even (suc n)
data odd : Set where
suc : {n : } even n odd (suc n)
{-
/Users/wadler/sf/src/extra/Mutual.agda:3,6-10
Missing definition for even
-}

View file

@ -1,46 +0,0 @@
open import Data.Nat using (; zero; suc; _+_; _*_)
open import Data.Product using (∃; _,_)
open import Relation.Binary.PropositionalEquality using (_≡_; refl; sym)
+-identity : (m : ) m + zero m
+-identity zero = refl
+-identity (suc m) rewrite +-identity m = refl
+-suc : (m n : ) n + suc m suc (n + m)
+-suc m zero = refl
+-suc m (suc n) rewrite +-suc m n = refl
+-comm : (m n : ) m + n n + m
+-comm zero n rewrite +-identity n = refl
+-comm (suc m) n rewrite +-suc m n | +-comm m n = refl
data even : Set
data odd : Set
data even where
zero : even zero
suc : {n : } odd n even (suc n)
data odd where
suc : {n : } even n odd (suc n)
+-lemma : (m : ) suc (suc (m + (m + 0))) suc m + suc (m + 0)
+-lemma m rewrite +-identity m | +-suc m m = refl
is-even : (n : ) even n (λ (m : ) n 2 * m)
is-odd : (n : ) odd n (λ (m : ) n 1 + 2 * m)
is-even zero zero = zero , refl
is-even (suc n) (suc oddn) with is-odd n oddn
... | m , n≡1+2*m rewrite n≡1+2*m | +-lemma m = suc m , refl
is-odd (suc n) (suc evenn) with is-even n evenn
... | m , n≡2*m rewrite n≡2*m = m , refl
+-lemma : (m : ) suc (suc (m + (m + 0))) suc m + suc (m + 0)
+-lemma m rewrite +-suc (m + 0) m = refl
is-even : (n : ) even n (λ (m : ) n 2 * m)
is-even zero zero = zero , refl
is-even (suc n) (suc oddn) with is-odd n oddn
... | m , n≡1+2*m rewrite n≡1+2*m | +-identity m | +-suc m m = suc m , {!!}

View file

@ -1,31 +0,0 @@
module Nat where
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl)
open Eq.≡-Reasoning using (begin_; _≡⟨⟩_; _∎)
data : Set where
zero :
suc :
{-# BUILTIN NATURAL #-}
_+_ :
zero + n = n
(suc m) + n = suc (m + n)
_ : 2 + 3 5
_ =
begin
2 + 3
≡⟨⟩
suc (1 + 3)
≡⟨⟩
suc (suc (0 + 3))
≡⟨⟩
suc (suc 3)
≡⟨⟩
5

View file

@ -1,50 +0,0 @@
\begin{code}
open import Data.Empty using (⊥; ⊥-elim)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Data.Product using (_×_; _,_; proj₁; proj₂)
open import Function using (_∘_)
open import Relation.Nullary using (¬_)
\end{code}
Two halves of de Morgan's laws hold intuitionistically. The other two
halves are each equivalent to the law of double negation.
\begin{code}
dem1 : ∀ {A B : Set} → A × B → ¬ (¬ A ⊎ ¬ B)
dem1 (a , b) (inj₁ ¬a) = ¬a a
dem1 (a , b) (inj₂ ¬b) = ¬b b
dem2 : ∀ {A B : Set} → A ⊎ B → ¬ (¬ A × ¬ B)
dem2 (inj₁ a) (¬a , ¬b) = ¬a a
dem2 (inj₂ b) (¬a , ¬b) = ¬b b
\end{code}
For the other variant of De Morgan's law, one way is an isomorphism.
\begin{code}
-- dem-≃ : ∀ {A B : Set} → (¬ (A ⊎ B)) ≃ (¬ A × ¬ B)
-- dem-≃ = →-distributes-⊎
\end{code}
The other holds in only one direction.
\begin{code}
dem-half : ∀ {A B : Set} → ¬ A ⊎ ¬ B → ¬ (A × B)
dem-half (inj₁ ¬a) (a , b) = ¬a a
dem-half (inj₂ ¬b) (a , b) = ¬b b
\end{code}
The other variant does not appear to be equivalent to classical logic.
So that undermines my idea that basic propositions are either true
intuitionistically or equivalent to classical logic.
For several of the laws equivalent to classical logic, the reverse
direction holds in intuitionistic long.
\begin{code}
implication-inv : ∀ {A B : Set} → (¬ A ⊎ B) → A → B
implication-inv (inj₁ ¬a) a = ⊥-elim (¬a a)
implication-inv (inj₂ b) a = b
demorgan-inv : ∀ {A B : Set} → A ⊎ B → ¬ (¬ A × ¬ B)
demorgan-inv (inj₁ a) (¬a , ¬b) = ¬a a
demorgan-inv (inj₂ b) (¬a , ¬b) = ¬b b
\end{code}

View file

@ -1,49 +0,0 @@
infix 9 _[_:=_]
_[_:=_] : Term → Id → Term → Term
(` x) [ y := V ] with x ≟ y
... | yes _ = V
... | no _ = ` x
(ƛ x ⇒ N) [ y := V ] with x ≟ y
... | yes _ = ƛ x ⇒ N
... | no _ = ƛ x ⇒ (N [ y := V ])
(L · M) [ y := V ] = (L [ y := V ]) · (M [ y := V ])
(`zero) [ y := V ] = `zero
(`suc M) [ y := V ] = `suc (M [ y := V ])
(`case L
[zero⇒ M
|suc x ⇒ N ])
[ y := V ] with x ≟ y
... | yes _ = `case L [ y := V ]
[zero⇒ M [ y := V ]
|suc x ⇒ N ]
... | no _ = `case L [ y := V ]
[zero⇒ M [ y := V ]
|suc x ⇒ N [ y := V ] ]
(μ x ⇒ N) [ y := V ] with x ≟ y
... | yes _ = μ x ⇒ N
... | no _ = μ x ⇒ (N [ y := V ])
subst : ∀ {Γ x N V A B}
→ ∅ ⊢ V ⦂ A
→ Γ , x ⦂ A ⊢ N ⦂ B
--------------------
→ Γ ⊢ N [ x := V ] ⦂ B
subst {x = y} ⊢V (⊢` {x = x} Z) with x ≟ y
... | yes refl = weaken ⊢V
... | no x≢y = ⊥-elim (x≢y refl)
subst {x = y} ⊢V (⊢` {x = x} (S x≢y ∋x)) with x ≟ y
... | yes refl = ⊥-elim (x≢y refl)
... | no _ = ⊢` ∋x
subst {x = y} ⊢V (⊢ƛ {x = x} ⊢N) with x ≟ y
... | yes refl = ⊢ƛ (drop ⊢N)
... | no x≢y = ⊢ƛ (subst ⊢V (swap x≢y ⊢N))
subst ⊢V (⊢L · ⊢M) = subst ⊢V ⊢L · subst ⊢V ⊢M
subst ⊢V ⊢zero = ⊢zero
subst ⊢V (⊢suc ⊢M) = ⊢suc (subst ⊢V ⊢M)
subst {x = y} ⊢V (⊢case {x = x} ⊢L ⊢M ⊢N) with x ≟ y
... | yes refl = ⊢case (subst ⊢V ⊢L) (subst ⊢V ⊢M) (drop ⊢N)
... | no x≢y = ⊢case (subst ⊢V ⊢L) (subst ⊢V ⊢M) (subst ⊢V (swap x≢y ⊢N))
subst {x = y} ⊢V (⊢μ {x = x} ⊢M) with x ≟ y
... | yes refl = ⊢μ (drop ⊢M)
... | no x≢y = ⊢μ (subst ⊢V (swap x≢y ⊢M))

View file

@ -1,112 +0,0 @@
open import Algebra
open import Data.Product
open import Data.Bool
open import Data.List
open import Data.List.Properties
open import Relation.Binary.PropositionalEquality
open import Function
open import Data.Empty
open import Relation.Nullary
open import Relation.Nullary.Decidable
module LM {A : Set} = Monoid (Data.List.Properties.++-monoid A)
infixr 4 _⇒_
data Type : Set where
o : Type
_⇒_ : Type Type Type
Env = List Type
Type≡? : (A B : Type) Dec (A B)
Type≡? o o = yes refl
Type≡? o (B B₁) = no (λ ())
Type≡? (A A₁) o = no (λ ())
Type≡? (A B) (A' B') with Type≡? A A'
Type≡? (A B) (.A B') | yes refl with Type≡? B B'
Type≡? (A B) (.A .B) | yes refl | yes refl = yes refl
Type≡? (A B) (.A B') | yes refl | no ¬p = no (λ {refl ¬p refl})
Type≡? (A B) (A' B') | no ¬p = no (λ {refl ¬p refl})
Env≡? : (Γ Δ : Env) Dec (Γ Δ)
Env≡? [] [] = yes refl
Env≡? [] (x Δ) = no (λ ())
Env≡? (x Γ) [] = no (λ ())
Env≡? (A Γ) (A' Δ) with Type≡? A A'
Env≡? (A Γ) (A' Δ) | yes p with Env≡? Γ Δ
Env≡? (A Γ) (.A .Γ) | yes refl | yes refl = yes refl
Env≡? (A Γ) (A' Δ) | yes p | no ¬q = no (λ {refl ¬q refl})
Env≡? (A Γ) (A' Δ) | no ¬p = no (λ {refl ¬p refl})
data Var : Env Type Set where
Z : {Γ : Env} {A : Type} Var (A Γ) A
S : {Γ : Env} {A B : Type} Var Γ B Var (A Γ) B
data Exp : Env Type Set where
var : {Γ : Env} {A : Type} Var Γ A Exp Γ A
abs : {Γ : Env} {A B : Type} Exp (A Γ) B Exp Γ (A B)
app : {Γ : Env} {A B : Type} Exp Γ (A B) Exp Γ A Exp Γ B
data PH (X : Type Set) : Type Set where
var : {A : Type} X A PH X A
abs : {A B : Type} (X A PH X B) PH X (A B)
app : {A B : Type} PH X (A B) PH X A PH X B
-- logical prediacte on PH
PHᴾ : {X}(Xᴾ : {A} X A Set) {A} PH X A Set
PHᴾ Xᴾ (var a) = Xᴾ a
PHᴾ Xᴾ (abs t) = a Xᴾ a PHᴾ Xᴾ (t a)
PHᴾ Xᴾ (app t u) = PHᴾ Xᴾ t × PHᴾ Xᴾ u
postulate
free-thm :
{A}(t : {X} PH X A) X (Xᴾ : {A} X A Set) PHᴾ {X} Xᴾ t
PH' : Type Set
PH' = PH (λ _ Env)
VarOK? : Γ A Δ Dec ( λ Ξ (Ξ ++ A Δ) Γ)
VarOK? [] A Δ = no (λ {([] , ()) ; (_ _ , ())})
VarOK? (A' Γ) A Δ with Env≡? (A' Γ) (A Δ)
VarOK? (A' Γ) .A' .Γ | yes refl = yes ([] , refl)
VarOK? (A' Γ) A Δ | no ¬p with VarOK? Γ A Δ
VarOK? (A' Γ) A Δ | no ¬p | yes (Σ , refl) =
yes (A' Σ , refl)
VarOK? (A' Γ) A Δ | no ¬p | no ¬q
= no λ { ([] , refl) ¬p refl ; (x Σ , s) ¬q (Σ , proj₂ (∷-injective s))}
OK : {A} Env PH' A Set
OK {A} Γ t = Δ PHᴾ (λ {B} Σ True (VarOK? (Δ ++ Γ) B Σ)) t
toVar : {Γ Σ A} ( λ Ξ (Ξ ++ A Σ) Γ) Var Γ A
toVar ([] , refl) = Z
toVar (x Ξ , refl) = S (toVar (Ξ , refl))
toExp' : {Γ A} (t : PH' A) OK {A} Γ t Exp Γ A
toExp' (var x) p = var (toVar (toWitness (p [])))
toExp' {Γ} (abs {A} {B} t) p =
abs (toExp' (t Γ)
λ Δ subst (λ z PHᴾ (λ {B₁} Σ₁ True (VarOK? z B₁ Σ₁)) (t Γ))
(LM.assoc Δ (A []) Γ)
(p (Δ ++ A []) Γ (fromWitness (Δ , sym (LM.assoc Δ (A []) Γ)))))
toExp' (app t u) p =
app (toExp' t (proj₁ p)) (toExp' u (proj₂ p))
toExp : {A} ( {X} PH X A) Exp [] A
toExp {A} t = toExp' t λ Δ free-thm t _ _
-- examples
------------------------------------------------------------
t0 : {X} PH X ((o o) o o)
t0 = abs var
t1 : {X} PH X ((o o) o o)
t1 = abs λ f abs λ x app (var f) (app (var f) (var x))
test1 : toExp t0 abs (var Z)
test1 = refl
test2 : toExp t1 abs (abs (app (var (S Z)) (app (var (S Z)) (var Z))))
test2 = refl

View file

@ -1,50 +0,0 @@
open import Stlc hiding (⟹*-Preorder; _⟹*⟪_⟫_; example₀; example₁)
open import Relation.Binary.PropositionalEquality as P using (_≡_; _≢_; refl)
open import Relation.Binary using (Preorder)
import Relation.Binary.PreorderReasoning as PreorderReasoning
⟹*-Preorder : Preorder _ _ _
⟹*-Preorder = record
{ Carrier = Term
; _≈_ = _≡_
; __ = _⟹*_
; isPreorder = record
{ isEquivalence = P.isEquivalence
; reflexive = λ {refl ⟨⟩}
; trans = _>>_
}
}
open PreorderReasoning ⟹*-Preorder
using (_IsRelatedTo_; begin_; _∎) renaming (_≈⟨_⟩_ to _≡⟨_⟩_; _⟨_⟩_ to _⟹*⟨_⟩_)
infixr 2 _⟹*⟪_⟫_
_⟹*⟪_⟫_ : x {y z} x y y IsRelatedTo z x IsRelatedTo z
x ⟹*⟪ x⟹y yz = x ⟹*⟨ x⟹y yz
example₀ : not · true ⟹* false
example₀ =
begin
not · true
⟹*⟪ β⇒ value-true
if true then false else true
⟹*⟪ β𝔹₁
false
example₁ : · I · (not · false) ⟹* true
example₁ =
begin
· I · (not · false)
⟹*⟪ γ⇒₁ (β⇒ value-λ)
(λ[ x 𝔹 ] I · var x) · (not · false)
⟹*⟪ γ⇒₂ value-λ (β⇒ value-false)
(λ[ x 𝔹 ] I · var x) · (if false then false else true)
⟹*⟪ γ⇒₂ value-λ β𝔹₂
(λ[ x 𝔹 ] I · var x) · true
⟹*⟪ β⇒ value-true
I · true
⟹*⟪ β⇒ value-true
true

View file

@ -1,21 +0,0 @@
## Formalising preorder
\begin{code}
record IsPreorder {A : Set} (_≤_ : A → A → Set) : Set where
field
reflexive : ∀ {x : A} → x ≤ x
trans : ∀ {x y z : A} → x ≤ y → y ≤ z → x ≤ z
IsPreorder-≤ : IsPreorder _≤_
IsPreorder-≤ =
record
{ reflexive = ≤-refl
; trans = ≤-trans
}
record Preorder : Set₁ where
field
A : Set
_≺_ : A → A → Set
isPre : IsPreorder _≺_
\end{code}

File diff suppressed because it is too large Load diff

View file

@ -1,631 +0,0 @@
---
title : "Raw: Raw, Scoped, Typed"
layout : page
permalink : /Raw
---
This version uses raw terms.
The substitution algorithm is based on one by McBride.
## Imports
\begin{code}
module Raw where
\end{code}
\begin{code}
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong; cong₂; _≢_)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.List using (List; []; _∷_; _++_; map; foldr; filter; length)
open import Data.Nat using (; zero; suc; _+_)
import Data.String as String
open import Data.String using (String; _≟_)
open import Data.Product using (_×_; proj₁; proj₂; ∃; ∃-syntax) renaming (_,_ to ⟨_,_⟩)
-- open import Data.Sum using (_⊎_; inj₁; inj₂)
-- open import Function using (_∘_)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Negation using (¬?)
import Collections
pattern [_] w = w ∷ []
pattern [_,_] w x = w ∷ x ∷ []
pattern [_,_,_] w x y = w ∷ x ∷ y ∷ []
pattern [_,_,_,_] w x y z = w ∷ x ∷ y ∷ z ∷ []
\end{code}
## First development: Raw
\begin{code}
module Raw where
\end{code}
### Syntax
\begin{code}
infix 6 `λ_`→_
infixl 9 _·_
Id : Set
Id = String
data Type : Set where
` : Type
_`→_ : Type → Type → Type
data Ctx : Set where
ε : Ctx
_,_`:_ : Ctx → Id → Type → Ctx
data Term : Set where
⌊_⌋ : Id → Term
`λ_`→_ : Id → Term → Term
_·_ : Term → Term → Term
`zero : Term
`suc : Term → Term
\end{code}
### Example terms
\begin{code}
two : Term
two = `λ "s" `→ `λ "z" `→ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋)
plus : Term
plus = `λ "m" `→ `λ "n" `→ `λ "s" `→ `λ "z" `→
⌊ "m" ⌋ · ⌊ "s" ⌋ · (⌊ "n" ⌋ · ⌊ "s" ⌋ · ⌊ "z" ⌋)
norm : Term
norm = `λ "m" `→ ⌊ "m" ⌋ · (`λ "x" `→ `suc ⌊ "x" ⌋) · `zero
\end{code}
### Lists of identifiers
\begin{code}
open Collections (Id) (_≟_)
\end{code}
### Free variables
\begin{code}
free : Term → List Id
free (⌊ x ⌋) = [ x ]
free (`λ x `→ N) = free N \\ x
free (L · M) = free L ++ free M
free (`zero) = []
free (`suc M) = free M
\end{code}
### Identifier maps
\begin{code}
∅ : Id → Term
∅ x = ⌊ x ⌋
infixl 5 _,_↦_
_,_↦_ : (Id → Term) → Id → Term → (Id → Term)
(ρ , x ↦ M) w with w ≟ x
... | yes _ = M
... | no _ = ρ w
\end{code}
### Fresh variables
\begin{code}
fresh : List Id → Id → Id
fresh xs₀ y = helper xs₀ (length xs₀) y
where
prime : Id → Id
prime x = x String.++ ""
helper : List Id → → Id → Id
helper [] _ w = w
helper (x ∷ xs) n w with w ≟ x
helper (x ∷ xs) n w | no _ = helper xs n w
helper (x ∷ xs) (suc n) w | yes refl = helper xs₀ n (prime w)
helper (x ∷ xs) zero w | yes refl = ⊥-elim impossible
where postulate impossible : ⊥
\end{code}
### Substitution
\begin{code}
subst : List Id → (Id → Term) → Term → Term
subst ys ρ ⌊ x ⌋ = ρ x
subst ys ρ (`λ x `→ N) = `λ y `→ subst (y ∷ ys) (ρ , x ↦ ⌊ y ⌋) N
where
y = fresh ys x
subst ys ρ (L · M) = subst ys ρ L · subst ys ρ M
subst ys ρ (`zero) = `zero
subst ys ρ (`suc M) = `suc (subst ys ρ M)
_[_:=_] : Term → Id → Term → Term
N [ x := M ] = subst (free M ++ (free N \\ x)) (∅ , x ↦ M) N
\end{code}
### Testing substitution
\begin{code}
_ : fresh [ "y" ] "y" ≡ "y"
_ = refl
_ : fresh [ "z" ] "y" ≡ "y"
_ = refl
_ : (⌊ "s" ⌋ · ⌊ "s" ⌋ · ⌊ "z" ⌋) [ "z" := `zero ] ≡ (⌊ "s" ⌋ · ⌊ "s" ⌋ · `zero)
_ = refl
_ : (`λ "y" `→ ⌊ "x" ⌋) [ "x" := ⌊ "z" ⌋ ] ≡ (`λ "y" `→ ⌊ "z" ⌋)
_ = refl
_ : (`λ "y" `→ ⌊ "x" ⌋) [ "x" := ⌊ "y" ⌋ ] ≡ (`λ "y" `→ ⌊ "y" ⌋)
_ = refl
_ : (⌊ "s" ⌋ · ⌊ "s" ⌋ · ⌊ "z" ⌋) [ "s" := (`λ "m" `→ `suc ⌊ "m" ⌋) ]
[ "z" := `zero ]
≡ (`λ "m" `→ `suc ⌊ "m" ⌋) · (`λ "m" `→ `suc ⌊ "m" ⌋) · `zero
_ = refl
_ : subst [] (∅ , "m" ↦ two , "n" ↦ `zero) (⌊ "m" ⌋ · ⌊ "n" ⌋) ≡ (two · `zero)
_ = refl
\end{code}
### Values
\begin{code}
data Natural : Term → Set where
Zero :
--------------
Natural `zero
Suc : ∀ {V}
→ Natural V
-----------------
→ Natural (`suc V)
data Value : Term → Set where
Nat : ∀ {V}
→ Natural V
----------
→ Value V
Fun : ∀ {x N}
-----------------
→ Value (`λ x `→ N)
\end{code}
### Decide whether a term is a value
Not needed, and no longer correct.
\begin{code}
{-
value : ∀ (M : Term) → Dec (Value M)
value ⌊ x ⌋ = no (λ())
value (`λ x `→ N) = yes Fun
value (L · M) = no (λ())
value `zero = yes Zero
value (`suc M) with value M
... | yes VM = yes (Suc VM)
... | no ¬VM = no (λ{(Suc VM) → (¬VM VM)})
-}
\end{code}
### Reduction
\begin{code}
infix 4 _⟶_
data _⟶_ : Term → Term → Set where
ξ-·₁ : ∀ {L L M}
→ L ⟶ L
----------------
→ L · M ⟶ L · M
ξ-·₂ : ∀ {V M M}
→ Value V
→ M ⟶ M
----------------
→ V · M ⟶ V · M
β-→ : ∀ {x N V}
→ Value V
--------------------------------
→ (`λ x `→ N) · V ⟶ N [ x := V ]
ξ-suc : ∀ {M M}
→ M ⟶ M
------------------
→ `suc M ⟶ `suc M
\end{code}
### Reflexive and transitive closure
\begin{code}
infix 2 _⟶*_
infix 1 begin_
infixr 2 _⟶⟨_⟩_
infix 3 _∎
data _⟶*_ : Term → Term → Set where
_∎ : ∀ (M : Term)
-------------
→ M ⟶* M
_⟶⟨_⟩_ : ∀ (L : Term) {M N}
→ L ⟶ M
→ M ⟶* N
---------
→ L ⟶* N
begin_ : ∀ {M N} → (M ⟶* N) → (M ⟶* N)
begin M⟶*N = M⟶*N
\end{code}
### Decide whether a term reduces
\begin{code}
{-
data Step (M : Term) : Set where
step : ∀ {N}
→ M ⟶ N
-------
→ Step M
reduce : ∀ (M : Term) → Dec (Step M)
reduce ⌊ x ⌋ = no (λ{(step ())})
reduce (`λ x `→ N) = no (λ{(step ())})
reduce (L · M) with reduce L
... | yes (step L⟶L) = yes (step (ξ-·₁ L⟶L))
... | no ¬L⟶L with value L
... | no ¬VL = no (λ{ (step (β-→ _)) → (¬VL Fun)
; (step (ξ-·₁ L⟶L)) → (¬L⟶L (step L⟶L))
; (step (ξ-·₂ VL _)) → (¬VL VL) })
... | yes VL with reduce M
... | yes (step M⟶M) = yes (step (ξ-·₂ VL M⟶M))
... | no ¬M⟶M = {!!}
reduce `zero = {!!}
reduce (`suc M) = {!!}
-}
\end{code}
### Stuck terms
\begin{code}
data Stuck : Term → Set where
st-·₁ : ∀ {L M}
→ Stuck L
--------------
→ Stuck (L · M)
st-·₂ : ∀ {V M}
→ Value V
→ Stuck M
--------------
→ Stuck (V · M)
st-·-nat : ∀ {V M}
→ Natural V
--------------
→ Stuck (V · M)
st-suc-λ : ∀ {x N}
-------------------------
→ Stuck (`suc (`λ x `→ N))
st-suc : ∀ {M}
→ Stuck M
--------------
→ Stuck (`suc M)
\end{code}
### Closed terms
\begin{code}
Closed : Term → Set
Closed M = free M ≡ []
Ax-lemma : ∀ {x} → ¬ (Closed ⌊ x ⌋)
Ax-lemma ()
closed-·₁ : ∀ {L M} → Closed (L · M) → Closed L
closed-·₁ r = lemma r
where
lemma : ∀ {A : Set} {xs ys : List A} → xs ++ ys ≡ [] → xs ≡ []
lemma {xs = []} _ = refl
lemma {xs = x ∷ xs} ()
closed-·₂ : ∀ {L M} → Closed (L · M) → Closed M
closed-·₂ r = lemma r
where
lemma : ∀ {A : Set} {xs ys : List A} → xs ++ ys ≡ [] → ys ≡ []
lemma {xs = []} refl = refl
lemma {xs = x ∷ xs} ()
·-closed : ∀ {L M} → Closed L → Closed M → Closed (L · M)
·-closed r s = lemma r s
where
lemma : ∀ {A : Set} {xs ys : List A} → xs ≡ [] → ys ≡ [] → xs ++ ys ≡ []
lemma refl refl = refl
closed-suc : ∀ {M} → Closed (`suc M) → Closed M
closed-suc r = r
suc-closed : ∀ {M} → Closed M → Closed (`suc M)
suc-closed r = r
\end{code}
### Progress
\begin{code}
data Progress (M : Term) : Set where
step : ∀ {N}
→ M ⟶ N
-----------
→ Progress M
stuck :
Stuck M
-----------
→ Progress M
done :
Value M
-----------
→ Progress M
\end{code}
### Progress
\begin{code}
progress : ∀ (M : Term) → Closed M → Progress M
progress ⌊ x ⌋ Cx = ⊥-elim (Ax-lemma Cx)
progress (L · M) CLM with progress L (closed-·₁ {L} {M} CLM)
... | step L⟶L = step (ξ-·₁ L⟶L)
... | stuck SL = stuck (st-·₁ SL)
... | done VL with progress M (closed-·₂ {L} {M} CLM)
... | step M⟶M = step (ξ-·₂ VL M⟶M)
... | stuck SM = stuck (st-·₂ VL SM)
... | done VM with VL
... | Nat NL = stuck (st-·-nat NL)
... | Fun = step (β-→ VM)
progress (`λ x `→ N) CxN = done Fun
progress `zero Cz = done (Nat Zero)
progress (`suc M) CsM with progress M (closed-suc {M} CsM)
... | step M⟶M = step (ξ-suc M⟶M)
... | stuck SM = stuck (st-suc SM)
... | done (Nat NL) = done (Nat (Suc NL))
... | done Fun = stuck st-suc-λ
\end{code}
### Preservation
Preservation of closed terms is not so easy.
\begin{code}
preservation : ∀ {M N : Term} → Closed M → M ⟶ N → Closed N
preservation = {!!}
{-
preservation CLM (ξ-·₁ L⟶L)
= ·-closed (preservation (closed-·₁ CLM) L⟶L) (closed-·₂ CLM)
preservation CLM (ξ-·₂ _ M⟶M)
= ·-closed (closed-·₁ CLM) (preservation (closed-·₂ CLM) M⟶M)
preservation CM (β-→ VM) = {!!} -- requires closure under substitution!
preservation CM (ξ-suc M⟶M)
= suc-closed (preservation (closed-suc CM) M⟶M)
-}
\end{code}
### Evaluation
\begin{code}
Gas : Set
Gas =
data Eval (M : Term) : Set where
out-of-gas : ∀ {N} → M ⟶* N → Eval M
stuck : ∀ {N} → M ⟶* N → Stuck N → Eval M
done : ∀ {V} → M ⟶* V → Value V → Eval M
eval : Gas → (L : Term) → Closed L → Eval L
eval zero L CL = out-of-gas (L ∎)
eval (suc n) L CL with progress L CL
... | stuck SL = stuck (L ∎) SL
... | done VL = done (L ∎) VL
... | step {M} L⟶M with eval n M (preservation CL L⟶M)
... | out-of-gas M⟶*N = out-of-gas (L ⟶⟨ L⟶M ⟩ M⟶*N)
... | stuck M⟶*N SN = stuck (L ⟶⟨ L⟶M ⟩ M⟶*N) SN
... | done M⟶*V VV = done (L ⟶⟨ L⟶M ⟩ M⟶*V) VV
\end{code}
## Second development: Scoped
\begin{code}
module Scoped where
\end{code}
### Syntax
\begin{code}
infix 4 _⊢*
infix 4 _∋*
infixl 5 _,*
infix 5 `λ_`→_
infixl 6 _·_
infix 7 S_
Id : Set
Id = String
data Ctx : Set where
ε : Ctx
_,* : Ctx → Ctx
data _∋* : Ctx → Set where
Z : ∀ {Γ}
------------
→ Γ ,* ∋*
S_ : ∀ {Γ}
→ Γ ∋*
--------
→ Γ ,* ∋*
data _⊢* : Ctx → Set where
⌊_⌋ : ∀ {Γ}
→ Γ ∋*
-----
→ Γ ⊢*
`λ_`→_ : ∀ {Γ} (x : Id)
→ Γ ,* ⊢*
--------
→ Γ ⊢*
_·_ : ∀ {Γ}
→ Γ ⊢*
→ Γ ⊢*
-----
→ Γ ⊢*
`zero : ∀ {Γ}
-----
→ Γ ⊢*
`suc : ∀ {Γ}
→ Γ ⊢*
-----
→ Γ ⊢*
\end{code}
## Conversion: Raw to Scoped
\begin{code}
infix 4 _∈_
data _∈_ : Id → List Id → Set where
here : ∀ {x xs} →
----------
x ∈ x ∷ xs
there : ∀ {w x xs} →
w ∈ xs →
----------
w ∈ x ∷ xs
_?∈_ : ∀ (x : Id) (xs : List Id) → Dec (x ∈ xs)
x ?∈ [] = no (λ())
x ?∈ (y ∷ ys) with x ≟ y
... | yes refl = yes here
... | no x≢ with x ?∈ ys
... | yes x∈ = yes (there x∈)
... | no x∉ = no (λ{ here → x≢ refl
; (there x∈) → x∉ x∈
})
distinct : List Id → List Id
distinct [] = []
distinct (x ∷ xs) with x ?∈ distinct xs
... | yes x∈ = distinct xs
... | no x∉ = x ∷ distinct xs
context : Raw.Term → Ctx
context M = helper (distinct (Raw.free M))
where
helper : List Id → Ctx
helper [] = ε
helper (x ∷ xs) = helper xs ,*
raw→scoped : (M : Raw.Term) → (context M ⊢*)
raw→scoped M = {!!}
where
xs₀ = distinct (Raw.free M)
{-
The following does not work because `context M` should shrink on recursive calls.
lookup : Id → (context M ⊢*)
lookup w = helper w xs₀
where
helper : Id → List Id → (context M ⊢*)
helper w [] = ⊥-elim impossible
where postulate impossible : ⊥
helper w (x ∷ xs) with w ≟ x
... | yes _ = Z
... | no _ = S (helper xs)
-}
\end{code}
## Third development: Typed
\begin{code}
module Typed where
\end{code}
infix 4 _⊢_
infix 4 _∋_
infixl 5 _,_
infixr 5 _`→_
infix 5 ƛ_`→_
infixl 6 _·_
infix 7 S_
data Type : Set where
` : Type
_`→_ : Type → Type → Type
data _∋_ : Ctx → Type → Set where
Z : ∀ {Γ A}
----------
→ Γ , A ∋ A
S_ : ∀ {Γ A B}
→ Γ ∋ B
---------
→ Γ , A ∋ B
data _⊢_ : Ctx → Type → Set where
⌊_⌋ : ∀ {Γ} {A}
→ Γ ∋ A
------
→ Γ ⊢ A
`λ_`→_ : ∀ {Γ A B} (x : Id)
→ Γ , A ⊢ B
-----------
→ Γ ⊢ A `→ B
_·_ : ∀ {Γ} {A B}
→ Γ ⊢ A `→ B
→ Γ ⊢ A
-----------
→ Γ ⊢ B
`zero : ∀ {Γ}
----------
→ Γ ⊢ `
`suc : ∀ {Γ}
→ Γ ⊢ `
-------
→ Γ ⊢ `
\end{code}

View file

@ -1,687 +0,0 @@
---
title : "Raw: Raw, Scoped, Typed"
layout : page
permalink : /Raw
---
This version uses raw terms.
The substitution algorithm is based on one by McBride.
## Imports
\begin{code}
module Raw where
\end{code}
\begin{code}
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong; cong₂; _≢_)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.List using (List; []; _∷_; _++_; map; foldr; filter; length)
open import Data.Nat using (; zero; suc; _+_)
import Data.String as String
open import Data.String using (String; _≟_)
open import Data.Product using (_×_; proj₁; proj₂; ∃; ∃-syntax) renaming (_,_ to ⟨_,_⟩)
-- open import Data.Sum using (_⊎_; inj₁; inj₂)
-- open import Function using (_∘_)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Negation using (¬?)
import Collections
pattern [_] w = w ∷ []
pattern [_,_] w x = w ∷ x ∷ []
pattern [_,_,_] w x y = w ∷ x ∷ y ∷ []
pattern [_,_,_,_] w x y z = w ∷ x ∷ y ∷ z ∷ []
\end{code}
## Identifiers
\begin{code}
Id : Set
Id = String
\end{code}
### Fresh variables
\begin{code}
fresh : List Id → Id → Id
fresh xs₀ y = helper xs₀ (length xs₀) y
where
prime : Id → Id
prime x = x String.++ ""
helper : List Id → → Id → Id
helper [] _ w = w
helper (x ∷ xs) n w with w ≟ x
helper (x ∷ xs) n w | no _ = helper xs n w
helper (x ∷ xs) (suc n) w | yes refl = helper xs₀ n (prime w)
helper (x ∷ xs) zero w | yes refl = ⊥-elim impossible
where postulate impossible : ⊥
\end{code}
### Lists of identifiers
\begin{code}
open Collections (Id) (_≟_)
\end{code}
## First development: Raw
\begin{code}
module Raw where
\end{code}
### Syntax
\begin{code}
infix 6 `λ_`→_
infixl 9 _·_
data Type : Set where
` : Type
_`→_ : Type → Type → Type
data Ctx : Set where
ε : Ctx
_,_`:_ : Ctx → Id → Type → Ctx
data Term : Set where
⌊_⌋ : Id → Term
`λ_`→_ : Id → Term → Term
_·_ : Term → Term → Term
`zero : Term
`suc : Term → Term
\end{code}
### Example terms
\begin{code}
two : Term
two = `λ "s" `→ `λ "z" `→ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋)
plus : Term
plus = `λ "m" `→ `λ "n" `→ `λ "s" `→ `λ "z" `→
⌊ "m" ⌋ · ⌊ "s" ⌋ · (⌊ "n" ⌋ · ⌊ "s" ⌋ · ⌊ "z" ⌋)
norm : Term
norm = `λ "m" `→ ⌊ "m" ⌋ · (`λ "x" `→ `suc ⌊ "x" ⌋) · `zero
\end{code}
### Free variables
\begin{code}
free : Term → List Id
free (⌊ x ⌋) = [ x ]
free (`λ x `→ N) = free N \\ x
free (L · M) = free L ++ free M
free (`zero) = []
free (`suc M) = free M
\end{code}
### Identifier maps
\begin{code}
∅ : Id → Term
∅ x = ⌊ x ⌋
infixl 5 _,_↦_
_,_↦_ : (Id → Term) → Id → Term → (Id → Term)
(ρ , x ↦ M) w with w ≟ x
... | yes _ = M
... | no _ = ρ w
\end{code}
### Fresh variables
### Substitution
\begin{code}
subst : List Id → (Id → Term) → Term → Term
subst ys ρ ⌊ x ⌋ = ρ x
subst ys ρ (`λ x `→ N) = `λ y `→ subst (y ∷ ys) (ρ , x ↦ ⌊ y ⌋) N
where
y = fresh ys x
subst ys ρ (L · M) = subst ys ρ L · subst ys ρ M
subst ys ρ (`zero) = `zero
subst ys ρ (`suc M) = `suc (subst ys ρ M)
_[_:=_] : Term → Id → Term → Term
N [ x := M ] = subst (free M ++ (free N \\ x)) (∅ , x ↦ M) N
\end{code}
### Testing substitution
\begin{code}
_ : fresh [ "y" ] "y" ≡ "y"
_ = refl
_ : fresh [ "z" ] "y" ≡ "y"
_ = refl
_ : (⌊ "s" ⌋ · ⌊ "s" ⌋ · ⌊ "z" ⌋) [ "z" := `zero ] ≡ (⌊ "s" ⌋ · ⌊ "s" ⌋ · `zero)
_ = refl
_ : (`λ "y" `→ ⌊ "x" ⌋) [ "x" := ⌊ "z" ⌋ ] ≡ (`λ "y" `→ ⌊ "z" ⌋)
_ = refl
_ : (`λ "y" `→ ⌊ "x" ⌋) [ "x" := ⌊ "y" ⌋ ] ≡ (`λ "y" `→ ⌊ "y" ⌋)
_ = refl
_ : (⌊ "s" ⌋ · ⌊ "s" ⌋ · ⌊ "z" ⌋) [ "s" := (`λ "m" `→ `suc ⌊ "m" ⌋) ]
[ "z" := `zero ]
≡ (`λ "m" `→ `suc ⌊ "m" ⌋) · (`λ "m" `→ `suc ⌊ "m" ⌋) · `zero
_ = refl
_ : subst [] (∅ , "m" ↦ two , "n" ↦ `zero) (⌊ "m" ⌋ · ⌊ "n" ⌋) ≡ (two · `zero)
_ = refl
\end{code}
### Values
\begin{code}
data Natural : Term → Set where
Zero :
--------------
Natural `zero
Suc : ∀ {V}
→ Natural V
-----------------
→ Natural (`suc V)
data Value : Term → Set where
Nat : ∀ {V}
→ Natural V
----------
→ Value V
Fun : ∀ {x N}
-----------------
→ Value (`λ x `→ N)
\end{code}
### Decide whether a term is a value
Not needed, and no longer correct.
\begin{code}
{-
value : ∀ (M : Term) → Dec (Value M)
value ⌊ x ⌋ = no (λ())
value (`λ x `→ N) = yes Fun
value (L · M) = no (λ())
value `zero = yes Zero
value (`suc M) with value M
... | yes VM = yes (Suc VM)
... | no ¬VM = no (λ{(Suc VM) → (¬VM VM)})
-}
\end{code}
### Reduction
\begin{code}
infix 4 _⟶_
data _⟶_ : Term → Term → Set where
ξ-·₁ : ∀ {L L M}
→ L ⟶ L
----------------
→ L · M ⟶ L · M
ξ-·₂ : ∀ {V M M}
→ Value V
→ M ⟶ M
----------------
→ V · M ⟶ V · M
β-→ : ∀ {x N V}
→ Value V
--------------------------------
→ (`λ x `→ N) · V ⟶ N [ x := V ]
ξ-suc : ∀ {M M}
→ M ⟶ M
------------------
→ `suc M ⟶ `suc M
\end{code}
### Reflexive and transitive closure
\begin{code}
infix 2 _⟶*_
infix 1 begin_
infixr 2 _⟶⟨_⟩_
infix 3 _∎
data _⟶*_ : Term → Term → Set where
_∎ : ∀ (M : Term)
-------------
→ M ⟶* M
_⟶⟨_⟩_ : ∀ (L : Term) {M N}
→ L ⟶ M
→ M ⟶* N
---------
→ L ⟶* N
begin_ : ∀ {M N} → (M ⟶* N) → (M ⟶* N)
begin M⟶*N = M⟶*N
\end{code}
### Decide whether a term reduces
\begin{code}
{-
data Step (M : Term) : Set where
step : ∀ {N}
→ M ⟶ N
-------
→ Step M
reduce : ∀ (M : Term) → Dec (Step M)
reduce ⌊ x ⌋ = no (λ{(step ())})
reduce (`λ x `→ N) = no (λ{(step ())})
reduce (L · M) with reduce L
... | yes (step L⟶L) = yes (step (ξ-·₁ L⟶L))
... | no ¬L⟶L with value L
... | no ¬VL = no (λ{ (step (β-→ _)) → (¬VL Fun)
; (step (ξ-·₁ L⟶L)) → (¬L⟶L (step L⟶L))
; (step (ξ-·₂ VL _)) → (¬VL VL) })
... | yes VL with reduce M
... | yes (step M⟶M) = yes (step (ξ-·₂ VL M⟶M))
... | no ¬M⟶M = {!!}
reduce `zero = {!!}
reduce (`suc M) = {!!}
-}
\end{code}
### Stuck terms
\begin{code}
data Stuck : Term → Set where
st-·₁ : ∀ {L M}
→ Stuck L
--------------
→ Stuck (L · M)
st-·₂ : ∀ {V M}
→ Value V
→ Stuck M
--------------
→ Stuck (V · M)
st-·-nat : ∀ {V M}
→ Natural V
--------------
→ Stuck (V · M)
st-suc-λ : ∀ {x N}
-------------------------
→ Stuck (`suc (`λ x `→ N))
st-suc : ∀ {M}
→ Stuck M
--------------
→ Stuck (`suc M)
\end{code}
### Closed terms
\begin{code}
Closed : Term → Set
Closed M = free M ≡ []
Ax-lemma : ∀ {x} → ¬ (Closed ⌊ x ⌋)
Ax-lemma ()
closed-·₁ : ∀ {L M} → Closed (L · M) → Closed L
closed-·₁ r = lemma r
where
lemma : ∀ {A : Set} {xs ys : List A} → xs ++ ys ≡ [] → xs ≡ []
lemma {xs = []} _ = refl
lemma {xs = x ∷ xs} ()
closed-·₂ : ∀ {L M} → Closed (L · M) → Closed M
closed-·₂ r = lemma r
where
lemma : ∀ {A : Set} {xs ys : List A} → xs ++ ys ≡ [] → ys ≡ []
lemma {xs = []} refl = refl
lemma {xs = x ∷ xs} ()
·-closed : ∀ {L M} → Closed L → Closed M → Closed (L · M)
·-closed r s = lemma r s
where
lemma : ∀ {A : Set} {xs ys : List A} → xs ≡ [] → ys ≡ [] → xs ++ ys ≡ []
lemma refl refl = refl
closed-suc : ∀ {M} → Closed (`suc M) → Closed M
closed-suc r = r
suc-closed : ∀ {M} → Closed M → Closed (`suc M)
suc-closed r = r
\end{code}
### Progress
\begin{code}
data Progress (M : Term) : Set where
step : ∀ {N}
→ M ⟶ N
-----------
→ Progress M
stuck :
Stuck M
-----------
→ Progress M
done :
Value M
-----------
→ Progress M
\end{code}
### Progress
\begin{code}
progress : ∀ (M : Term) → Closed M → Progress M
progress ⌊ x ⌋ Cx = ⊥-elim (Ax-lemma Cx)
progress (L · M) CLM with progress L (closed-·₁ {L} {M} CLM)
... | step L⟶L = step (ξ-·₁ L⟶L)
... | stuck SL = stuck (st-·₁ SL)
... | done VL with progress M (closed-·₂ {L} {M} CLM)
... | step M⟶M = step (ξ-·₂ VL M⟶M)
... | stuck SM = stuck (st-·₂ VL SM)
... | done VM with VL
... | Nat NL = stuck (st-·-nat NL)
... | Fun = step (β-→ VM)
progress (`λ x `→ N) CxN = done Fun
progress `zero Cz = done (Nat Zero)
progress (`suc M) CsM with progress M (closed-suc {M} CsM)
... | step M⟶M = step (ξ-suc M⟶M)
... | stuck SM = stuck (st-suc SM)
... | done (Nat NL) = done (Nat (Suc NL))
... | done Fun = stuck st-suc-λ
\end{code}
### Preservation
Preservation of closed terms is not so easy.
\begin{code}
preservation : ∀ {M N : Term} → Closed M → M ⟶ N → Closed N
preservation = {!!}
{-
preservation CLM (ξ-·₁ L⟶L)
= ·-closed (preservation (closed-·₁ CLM) L⟶L) (closed-·₂ CLM)
preservation CLM (ξ-·₂ _ M⟶M)
= ·-closed (closed-·₁ CLM) (preservation (closed-·₂ CLM) M⟶M)
preservation CM (β-→ VM) = {!!} -- requires closure under substitution!
preservation CM (ξ-suc M⟶M)
= suc-closed (preservation (closed-suc CM) M⟶M)
-}
\end{code}
### Evaluation
\begin{code}
Gas : Set
Gas =
data Eval (M : Term) : Set where
out-of-gas : ∀ {N} → M ⟶* N → Eval M
stuck : ∀ {N} → M ⟶* N → Stuck N → Eval M
done : ∀ {V} → M ⟶* V → Value V → Eval M
eval : Gas → (L : Term) → Closed L → Eval L
eval zero L CL = out-of-gas (L ∎)
eval (suc n) L CL with progress L CL
... | stuck SL = stuck (L ∎) SL
... | done VL = done (L ∎) VL
... | step {M} L⟶M with eval n M (preservation CL L⟶M)
... | out-of-gas M⟶*N = out-of-gas (L ⟶⟨ L⟶M ⟩ M⟶*N)
... | stuck M⟶*N SN = stuck (L ⟶⟨ L⟶M ⟩ M⟶*N) SN
... | done M⟶*V VV = done (L ⟶⟨ L⟶M ⟩ M⟶*V) VV
\end{code}
## Second development: Scoped
\begin{code}
module Scoped where
\end{code}
### Syntax
\begin{code}
infix 4 _⊢*
infix 4 _∋*
infixl 5 _,*
infix 5 `λ_`→_
infixl 6 _·_
data Ctx : Set where
ε : Ctx
_,* : Ctx → Ctx
data _∋* : Ctx → Set where
Z : ∀ {Γ}
------------
→ Γ ,* ∋*
S : ∀ {Γ}
→ Γ ∋*
--------
→ Γ ,* ∋*
data _⊢* : Ctx → Set where
⌊_⌋ : ∀ {Γ}
→ Γ ∋*
-----
→ Γ ⊢*
`λ_`→_ : ∀ {Γ} (x : Id)
→ Γ ,* ⊢*
--------
→ Γ ⊢*
_·_ : ∀ {Γ}
→ Γ ⊢*
→ Γ ⊢*
-----
→ Γ ⊢*
`zero : ∀ {Γ}
-----
→ Γ ⊢*
`suc : ∀ {Γ}
→ Γ ⊢*
-----
→ Γ ⊢*
\end{code}
### Shorthand for variables
\begin{code}
short : ∀{Γ} → → Γ ∋*
short {ε} n = ⊥-elim impossible
where postulate impossible : ⊥
short {Γ ,*} zero = Z
short {Γ ,*} (suc n) = S (short {Γ} n)
⌈_⌉ : ∀{Γ} → → Γ ⊢*
⌈ n ⌉ = ⌊ short n ⌋
\end{code}
### Sample terms
\begin{code}
two : ∀{Γ} → Γ ⊢*
two = `λ "s" `→ `λ "z" `→ ⌈ 1 ⌉ · (⌈ 1 ⌉ · ⌈ 0 ⌉)
plus : ∀{Γ} → Γ ⊢*
plus = `λ "m" `→ `λ "n" `→ `λ "s" `→ `λ "z" `→
⌈ 3 ⌉ · ⌈ 1 ⌉ · (⌈ 2 ⌉ · ⌈ 1 ⌉ · ⌈ 0 ⌉)
norm : ∀{Γ} → Γ ⊢*
norm = `λ "m" `→ ⌈ 0 ⌉ · (`λ "x" `→ `suc ⌈ 0 ⌉) · `zero
\end{code}
### Conversion: Raw to Scoped
Doing the conversion from Raw to Scoped is hard.
The conversion takes a list of variables, with the invariant
is that every free variable in the term appears in this list.
But ensuring that the invariant holds is difficult.
One way around this may be *not* to ensure the invariant,
and to return `impossible` if it is violated. If the
conversion succeeds, it is guaranteed to return a term of
the correct type.
\begin{code}
raw→scoped : Raw.Term → ε ⊢*
raw→scoped M = helper [] M
where
lookup : List Id → Id →
lookup [] w = ⊥-elim impossible
where postulate impossible : ⊥
lookup (x ∷ xs) w with w ≟ x
... | yes _ = 0
... | no _ = suc (lookup xs w)
helper : ∀ {Γ} → List Id → Raw.Term → Γ ⊢*
helper xs Raw.⌊ x ⌋ = ⌈ lookup xs x ⌉
helper xs (Raw.`λ x `→ N) = `λ x `→ helper (x ∷ xs) N
helper xs (L Raw.· M) = helper xs L · helper xs M
helper xs Raw.`zero = `zero
helper xs (Raw.`suc M) = `suc (helper xs M)
\end{code}
### Test cases
\begin{code}
_ : raw→scoped Raw.two ≡ two
_ = refl
_ : raw→scoped Raw.plus ≡ plus
_ = refl
_ : raw→scoped Raw.norm ≡ norm
_ = refl
\end{code}
### Conversion: Scoped to Raw
\begin{code}
scoped→raw : ε ⊢* → Raw.Term
scoped→raw M = helper [] M
where
index : ∀ {Γ} → List Id → Γ ∋* → Id
index [] w = ⊥-elim impossible
where postulate impossible : ⊥
index (x ∷ xs) Z = x
index (x ∷ xs) (S w) = index xs w
helper : ∀ {Γ} → List Id → Γ ⊢* → Raw.Term
helper xs ⌊ x ⌋ = Raw.⌊ index xs x ⌋
helper xs (`λ x `→ N) = Raw.`λ y `→ helper (y ∷ xs) N
where y = fresh xs x
helper xs (L · M) = (helper xs L) Raw.· (helper xs M)
helper xs `zero = Raw.`zero
helper xs (`suc M) = Raw.`suc (helper xs M)
\end{code}
This is all straightforward. But what I would like to do is show that
meaning is preserved (or reductions are preserved) by the translations,
and that would be harder. I'm especially concerned by how one would
show the call to fresh is needed, or what goes wrong if it is omitted.
### Test cases
\begin{code}
_ : scoped→raw two ≡ Raw.two
_ = refl
_ : scoped→raw plus ≡ Raw.plus
_ = refl
_ : scoped→raw norm ≡ Raw.norm
_ = refl
_ : scoped→raw (`λ "x" `→ `λ "x" `→ ⌈ 1 ⌉ · ⌈ 0 ⌉) ≡
Raw.`λ "x" `→ Raw.`λ "x" `→ Raw.⌊ "x" ⌋ Raw.· Raw.⌊ "x" ⌋
_ = refl
\end{code}
## Third development: Typed
\begin{code}
module Typed where
infix 4 _⊢_
infix 4 _∋_
infixl 5 _,_
infixr 5 _`→_
infix 5 `λ_`→_
infixl 6 _·_
data Type : Set where
` : Type
_`→_ : Type → Type → Type
data Ctx : Set where
ε : Ctx
_,_ : Ctx → Type → Ctx
data _∋_ : Ctx → Type → Set where
Z : ∀ {Γ A}
----------
→ Γ , A ∋ A
S : ∀ {Γ A B}
→ Γ ∋ B
---------
→ Γ , A ∋ B
data _⊢_ : Ctx → Type → Set where
⌊_⌋ : ∀ {Γ} {A}
→ Γ ∋ A
------
→ Γ ⊢ A
`λ_`→_ : ∀ {Γ A B} (x : Id)
→ Γ , A ⊢ B
-----------
→ Γ ⊢ A `→ B
_·_ : ∀ {Γ} {A B}
→ Γ ⊢ A `→ B
→ Γ ⊢ A
-----------
→ Γ ⊢ B
`zero : ∀ {Γ}
----------
→ Γ ⊢ `
`suc : ∀ {Γ}
→ Γ ⊢ `
-------
→ Γ ⊢ `
\end{code}

View file

@ -1,86 +0,0 @@
open import Data.Nat using (; zero; suc; _+_)
import Relation.Binary.PropositionalEquality as Eq
import Relation.Binary.PreorderReasoning as Re
module ReEq = Re (Eq.preorder )
open ReEq using (begin_; _∎; _IsRelatedTo_) renaming (_≈⟨⟩_ to _≡⟨⟩_; _⟨_⟩_ to _≡⟨_⟩_)
open Eq using (_≡_; refl; sym; trans)
lift : {m n : } m n suc m suc n
lift refl = refl
+-assoc : (m n p : ) (m + n) + p m + (n + p)
+-assoc zero n p =
begin
(zero + n) + p
≡⟨⟩
zero + (n + p)
+-assoc (suc m) n p =
begin
(suc m + n) + p
≡⟨⟩
suc ((m + n) + p)
≡⟨ lift (+-assoc m n p)
suc (m + (n + p))
≡⟨⟩
suc m + (n + p)
+-identity : (m : ) m + zero m
+-identity zero =
begin
zero + zero
≡⟨⟩
zero
+-identity (suc m) =
begin
suc m + zero
≡⟨⟩
suc (m + zero)
≡⟨ lift (+-identity m)
suc m
+-suc : (m n : ) m + suc n suc (m + n)
+-suc zero n =
begin
zero + suc n
≡⟨⟩
suc n
≡⟨⟩
suc (zero + n)
+-suc (suc m) n =
begin
suc m + suc n
≡⟨⟩
suc (m + suc n)
≡⟨ lift (+-suc m n)
suc (suc (m + n))
≡⟨⟩
suc (suc m + n)
+-comm : (m n : ) m + n n + m
+-comm m zero =
begin
m + zero
≡⟨ +-identity m
m
≡⟨⟩
zero + m
+-comm m (suc n) =
begin
m + suc n
≡⟨ +-suc m n
suc (m + n)
≡⟨ lift (+-comm m n)
suc (n + m)
≡⟨⟩
suc n + m

View file

@ -1,82 +0,0 @@
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans)
open Eq.≡-Reasoning
open import Data.Nat using (; zero; suc; _+_)
lift : {m n : } m n suc m suc n
lift refl = refl
+-assoc : (m n p : ) (m + n) + p m + (n + p)
+-assoc zero n p =
begin
(zero + n) + p
≡⟨⟩
zero + (n + p)
+-assoc (suc m) n p =
begin
(suc m + n) + p
≡⟨⟩
suc ((m + n) + p)
≡⟨ lift (+-assoc m n p)
suc (m + (n + p))
≡⟨⟩
suc m + (n + p)
+-identity : (m : ) m + zero m
+-identity zero =
begin
zero + zero
≡⟨⟩
zero
+-identity (suc m) =
begin
suc m + zero
≡⟨⟩
suc (m + zero)
≡⟨ lift (+-identity m)
suc m
+-suc : (m n : ) m + suc n suc (m + n)
+-suc zero n =
begin
zero + suc n
≡⟨⟩
suc n
≡⟨⟩
suc (zero + n)
+-suc (suc m) n =
begin
suc m + suc n
≡⟨⟩
suc (m + suc n)
≡⟨ lift (+-suc m n)
suc (suc (m + n))
≡⟨⟩
suc (suc m + n)
+-comm : (m n : ) m + n n + m
+-comm m zero =
begin
m + zero
≡⟨ +-identity m
m
≡⟨⟩
zero + m
+-comm m (suc n) =
begin
m + suc n
≡⟨ +-suc m n
suc (m + n)
≡⟨ lift (+-comm m n)
suc (n + m)
≡⟨⟩
suc n + m

View file

@ -1,76 +0,0 @@
Old version of reduction
## Imports
\begin{code}
open import Maps using (Id; id; _≟_; PartialMap; module PartialMap)
open PartialMap using (∅) renaming (_,_↦_ to _,__)
-- open import Data.String using (String)
open import Data.Nat using ()
open import Data.Maybe using (Maybe; just; nothing)
open import Relation.Nullary using (Dec; yes; no)
open import Relation.Binary.PropositionalEquality using (_≡_; _≢_; refl)
open import Stlc hiding (_⟹*_; _⟹⟨_⟩_; _∎; reduction₁; reduction₂)
\end{code}
## Reflexive and transitive closure
\begin{code}
Rel : Set → Set₁
Rel A = A → A → Set
infixl 10 _>>_
data _* {A : Set} (R : Rel A) : Rel A where
⟨⟩ : ∀ {x : A} → (R *) x x
⟨_⟩ : ∀ {x y : A} → R x y → (R *) x y
_>>_ : ∀ {x y z : A} → (R *) x y → (R *) y z → (R *) x z
infix 10 _⟹*_
_⟹*_ : Rel Term
_⟹*_ = (_⟹_) *
\end{code}
## Notation for setting out reductions
\begin{code}
infixr 2 _⟹⟨_⟩_
infix 3 _∎
_⟹⟨_⟩_ : ∀ L {M N} → L ⟹ M → M ⟹* N → L ⟹* N
L ⟹⟨ L⟹M ⟩ M⟹*N = ⟨ L⟹M ⟩ >> M⟹*N
_∎ : ∀ M → M ⟹* M
M ∎ = ⟨⟩
\end{code}
## Example reduction derivations
\begin{code}
reduction₁ : not · true ⟹* false
reduction₁ =
not · true
⟹⟨ β⇒ value-true ⟩
if true then false else true
⟹⟨ β𝔹₁ ⟩
false
reduction₂ : two · not · true ⟹* true
reduction₂ =
two · not · true
⟹⟨ γ⇒₁ (β⇒ value-λ) ⟩
(λ[ x 𝔹 ] not · (not · var x)) · true
⟹⟨ β⇒ value-true ⟩
not · (not · true)
⟹⟨ γ⇒₂ value-λ (β⇒ value-true) ⟩
not · (if true then false else true)
⟹⟨ γ⇒₂ value-λ β𝔹₁ ⟩
not · false
⟹⟨ β⇒ value-false ⟩
if false then false else true
⟹⟨ β𝔹₂ ⟩
true
\end{code}

View file

@ -1,71 +0,0 @@
module Rev {A : Set} where
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong; cong₂; _≢_)
open Eq.≡-Reasoning
open import Data.Empty using (⊥; ⊥-elim)
open import Data.List
using (List; []; _∷_; _++_; map; foldr; replicate; length; _∷ʳ_)
-- renaming (reverse to rev)
open import Data.List.Properties
using (++-assoc; ++-identityʳ)
-- renaming (unfold-reverse to revʳ;
-- reverse-++-commute to rev-++;
-- reverse-involutive to rev-inv)
open import Data.List.All using (All; []; _∷_)
open import Data.List.All.Properties
renaming (++⁺ to _++All_)
pattern [_] x = x []
pattern [_,_] x y = x y []
pattern [_,_,_] x y z = x y z []
pattern [_,_,_,_] x y z w = x y z w []
rev : List A List A
rev [] = []
rev (x xs) = rev xs ++ [ x ]
rev-++ : xs ys rev (xs ++ ys) rev ys ++ rev xs
rev-++ [] ys =
begin
rev ([] ++ ys)
≡⟨ sym (++-identityʳ (rev ys))
rev ys ++ rev []
rev-++ (x xs) ys =
begin
rev (x xs ++ ys)
≡⟨⟩
rev (xs ++ ys) ++ [ x ]
≡⟨ cong (_++ [ x ]) (rev-++ xs ys)
(rev ys ++ rev xs) ++ [ x ]
≡⟨ ++-assoc (rev ys) (rev xs) [ x ]
rev ys ++ (rev xs ++ [ x ])
≡⟨⟩
rev ys ++ (rev (x xs))
rev-inv : xs rev (rev xs) xs
rev-inv [] =
begin
rev (rev [])
≡⟨⟩
[]
rev-inv (x xs) =
begin
rev (rev (x xs))
≡⟨⟩
rev (rev xs ++ [ x ])
≡⟨ rev-++ (rev xs) [ x ]
rev [ x ] ++ rev (rev xs)
≡⟨ cong (rev [ x ] ++_) (rev-inv xs)
rev [ x ] ++ xs
≡⟨⟩
x xs
revAll : (P : A Set) {xs} All P xs All P (rev xs)
revAll P [] = []
revAll P (Px Pxs) = revAll P Pxs ++All [ Px ]

View file

@ -1,60 +0,0 @@
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong)
open Eq.≡-Reasoning
open import Data.Nat using (; zero; suc; _+_; _*_)
open import Data.Nat.Properties.Simple using (+-suc)
open import Data.Product using (∃; ∃-syntax; _,_)
data even : Set
data odd : Set
data even where
even-zero : even zero
even-suc : {n : } odd n even (suc n)
data odd where
odd-suc : {n : } even n odd (suc n)
lemma : (m : ) 2 * suc m suc (suc (2 * m))
lemma m =
begin
2 * suc m
≡⟨⟩
suc m + (suc m + zero)
≡⟨⟩
suc (m + (suc (m + zero)))
≡⟨ cong suc (+-suc m (m + zero))
suc (suc (m + (m + zero)))
≡⟨⟩
suc (suc (2 * m))
∃-even : {n : } even n ∃[ m ] (2 * m n)
∃-odd : {n : } odd n ∃[ m ] (1 + 2 * m n)
∃-even even-zero = zero , refl
∃-even (even-suc o) with ∃-odd o
... | m , refl = suc m , lemma m
∃-odd (odd-suc e) with ∃-even e
... | m , refl = m , refl
∃-even : {n : } even n ∃[ m ] (n 2 * m)
∃-odd : {n : } odd n ∃[ m ] (n 1 + 2 * m)
∃-even even-zero = zero , refl
∃-even (even-suc o) with ∃-odd o
... | m , eqn rewrite eqn | +-suc m (m + 0) = suc m , {!!}
∃-odd (odd-suc e) with ∃-even e
... | m , eqn rewrite eqn = m , refl
data Even : Set where
ev0 : Even zero
ev2 : {n} Even n Even (suc (suc n))
ev-ex : {n : } Even n ∃[ m ] (2 * m n)
ev-ex ev0 = (zero , refl)
ev-ex (ev2 ev) with ev-ex ev
... | (m , refl) = (suc m , lemma m)

View file

@ -1,217 +0,0 @@
---
title : "SmallInherent"
layout : page
permalink : /SmallInherent/
---
\begin{code}
module plfa.SmallInherent where
open import Data.Empty using (⊥; ⊥-elim)
open import Data.Nat using (; zero; suc)
infix 4 _⊢_
infix 4 _∋_
infixl 5 _,_
infixr 7 _⇒_
infix 5 ƛ_
infixl 7 _·_
infix 9 `_
infix 9 S_
infix 9 #_
infix 1 begin_
infix 2 _—→_
infix 2 _—↠_
infixr 2 _—→⟨_⟩_
infix 3 _∎
data Type : Set where
_⇒_ : Type → Type → Type
` : Type
data Context : Set where
∅ : Context
_,_ : Context → Type → Context
data _∋_ : Context → Type → Set where
Z : ∀ {Γ A}
----------
→ Γ , A ∋ A
S_ : ∀ {Γ A B}
→ Γ ∋ A
---------
→ Γ , B ∋ A
data _⊢_ : Context → Type → Set where
`_ : ∀ {Γ} {A}
→ Γ ∋ A
------
→ Γ ⊢ A
ƛ_ : ∀ {Γ} {A B}
→ Γ , A ⊢ B
----------
→ Γ ⊢ A ⇒ B
_·_ : ∀ {Γ} {A B}
→ Γ ⊢ A ⇒ B
→ Γ ⊢ A
----------
→ Γ ⊢ B
lookup : Context → → Type
lookup (Γ , A) zero = A
lookup (Γ , _) (suc n) = lookup Γ n
lookup ∅ _ = ⊥-elim impossible
where postulate impossible : ⊥
count : ∀ {Γ} → (n : ) → Γ ∋ lookup Γ n
count {Γ , _} zero = Z
count {Γ , _} (suc n) = S (count n)
count {∅} _ = ⊥-elim impossible
where postulate impossible : ⊥
#_ : ∀ {Γ} → (n : ) → Γ ⊢ lookup Γ n
# n = ` count n
ext : ∀ {Γ Δ} → (∀ {A} → Γ ∋ A → Δ ∋ A)
----------------------------------
→ (∀ {A B} → Γ , B ∋ A → Δ , B ∋ A)
ext ρ Z = Z
ext ρ (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)
exts : ∀ {Γ Δ} → (∀ {A} → Γ ∋ A → Δ ⊢ A)
----------------------------------
→ (∀ {A B} → Γ , B ∋ A → Δ , B ⊢ A)
exts σ Z = ` Z
exts σ (S x) = rename S_ (σ x)
subst : ∀ {Γ Δ}
→ (∀ {A} → Γ ∋ A → Δ ⊢ A)
------------------------
→ (∀ {A} → Γ ⊢ A → Δ ⊢ A)
subst σ (` k) = σ k
subst σ (ƛ N) = ƛ (subst (exts σ) N)
subst σ (L · M) = (subst σ L) · (subst σ M)
_[_] : ∀ {Γ A B}
→ Γ , B ⊢ A
→ Γ ⊢ B
---------
→ Γ ⊢ A
_[_] {Γ} {A} {B} N M = subst {Γ , B} {Γ} σ {A} N
where
σ : ∀ {A} → Γ , B ∋ A → Γ ⊢ A
σ Z = M
σ (S x) = ` x
data Value : ∀ {Γ A} → Γ ⊢ A → Set where
V-ƛ : ∀ {Γ A B} {N : Γ , A ⊢ B}
---------------------------
→ Value (ƛ N)
data _—→_ : ∀ {Γ A} → (Γ ⊢ A) → (Γ ⊢ A) → Set where
ξ-·₁ : ∀ {Γ 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} {W : Γ ⊢ A}
→ Value W
-------------------
→ (ƛ N) · W —→ N [ W ]
data _—↠_ : ∀ {Γ A} → (Γ ⊢ A) → (Γ ⊢ A) → Set where
_∎ : ∀ {Γ A} (M : Γ ⊢ A)
--------
→ M —↠ M
_—→⟨_⟩_ : ∀ {Γ A} (L : Γ ⊢ A) {M N : Γ ⊢ A}
→ L —→ M
→ M —↠ N
---------
→ L —↠ N
begin_ : ∀ {Γ} {A} {M N : Γ ⊢ A}
→ M —↠ N
------
→ M —↠ N
begin M—↠N = M—↠N
data Progress {A} (M : ∅ ⊢ A) : Set where
step : ∀ {N : ∅ ⊢ A}
→ M —→ N
-------------
→ Progress M
done :
Value M
----------
→ Progress M
progress : ∀ {A} → (M : ∅ ⊢ A) → Progress M
progress (` ())
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)
data Gas : Set where
gas : → Gas
data Finished {Γ A} (N : Γ ⊢ A) : Set where
done :
Value N
----------
→ Finished N
out-of-gas :
----------
Finished N
data Steps : ∀ {A} → ∅ ⊢ A → Set where
steps : ∀ {A} {L N : ∅ ⊢ A}
→ L —↠ N
→ Finished N
----------
→ Steps L
eval : ∀ {A}
→ Gas
→ (L : ∅ ⊢ A)
-----------
→ Steps L
eval (gas zero) L = steps (L ∎) out-of-gas
eval (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) fin
\end{code}

View file

@ -1,74 +0,0 @@
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong)
open Eq.≡-Reasoning
open import Data.Nat using (; zero; suc)
open import Data.Product using (_×_; proj₁; proj₂) renaming (_,_ to ⟨_,_⟩)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Relation.Nullary using (¬_)
open import Relation.Nullary.Negation using (contraposition)
open import Data.Unit using (; tt)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.List using (List; []; _∷_; foldr; map)
open import Function using (_∘_)
double-negation : {A : Set} A ¬ ¬ A
double-negation x ¬x = ¬x x
triple-negation : {A : Set} ¬ ¬ ¬ A ¬ A
triple-negation ¬¬¬x x = ¬¬¬x (double-negation x)
Stable : Set Set
Stable A = ¬ ¬ A A
¬-stable : {A : Set} Stable (¬ A)
¬-stable = triple-negation
×-stable : {A B : Set} Stable A Stable B Stable (A × B)
×-stable ¬¬x→x ¬¬y→y ¬¬xy =
¬¬x→x (contraposition (contraposition proj₁) ¬¬xy)
, ¬¬y→y (contraposition (contraposition proj₂) ¬¬xy)
∀-stable : {A : Set} {B : A Set} ( (x : A) Stable (B x)) Stable ( (x : A) B x)
-stable x→¬¬y→y ¬¬∀x→y x =
x→¬¬y→y x (contraposition (contraposition λ{x→y x→y x}) ¬¬∀x→y)
-- Gödel-Gentzen translation
{--
data Var : Set where
zero : (n : ) Var (suc n)
suc : (n : ) Var n Var (suc n)
data Formula : Set where
_`≡_ : (n : ) Var n Var n Formula n
_`×_ : (n : ) Formula n Formula n Formula n
_`⊎_ : (n : ) Formula n Formula n Formula n
`¬_ : (n : ) Formula n Formula n
--}
data Formula : Set where
atomic : (A : Set) Formula
_`×_ : Formula Formula Formula
_`⊎_ : Formula Formula Formula
`¬_ : Formula Formula
interp : Formula Set
interp (atomic A) = A
interp (`A `× `B) = interp `A × interp `B
interp (`A `⊎ `B) = interp `A interp `B
interp ( `A) = ¬ interp `A
g : Formula Formula
g (atomic A) = (atomic A)
g (`A `× `B) = g `A `× g `B
g (`A `⊎ `B) = (( g `A) `× ( g `B))
g ( `A) = g `A
stable-g : (`A : Formula) Stable (interp (g `A))
stable-g (atomic A) = ¬-stable
stable-g (`A `× `B) = ×-stable (stable-g `A) (stable-g `B)
stable-g (`A `⊎ `B) = ¬-stable
stable-g ( `A) = ¬-stable

View file

@ -1,898 +0,0 @@
---
title : "StreamLambdaProp: Properties of Simply-Typed Lambda Calculus"
layout : page
permalink : /StreamLambdaProp/
---
[Variant of normalise that uses streams is at end]
\begin{code}
module StreamLambdaProp where
\end{code}
[Parts of this chapter take their text from chapter _Stlc_
of _Software Foundations_ (_Programming Language Foundations_).
Those parts will be revised.]
This chapter develops the fundamental theory of the Simply
Typed Lambda Calculus, particularly progress and preservation.
The development in this chapter was inspired by the corresponding
development in Chapter _StlcProp_ of _Software Foundations_
(_Programming Language Foundations_). It will turn
out that one of our technical choices in the previous chapter
(to introduce an explicit judgment `Γ ∋ x ⦂ A` in place of
treating a context as a function from identifiers to types)
permits a simpler development. In particular, we can prove substitution preserves
types without needing to develop a separate inductive definition of the
`appears_free_in` relation.
## Imports
\begin{code}
open import Relation.Binary.PropositionalEquality using (_≡_; _≢_; refl)
open import Data.String using (String; _≟_)
open import Data.Nat using (; zero; suc)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.Product
using (_×_; proj₁; proj₂; ∃; ∃-syntax)
renaming (_,_ to ⟨_,_⟩)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Function using (_∘_)
open import plta.Lambda
open Chain (Term) (_⟶_)
\end{code}
## Canonical Forms
The first step in establishing basic properties of reduction and typing
is to identify the possible _canonical forms_ (i.e., well-typed closed values)
belonging to each type. For function types the canonical forms are lambda-abstractions,
while for boolean types they are values `true` and `false`.
\begin{code}
infix 4 Canonical_⦂_
data Canonical_⦂_ : Term → Type → Set where
C-ƛ : ∀ {x A N B}
-----------------------------
→ Canonical (ƛ x ⇒ N) ⦂ (A ⇒ B)
C-zero :
--------------------
Canonical `zero ⦂ `
C-suc : ∀ {V}
→ Canonical V ⦂ `
---------------------
→ Canonical `suc V ⦂ `
canonical : ∀ {M A}
→ ∅ ⊢ M ⦂ A
→ Value M
---------------
→ Canonical M ⦂ A
canonical (Ax ()) ()
canonical (⊢ƛ ⊢N) V-ƛ = C-ƛ
canonical (⊢L · ⊢M) ()
canonical ⊢zero V-zero = C-zero
canonical (⊢suc ⊢V) (V-suc VV) = C-suc (canonical ⊢V VV)
canonical (⊢case ⊢L ⊢M ⊢N) ()
canonical (⊢μ ⊢M) ()
value : ∀ {M A}
→ Canonical M ⦂ A
----------------
→ Value M
value C-ƛ = V-ƛ
value C-zero = V-zero
value (C-suc CM) = V-suc (value CM)
\end{code}
## Progress
As before, the _progress_ theorem tells us that closed, well-typed
terms are not stuck: either a well-typed term can take a reduction
step or it is a value.
\begin{code}
data Progress (M : Term) : Set where
step : ∀ {N}
→ M ⟶ N
----------
→ Progress M
done :
Value M
----------
→ Progress M
progress : ∀ {M A}
→ ∅ ⊢ M ⦂ A
----------
→ Progress M
progress (Ax ())
progress (⊢ƛ ⊢N) = done V-ƛ
progress (⊢L · ⊢M) with progress ⊢L
... | step L⟶L = step (ξ-·₁ L⟶L)
... | done VL with progress ⊢M
... | step M⟶M = step (ξ-·₂ VL M⟶M)
... | done VM with canonical ⊢L VL
... | C-ƛ = step (β-ƛ· VM)
progress ⊢zero = done V-zero
progress (⊢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 VL with canonical ⊢L VL
... | C-zero = step β-case-zero
... | C-suc CL = step (β-case-suc (value CL))
progress (⊢μ ⊢M) = step β-μ
\end{code}
This code reads neatly in part because we consider the
`step` option before the `done` option. We could, of course,
do it the other way around, but then the `...` abbreviation
no longer works, and we will need to write out all the arguments
in full. In general, the rule of thumb is to consider the easy case
(here `step`) before the hard case (here `done`).
If you have two hard cases, you will have to expand out `...`
or introduce subsidiary functions.
\begin{code}
postulate
progress : ∀ M {A} → ∅ ⊢ M ⦂ A → Progress M
\end{code}
## Prelude to preservation
The other half of the type soundness property is the preservation
of types during reduction. For this, we need to develop
technical machinery for reasoning about variables and
substitution. Working from top to bottom (from the high-level
property we are actually interested in to the lowest-level
technical lemmas), the story goes like this:
- The _preservation theorem_ is proved by induction on a typing derivation.
The definition of `β-ƛ· uses substitution. To see that
this step preserves typing, we need to know that the substitution itself
does. So we prove a ...
- _substitution lemma_, stating that substituting a (closed) term
`V` for a variable `x` in a term `N` preserves the type of `N`.
The proof goes by induction on the typing derivation of `N`.
The lemma does not require that `V` be a value,
though in practice we only substitute values. The tricky cases
are the ones for variables and those that do binding, namely,
function abstraction, case over a natural, and fixpoints. In each
case, we discover that we need to take a term `V` that has been
shown to be well-typed in some context `Γ` and consider the same
term in a different context `Δ`. For this we prove a ...
- _renaming lemma_, showing that typing is preserved
under weakening of the context---a term `M`
well typed in `Γ` is also well typed in `Δ`, so long as
every free variable found in `Γ` is also found in `Δ`.
To make Agda happy, we need to formalize the story in the opposite
order.
### Renaming
Sometimes, when we have a proof `Γ ⊢ M ⦂ A`, we will need to
replace `Γ` by a different context `Δ`. When is it safe
to do this? Intuitively, whenever every variable given a type
by `Γ` is also given a type by `Δ`.
*(((Need to explain ext)))*
\begin{code}
ext : ∀ {Γ Δ}
→ (∀ {w B} → Γ ∋ w ⦂ B → Δ ∋ w ⦂ B)
-----------------------------------------------------
→ (∀ {w x A B} → Γ , x ⦂ A ∋ w ⦂ B → Δ , x ⦂ A ∋ w ⦂ B)
ext σ Z = Z
ext σ (S w≢ ∋w) = S w≢ (σ ∋w)
rename : ∀ {Γ Δ}
→ (∀ {w B} → Γ ∋ w ⦂ B → Δ ∋ w ⦂ B)
----------------------------------
→ (∀ {M A} → Γ ⊢ M ⦂ A → Δ ⊢ M ⦂ A)
rename σ (Ax ∋w) = Ax (σ ∋w)
rename σ (⊢ƛ ⊢N) = ⊢ƛ (rename (ext σ) ⊢N)
rename σ (⊢L · ⊢M) = (rename σ ⊢L) · (rename σ ⊢M)
rename σ ⊢zero = ⊢zero
rename σ (⊢suc ⊢M) = ⊢suc (rename σ ⊢M)
rename σ (⊢case ⊢L ⊢M ⊢N) = ⊢case (rename σ ⊢L) (rename σ ⊢M) (rename (ext σ) ⊢N)
rename σ (⊢μ ⊢M) = ⊢μ (rename (ext σ) ⊢M)
\end{code}
We have three important corollaries. First,
any closed term can be weakened to any context.
\begin{code}
rename-∅ : ∀ {Γ M A}
→ ∅ ⊢ M ⦂ A
----------
→ Γ ⊢ M ⦂ A
rename-∅ {Γ} ⊢M = rename σ ⊢M
where
σ : ∀ {z C}
→ ∅ ∋ z ⦂ C
---------
→ Γ ∋ z ⦂ C
σ ()
\end{code}
Second, if the last two variables in a context are
equal, the term can be renamed to drop the redundant one.
\begin{code}
rename-≡ : ∀ {Γ x M A B C}
→ Γ , x ⦂ A , x ⦂ B ⊢ M ⦂ C
--------------------------
→ Γ , x ⦂ B ⊢ M ⦂ C
rename-≡ {Γ} {x} {M} {A} {B} {C} ⊢M = rename σ ⊢M
where
σ : ∀ {z C}
→ Γ , x ⦂ A , x ⦂ B ∋ z ⦂ C
-------------------------
→ Γ , x ⦂ B ∋ z ⦂ C
σ Z = Z
σ (S z≢x Z) = ⊥-elim (z≢x refl)
σ (S z≢x (S z≢y ∋z)) = S z≢x ∋z
\end{code}
Third, if the last two variables in a context differ,
the term can be renamed to flip their order.
\begin{code}
rename-≢ : ∀ {Γ x y M A B C}
→ x ≢ y
→ Γ , y ⦂ A , x ⦂ B ⊢ M ⦂ C
--------------------------
→ Γ , x ⦂ B , y ⦂ A ⊢ M ⦂ C
rename-≢ {Γ} {x} {y} {M} {A} {B} {C} x≢y ⊢M = rename σ ⊢M
where
σ : ∀ {z C}
→ Γ , y ⦂ A , x ⦂ B ∋ z ⦂ C
--------------------------
→ Γ , x ⦂ B , y ⦂ A ∋ z ⦂ C
σ Z = S (λ{refl → x≢y refl}) Z
σ (S z≢x Z) = Z
σ (S z≢x (S z≢y ∋z)) = S z≢y (S z≢x ∋z)
\end{code}
## Substitution
Now we come to the conceptual heart of the proof that reduction
preserves types---namely, the observation that _substitution_
preserves types.
Formally, the _Substitution Lemma_ says this: Suppose we
have a term `N` with a free variable `x`, where `N` has
type `B` under the assumption that `x` has some type `A`.
Also, suppose that we have some other term `V`,
where `V` has type `A`. Then, since `V` satisfies
the assumption we made about `x` when typing `N`, we should be
able to substitute `V` for each of the occurrences of `x` in `N`
and obtain a new term that still has type `B`.
_Lemma_: If `Γ , x ⦂ A ⊢ N ⦂ B` and `∅ ⊢ V ⦂ A`, then
`Γ ⊢ (N [ x := V ]) ⦂ B`.
One technical subtlety in the statement of the lemma is that we assume
`V` is closed; it has type `A` in the _empty_ context. This
assumption simplifies the `λ` case of the proof because the context
invariance lemma then tells us that `V` has type `A` in any context at
all---we don't have to worry about free variables in `V` clashing with
the variable being introduced into the context by `λ`. It is possible
to prove the theorem under the more general assumption `Γ ⊢ V ⦂ A`,
but the proof is more difficult.
<!--
Intuitively, the substitution lemma says that substitution and typing can
be done in either order: we can either assign types to the terms
`N` and `V` separately (under suitable contexts) and then combine
them using substitution, or we can substitute first and then
assign a type to `N [ x := V ]`---the result is the same either
way.
-->
\begin{code}
subst : ∀ {Γ x N V A B}
→ Γ , x ⦂ A ⊢ N ⦂ B
→ ∅ ⊢ V ⦂ A
--------------------
→ Γ ⊢ N [ x := V ] ⦂ B
subst {x = y} (Ax {x = x} Z) ⊢V with x ≟ y
... | yes refl = rename-∅ ⊢V
... | no x≢y = ⊥-elim (x≢y refl)
subst {x = y} (Ax {x = x} (S x≢y ∋x)) ⊢V with x ≟ y
... | yes refl = ⊥-elim (x≢y refl)
... | no _ = Ax ∋x
subst {x = y} (⊢ƛ {x = x} ⊢N) ⊢V with x ≟ y
... | yes refl = ⊢ƛ (rename-≡ ⊢N)
... | no x≢y = ⊢ƛ (subst (rename-≢ x≢y ⊢N) ⊢V)
subst (⊢L · ⊢M) ⊢V = (subst ⊢L ⊢V) · (subst ⊢M ⊢V)
subst ⊢zero ⊢V = ⊢zero
subst (⊢suc ⊢M) ⊢V = ⊢suc (subst ⊢M ⊢V)
subst {x = y} (⊢case {x = x} ⊢L ⊢M ⊢N) ⊢V with x ≟ y
... | yes refl = ⊢case (subst ⊢L ⊢V) (subst ⊢M ⊢V) (rename-≡ ⊢N)
... | no x≢y = ⊢case (subst ⊢L ⊢V) (subst ⊢M ⊢V) (subst (rename-≢ x≢y ⊢N) ⊢V)
subst {x = y} (⊢μ {x = x} ⊢M) ⊢V with x ≟ y
... | yes refl = ⊢μ (rename-≡ ⊢M)
... | no x≢y = ⊢μ (subst (rename-≢ x≢y ⊢M) ⊢V)
\end{code}
### Main Theorem
We now have the tools we need to prove preservation: if a closed
term `M` has type `A` and takes a step to `N`, then `N`
is also a closed term with type `A`. In other words, small-step
reduction preserves types.
\begin{code}
preserve : ∀ {M N A}
→ ∅ ⊢ M ⦂ A
→ M ⟶ N
----------
→ ∅ ⊢ N ⦂ A
preserve (Ax ())
preserve (⊢ƛ ⊢N) ()
preserve (⊢L · ⊢M) (ξ-·₁ L⟶L) = (preserve ⊢L L⟶L) · ⊢M
preserve (⊢L · ⊢M) (ξ-·₂ VL M⟶M) = ⊢L · (preserve ⊢M M⟶M)
preserve ((⊢ƛ ⊢N) · ⊢V) (β-ƛ· VV) = subst ⊢N ⊢V
preserve ⊢zero ()
preserve (⊢suc ⊢M) (ξ-suc M⟶M) = ⊢suc (preserve ⊢M M⟶M)
preserve (⊢case ⊢L ⊢M ⊢N) (ξ-case L⟶L) = ⊢case (preserve ⊢L L⟶L) ⊢M ⊢N
preserve (⊢case ⊢zero ⊢M ⊢N) β-case-zero = ⊢M
preserve (⊢case (⊢suc ⊢V) ⊢M ⊢N) (β-case-suc VV) = subst ⊢N ⊢V
preserve (⊢μ ⊢M) (β-μ) = subst ⊢M (⊢μ ⊢M)
\end{code}
## Normalisation
\begin{code}
Gas : Set
Gas =
data Normalise (M : Term) : Set where
out-of-gas : ∀ {N A}
→ M ⟶* N
→ ∅ ⊢ N ⦂ A
-------------
→ Normalise M
normal : ∀ {V}
→ Gas
→ M ⟶* V
→ Value V
--------------
→ Normalise M
normalise : ∀ {M A}
→ Gas
→ ∅ ⊢ M ⦂ A
-----------
→ Normalise M
normalise {L} zero ⊢L = out-of-gas (L ∎) ⊢L
normalise {L} (suc m) ⊢L with progress ⊢L
... | done VL = normal (suc m) (L ∎) VL
... | step L⟶M with normalise m (preserve ⊢L L⟶M)
... | out-of-gas M⟶*N ⊢N = out-of-gas (L ⟶⟨ L⟶M ⟩ M⟶*N) ⊢N
... | normal n M⟶*V VV = normal n (L ⟶⟨ L⟶M ⟩ M⟶*V) VV
\end{code}
### Examples
\begin{code}
_ : normalise 100 ⊢four ≡
normal 88
((μ "+" ⇒
(ƛ "m" ⇒
(ƛ "n" ⇒
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (⌊ "+" ⌋ · ⌊ "m" ⌋ · ⌊ "n" ⌋)
])))
· `suc (`suc `zero)
· `suc (`suc `zero)
⟶⟨ ξ-·₁ (ξ-·₁ β-μ) ⟩
(ƛ "m" ⇒
(ƛ "n" ⇒
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒
`suc
((μ "+" ⇒
(ƛ "m" ⇒
(ƛ "n" ⇒
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (⌊ "+" ⌋ · ⌊ "m" ⌋ · ⌊ "n" ⌋)
])))
· ⌊ "m" ⌋
· ⌊ "n" ⌋)
]))
· `suc (`suc `zero)
· `suc (`suc `zero)
⟶⟨ ξ-·₁ (β-ƛ· (V-suc (V-suc V-zero))) ⟩
(ƛ "n" ⇒
`case `suc (`suc `zero) [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒
`suc
((μ "+" ⇒
(ƛ "m" ⇒
(ƛ "n" ⇒
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (⌊ "+" ⌋ · ⌊ "m" ⌋ · ⌊ "n" ⌋)
])))
· ⌊ "m" ⌋
· ⌊ "n" ⌋)
])
· `suc (`suc `zero)
⟶⟨ β-ƛ· (V-suc (V-suc V-zero)) ⟩
`case `suc (`suc `zero) [zero⇒ `suc (`suc `zero) |suc "m" ⇒
`suc
((μ "+" ⇒
(ƛ "m" ⇒
(ƛ "n" ⇒
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (⌊ "+" ⌋ · ⌊ "m" ⌋ · ⌊ "n" ⌋)
])))
· ⌊ "m" ⌋
· `suc (`suc `zero))
]
⟶⟨ β-case-suc (V-suc V-zero) ⟩
`suc
((μ "+" ⇒
(ƛ "m" ⇒
(ƛ "n" ⇒
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (⌊ "+" ⌋ · ⌊ "m" ⌋ · ⌊ "n" ⌋)
])))
· `suc `zero
· `suc (`suc `zero))
⟶⟨ ξ-suc (ξ-·₁ (ξ-·₁ β-μ)) ⟩
`suc
((ƛ "m" ⇒
(ƛ "n" ⇒
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒
`suc
((μ "+" ⇒
(ƛ "m" ⇒
(ƛ "n" ⇒
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (⌊ "+" ⌋ · ⌊ "m" ⌋ · ⌊ "n" ⌋)
])))
· ⌊ "m" ⌋
· ⌊ "n" ⌋)
]))
· `suc `zero
· `suc (`suc `zero))
⟶⟨ ξ-suc (ξ-·₁ (β-ƛ· (V-suc V-zero))) ⟩
`suc
((ƛ "n" ⇒
`case `suc `zero [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒
`suc
((μ "+" ⇒
(ƛ "m" ⇒
(ƛ "n" ⇒
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (⌊ "+" ⌋ · ⌊ "m" ⌋ · ⌊ "n" ⌋)
])))
· ⌊ "m" ⌋
· ⌊ "n" ⌋)
])
· `suc (`suc `zero))
⟶⟨ ξ-suc (β-ƛ· (V-suc (V-suc V-zero))) ⟩
`suc
`case `suc `zero [zero⇒ `suc (`suc `zero) |suc "m" ⇒
`suc
((μ "+" ⇒
(ƛ "m" ⇒
(ƛ "n" ⇒
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (⌊ "+" ⌋ · ⌊ "m" ⌋ · ⌊ "n" ⌋)
])))
· ⌊ "m" ⌋
· `suc (`suc `zero))
]
⟶⟨ ξ-suc (β-case-suc V-zero) ⟩
`suc
(`suc
((μ "+" ⇒
(ƛ "m" ⇒
(ƛ "n" ⇒
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (⌊ "+" ⌋ · ⌊ "m" ⌋ · ⌊ "n" ⌋)
])))
· `zero
· `suc (`suc `zero)))
⟶⟨ ξ-suc (ξ-suc (ξ-·₁ (ξ-·₁ β-μ))) ⟩
`suc
(`suc
((ƛ "m" ⇒
(ƛ "n" ⇒
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒
`suc
((μ "+" ⇒
(ƛ "m" ⇒
(ƛ "n" ⇒
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (⌊ "+" ⌋ · ⌊ "m" ⌋ · ⌊ "n" ⌋)
])))
· ⌊ "m" ⌋
· ⌊ "n" ⌋)
]))
· `zero
· `suc (`suc `zero)))
⟶⟨ ξ-suc (ξ-suc (ξ-·₁ (β-ƛ· V-zero))) ⟩
`suc
(`suc
((ƛ "n" ⇒
`case `zero [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒
`suc
((μ "+" ⇒
(ƛ "m" ⇒
(ƛ "n" ⇒
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (⌊ "+" ⌋ · ⌊ "m" ⌋ · ⌊ "n" ⌋)
])))
· ⌊ "m" ⌋
· ⌊ "n" ⌋)
])
· `suc (`suc `zero)))
⟶⟨ ξ-suc (ξ-suc (β-ƛ· (V-suc (V-suc V-zero)))) ⟩
`suc
(`suc
`case `zero [zero⇒ `suc (`suc `zero) |suc "m" ⇒
`suc
((μ "+" ⇒
(ƛ "m" ⇒
(ƛ "n" ⇒
`case ⌊ "m" ⌋ [zero⇒ ⌊ "n" ⌋ |suc "m" ⇒ `suc (⌊ "+" ⌋ · ⌊ "m" ⌋ · ⌊ "n" ⌋)
])))
· ⌊ "m" ⌋
· `suc (`suc `zero))
])
⟶⟨ ξ-suc (ξ-suc β-case-zero) ⟩ `suc (`suc (`suc (`suc `zero))) ∎)
(V-suc (V-suc (V-suc (V-suc V-zero))))
_ = refl
\end{code}
\begin{code}
_ : normalise 100 ⊢fourᶜ ≡
normal 88
((ƛ "m" ⇒
(ƛ "n" ⇒
(ƛ "s" ⇒ (ƛ "z" ⇒ ⌊ "m" ⌋ · ⌊ "s" ⌋ · (⌊ "n" ⌋ · ⌊ "s" ⌋ · ⌊ "z" ⌋)))))
· (ƛ "s" ⇒ (ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋)))
· (ƛ "s" ⇒ (ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋)))
· (ƛ "n" ⇒ `suc ⌊ "n" ⌋)
· `zero
⟶⟨ ξ-·₁ (ξ-·₁ (ξ-·₁ (β-ƛ· V-ƛ))) ⟩
(ƛ "n" ⇒
(ƛ "s" ⇒
(ƛ "z" ⇒
(ƛ "s" ⇒ (ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋))) · ⌊ "s" ⌋ ·
(⌊ "n" ⌋ · ⌊ "s" ⌋ · ⌊ "z" ⌋))))
· (ƛ "s" ⇒ (ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋)))
· (ƛ "n" ⇒ `suc ⌊ "n" ⌋)
· `zero
⟶⟨ ξ-·₁ (ξ-·₁ (β-ƛ· V-ƛ)) ⟩
(ƛ "s" ⇒
(ƛ "z" ⇒
(ƛ "s" ⇒ (ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋))) · ⌊ "s" ⌋ ·
((ƛ "s" ⇒ (ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋))) · ⌊ "s" ⌋ · ⌊ "z" ⌋)))
· (ƛ "n" ⇒ `suc ⌊ "n" ⌋)
· `zero
⟶⟨ ξ-·₁ (β-ƛ· V-ƛ) ⟩
(ƛ "z" ⇒
(ƛ "s" ⇒ (ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋))) · (ƛ "n" ⇒ `suc ⌊ "n" ⌋)
·
((ƛ "s" ⇒ (ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋))) · (ƛ "n" ⇒ `suc ⌊ "n" ⌋)
· ⌊ "z" ⌋))
· `zero
⟶⟨ β-ƛ· V-zero ⟩
(ƛ "s" ⇒ (ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋))) · (ƛ "n" ⇒ `suc ⌊ "n" ⌋)
·
((ƛ "s" ⇒ (ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋))) · (ƛ "n" ⇒ `suc ⌊ "n" ⌋)
· `zero)
⟶⟨ ξ-·₁ (β-ƛ· V-ƛ) ⟩
(ƛ "z" ⇒ (ƛ "n" ⇒ `suc ⌊ "n" ⌋) · ((ƛ "n" ⇒ `suc ⌊ "n" ⌋) · ⌊ "z" ⌋)) ·
((ƛ "s" ⇒ (ƛ "z" ⇒ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋))) · (ƛ "n" ⇒ `suc ⌊ "n" ⌋)
· `zero)
⟶⟨ ξ-·₂ V-ƛ (ξ-·₁ (β-ƛ· V-ƛ)) ⟩
(ƛ "z" ⇒ (ƛ "n" ⇒ `suc ⌊ "n" ⌋) · ((ƛ "n" ⇒ `suc ⌊ "n" ⌋) · ⌊ "z" ⌋)) ·
((ƛ "z" ⇒ (ƛ "n" ⇒ `suc ⌊ "n" ⌋) · ((ƛ "n" ⇒ `suc ⌊ "n" ⌋) · ⌊ "z" ⌋)) ·
`zero)
⟶⟨ ξ-·₂ V-ƛ (β-ƛ· V-zero) ⟩
(ƛ "z" ⇒ (ƛ "n" ⇒ `suc ⌊ "n" ⌋) · ((ƛ "n" ⇒ `suc ⌊ "n" ⌋) · ⌊ "z" ⌋)) ·
((ƛ "n" ⇒ `suc ⌊ "n" ⌋) · ((ƛ "n" ⇒ `suc ⌊ "n" ⌋) · `zero))
⟶⟨ ξ-·₂ V-ƛ (ξ-·₂ V-ƛ (β-ƛ· V-zero)) ⟩
(ƛ "z" ⇒ (ƛ "n" ⇒ `suc ⌊ "n" ⌋) · ((ƛ "n" ⇒ `suc ⌊ "n" ⌋) · ⌊ "z" ⌋)) ·
((ƛ "n" ⇒ `suc ⌊ "n" ⌋) · `suc `zero)
⟶⟨ ξ-·₂ V-ƛ (β-ƛ· (V-suc V-zero)) ⟩
(ƛ "z" ⇒ (ƛ "n" ⇒ `suc ⌊ "n" ⌋) · ((ƛ "n" ⇒ `suc ⌊ "n" ⌋) · ⌊ "z" ⌋)) ·
`suc (`suc `zero)
⟶⟨ β-ƛ· (V-suc (V-suc V-zero)) ⟩
(ƛ "n" ⇒ `suc ⌊ "n" ⌋) · ((ƛ "n" ⇒ `suc ⌊ "n" ⌋) · `suc (`suc `zero))
⟶⟨ ξ-·₂ V-ƛ (β-ƛ· (V-suc (V-suc V-zero))) ⟩
(ƛ "n" ⇒ `suc ⌊ "n" ⌋) · `suc (`suc (`suc `zero)) ⟶⟨
β-ƛ· (V-suc (V-suc (V-suc V-zero))) ⟩
`suc (`suc (`suc (`suc `zero))) ∎)
(V-suc (V-suc (V-suc (V-suc V-zero))))
_ = refl
\end{code}
#### Exercise: 2 stars, recommended (subject_expansion_stlc)
<!--
An exercise in the [Types]({{ "Types" | relative_url }}) chapter asked about the
subject expansion property for the simple language of arithmetic and boolean
expressions. Does this property hold for STLC? That is, is it always the case
that, if `M ==> N` and `∅ ⊢ N ⦂ A`, then `∅ ⊢ M ⦂ A`? It is easy to find a
counter-example with conditionals, find one not involving conditionals.
-->
We say that `M` _reduces_ to `N` if `M ⟶ N`,
and that `M` _expands_ to `N` if `N ⟶ M`.
The preservation property is sometimes called _subject reduction_.
Its opposite is _subject expansion_, which holds if
`M ==> N` and `∅ ⊢ N ⦂ A`, then `∅ ⊢ M ⦂ A`.
Find two counter-examples to subject expansion, one
with case expressions and one not involving case expressions.
## Type Soundness
#### Exercise: 2 stars, optional (type_soundness)
Put progress and preservation together and show that a well-typed
term can _never_ reach a stuck state.
\begin{code}
Normal : Term → Set
Normal M = ∀ {N} → ¬ (M ⟶ N)
Stuck : Term → Set
Stuck M = Normal M × ¬ Value M
postulate
Soundness : ∀ {M N A}
→ ∅ ⊢ M ⦂ A
→ M ⟶* N
-----------
→ ¬ (Stuck N)
\end{code}
<div class="hidden">
\begin{code}
Soundness : ∀ {M N A}
→ ∅ ⊢ M ⦂ A
→ M ⟶* N
-----------
→ ¬ (Stuck N)
Soundness ⊢M (M ∎) ⟨ ¬M⟶N , ¬VM ⟩ with progress ⊢M
... | step M⟶N = ¬M⟶N M⟶N
... | done VM = ¬VM VM
Soundness ⊢L (L ⟶⟨ L⟶M ⟩ M⟶*N) = Soundness (preserve ⊢L L⟶M) M⟶*N
\end{code}
</div>
## Additional Exercises
#### Exercise: 1 star (progress_preservation_statement)
Without peeking at their statements above, write down the progress
and preservation theorems for the simply typed lambda-calculus.
#### Exercise: 2 stars (stlc_variation1)
Suppose we add a new term `zap` with the following reduction rule
--------- (ST_Zap)
M ⟶ zap
and the following typing rule:
----------- (T_Zap)
Γ ⊢ zap : A
Which of the following properties of the STLC remain true in
the presence of these rules? For each property, write either
"remains true" or "becomes false." If a property becomes
false, give a counterexample.
- Determinism of `step`
- Progress
- Preservation
#### Exercise: 2 stars (stlc_variation2)
Suppose instead that we add a new term `foo` with the following
reduction rules:
------------------- (Foo₁)
(λ x ⇒ ⌊ x ⌋) ⟶ foo
------------ (Foo₂)
foo ⟶ true
Which of the following properties of the STLC remain true in
the presence of this rule? For each one, write either
"remains true" or else "becomes false." If a property becomes
false, give a counterexample.
- Determinism of `step`
- Progress
- Preservation
#### Exercise: 2 stars (stlc_variation3)
Suppose instead that we remove the rule `ξ·₁` from the `⟶`
relation. Which of the following properties of the STLC remain
true in the absence of this rule? For each one, write either
"remains true" or else "becomes false." If a property becomes
false, give a counterexample.
- Determinism of `step`
- Progress
- Preservation
#### Exercise: 2 stars, optional (stlc_variation4)
Suppose instead that we add the following new rule to the
reduction relation:
---------------------------------------- (FunnyCaseZero)
case zero [zero⇒ M |suc x ⇒ N ] ⟶ true
Which of the following properties of the STLC remain true in
the presence of this rule? For each one, write either
"remains true" or else "becomes false." If a property becomes
false, give a counterexample.
- Determinism of `step`
- Progress
- Preservation
#### Exercise: 2 stars, optional (stlc_variation5)
Suppose instead that we add the following new rule to the typing
relation:
Γ ⊢ L ⦂ ` ⇒ ` ⇒ `
Γ ⊢ M ⦂ `
------------------------------ (FunnyApp)
Γ ⊢ L · M ⦂ `
Which of the following properties of the STLC remain true in
the presence of this rule? For each one, write either
"remains true" or else "becomes false." If a property becomes
false, give a counterexample.
- Determinism of `step`
- Progress
- Preservation
#### Exercise: 2 stars, optional (stlc_variation6)
Suppose instead that we add the following new rule to the typing
relation:
Γ ⊢ L ⦂ `
Γ ⊢ M ⦂ `
--------------------- (FunnyApp')
Γ ⊢ L · M ⦂ `
Which of the following properties of the STLC remain true in
the presence of this rule? For each one, write either
"remains true" or else "becomes false." If a property becomes
false, give a counterexample.
- Determinism of `step`
- Progress
- Preservation
#### Exercise : 2 stars, optional (stlc_variation7)
Suppose we add the following new rule to the typing relation
of the STLC:
-------------------- (T_FunnyAbs)
∅ ⊢ ƛ x ⇒ N ⦂ `
Which of the following properties of the STLC remain true in
the presence of this rule? For each one, write either
"remains true" or else "becomes false." If a property becomes
false, give a counterexample.
- Determinism of `step`
- Progress
- Preservation
## Normalisation with streams
\begin{code}
record Lift (M : Term) : Set
data Steps (M : Term) : Set
record Lift (M : Term) where
coinductive
field
force : Steps M
open Lift
data Steps (M : Term) where
done :
Value M
-------
→ Steps M
step : ∀ {N : Term}
→ M ⟶ N
→ Lift N
--------------
→ Steps M
norm : ∀ {M A}
→ ∅ ⊢ M ⦂ A
----------
→ Lift M
force (norm ⊢M) with progress ⊢M
... | done VM = done VM
... | step M↦N = step M↦N (norm (preserve ⊢M M↦N))
data Cut (M : Term) : Set where
out-of-gas : ∀ {N : Term}
→ M ⟶* N
--------
→ Cut M
normal : ∀ {V : Term}
→ Gas
→ M ⟶* V
→ Value V
-------
→ Cut M
cut : ∀ {L} → Gas → Lift L → Cut L
cut {L} zero _ = out-of-gas (L ∎)
cut {L} (suc n) LiftL with force LiftL
... | done VL = normal n (L ∎) VL
... | step L↦M LiftM with cut n LiftM
... | out-of-gas M↠N = out-of-gas (L ⟶⟨ L↦M ⟩ M↠N)
... | normal g M↠V VV = normal g (L ⟶⟨ L↦M ⟩ M↠V) VV
take : ∀ {L} → Gas → Lift L → ∃[ N ](L ⟶* N)
take {L} zero _ = ⟨ L , L ∎ ⟩
take {L} (suc n) LiftL with force LiftL
... | done _ = ⟨ L , L ∎ ⟩
... | step L↦M LiftM with take n LiftM
... | ⟨ N , M↠N ⟩ = ⟨ N , L ⟶⟨ L↦M ⟩ M↠N ⟩
\end{code}

View file

@ -1,179 +0,0 @@
---
title : "Streams: Streams and coinduction"
layout : page
permalink : /Streams
---
This chapter introduces streams and coinduction.
## Imports
\begin{code}
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong)
open Eq.≡-Reasoning
open import Coinduction using (∞; ♯_; ♭)
open import Data.Product using (_×_; proj₁; proj₂) renaming (_,_ to ⟨_,_⟩)
\end{code}
We assume [extensionality][extensionality].
\begin{code}
postulate
extensionality : ∀ {A B : Set} {f g : A → B} → (∀ (x : A) → f x ≡ g x) → f ≡ g
\end{code}
[extensionality]: Equality/index.html#extensionality
## Streams
Streams are defined in Agda as follows.
\begin{code}
record Stream (A : Set) : Set where
coinductive
field
hd : A
tl : Stream A
open Stream
\end{code}
A constructor for streams may be defined via *co-pattern matching*.
\begin{code}
infixr 5 _∷_
_∷_ : ∀ {A : Set} → A → Stream A → Stream A
hd (x ∷ xs) = x
tl (x ∷ xs) = xs
\end{code}
\begin{code}
even : ∀ {A} → Stream A → Stream A
hd (even x) = hd x
tl (even x) = even (tl (tl x))
\end{code}
## Lifting
\begin{code}
record Lift (A : Set) : Set where
coinductive
field
force : A
open Lift
\end{code}
\begin{code}
delay : ∀ {A : Set} → A → Lift A
force (delay x) = x
\end{code}
## Alternative definition of stream
\begin{code}
data Stream (A : Set) : Set where
_∷_ : A → ∞ (Stream A) → Stream A
hd : ∀ {A} → Stream A → A
hd (x ∷′ xs) = x
tl : ∀ {A} → Stream A → Stream A
tl (x ∷′ xs) = ♭ xs
\end{code}
## Maps between the two definitions
\begin{code}
to : ∀ {A} → Stream A → Stream A
to xs = hd xs ∷′ ♯ (to (tl xs))
from : ∀ {A} → Stream A → Stream A
hd (from (x ∷′ xs)) = x
tl (from (x ∷′ xs)) = from (♭ xs)
\end{code}
Termination check does not succeed if I replace `∞`, `♯`, `♭` by `Lift`,
`delay`, `force`.
Trying to show full-blown isomorphism appears difficult.
## How to be lazy without even being odd
This is the approach hinted at by Abel in his [lecture].
[lecture]: http://cs.ioc.ee/~tarmo/tsem12/abel-slides.pdf
\begin{code}
record EStream (A : Set) : Set
data OStream (A : Set) : Set
record EStream (A : Set) where
coinductive
field
force : OStream A
open EStream
data OStream (A : Set) where
cons : A → EStream A → OStream A
\end{code}
Type `OStream` can also include a `nil` clause, if needed.
## Conversions between `Stream` and `EStream`.
\begin{code}
toE : ∀ {A} → Stream A → EStream A
force (toE xs) = cons (hd xs) (toE (tl xs))
fromE : ∀ {A} → EStream A → Stream A
hd (fromE xs) with force xs
... | cons x xs″ = x
tl (fromE xs) with force xs
... | cons x xs″ = fromE xs″
record __ {A : Set} (xs : Stream A) (ys : Stream A) : Set where
coinductive
field
hd- : hd xs ≡ hd ys
tl- : tl xs tl ys
open __
record _≈_ {A : Set} (xs ys : EStream A) : Set
_≋_ : ∀ {A : Set} (xs″ ys″ : OStream A) → Set
record _≈_ {A : Set} (xs ys : EStream A) where
coinductive
field
force-≈ : force xs ≋ force ys
open _≈_
cons x xs ≋ cons y ys = (x ≡ y) × (xs ≈ ys)
fromE∘toE : ∀ {A} (xs : Stream A) → fromE (toE xs) xs
hd- (fromE∘toE xs) = refl
tl- (fromE∘toE xs) = fromE∘toE (tl xs)
toE∘fromE : ∀ {A} (xs : EStream A) → toE (fromE xs) ≈ xs
force-≈ (toE∘fromE xs) with force xs
... | cons x xs = ⟨ refl , toE∘fromE xs ⟩
\end{code}
## Standard Library
Definitions similar to those in this chapter can be found in the standard library.
\begin{code}
\end{code}
## Unicode
This chapter uses the following unicode.
∷ U+2237 PROPORTION (\::)
⊗ U+2297 CIRCLED TIMES (\otimes)
∈ U+2208 ELEMENT OF (\in)
∉ U+2209 NOT AN ELEMENT OF (\inn)

View file

@ -1,32 +0,0 @@
## Subset
\begin{code}
open import Data.List using (List; []; _∷_)
open import Function using (id; _∘_)
open import Relation.Binary.Core using (Reflexive; Transitive)
module Subset (A : Set) where
infix 4 _⊆_
infix 4 _∈_
data _∈_ : A → List A → Set where
here : ∀ {x : A} {xs : List A}
----------
→ x ∈ x ∷ xs
there : ∀ {x y : A} {xs : List A}
→ x ∈ xs
----------
→ x ∈ y ∷ xs
_⊆_ : List A → List A → Set
xs ⊆ ys = ∀ {w : A} → w ∈ xs → w ∈ ys
⊆-refl : Reflexive _⊆_
⊆-refl = id
⊆-trans : Transitive _⊆_
⊆-trans xs⊆ys ys⊆zs = ys⊆zs ∘ xs⊆ys
\end{code}

View file

@ -1,260 +0,0 @@
---
title : "SystemF: Inherently typed System F"
layout : page
permalink : /SystemF/
---
\begin{code}
module plfa.SystemF where
\end{code}
## Fixity declarations
To begin, we get all our infix declarations out of the way.
We list separately operators for judgments, types, and terms.
\begin{code}
infix 4 _∋⋆_
infix 4 _∋_
infix 4 _⊢⋆_
infix 4 _⊢_
infixl 5 _,⋆_
infixl 5 _,_
infix 6 Π_
infixr 7 _⇒_
infix 5 ƛ_
infixl 7 _·_
infix 9 S_
\end{code}
## Kinds
The only kind is `★`, the kind of types.
\begin{code}
data Kind : Set where
★ : Kind
\end{code}
Let `J`, `K` range over kinds.
## Type contexts
A type context is either empty or extends a type
context by a type variable of a given kind.
\begin{code}
data Ctx⋆ : Set where
∅ : Ctx⋆
_,⋆_ : Ctx⋆ → Kind → Ctx⋆
\end{code}
Let `Φ`, `Ψ` range over type contexts.
## Type variables
A type variable is indexed by its context and kind.
\begin{code}
data _∋⋆_ : Ctx⋆ → Kind → Set where
Z : ∀ {Φ J}
-------------
→ Φ ,⋆ J ∋⋆ J
S_ : ∀ {Φ J K}
→ Φ ∋⋆ J
-------------
→ Φ ,⋆ K ∋⋆ J
\end{code}
Let `α`, `β` range over type variables.
## Types
A type is indexed by its context and kind. A type is either a type
variable, a pi type, or a function type.
\begin{code}
data _⊢⋆_ : Ctx⋆ → Kind → Set where
`_ : ∀ {Φ J}
→ Φ ∋⋆ J
--------
→ Φ ⊢⋆ J
Π_ : ∀ {Φ K}
→ Φ ,⋆ K ⊢⋆ ★
-----------
→ Φ ⊢⋆ ★
_⇒_ : ∀ {Φ}
→ Φ ⊢⋆ ★
→ Φ ⊢⋆ ★
------
→ Φ ⊢⋆ ★
\end{code}
Let `A`, `B`, `C` range over types.
## Type renaming
A type renaming is a mapping of type variables to type variables.
Extending a type renaming — used when going under a binder.
\begin{code}
ext⋆ : ∀ {Φ Ψ} → (∀ {J} → Φ ∋⋆ J → Ψ ∋⋆ J)
------------------------------------------
→ (∀ {J K} → Φ ,⋆ K ∋⋆ J → Ψ ,⋆ K ∋⋆ J)
ext⋆ ρ Z = Z
ext⋆ ρ (S α) = S (ρ α)
\end{code}
Apply a type renaming to a type.
\begin{code}
rename⋆ : ∀ {Φ Ψ}
→ (∀ {J} → Φ ∋⋆ J → Ψ ∋⋆ J)
----------------------------
→ (∀ {J} → Φ ⊢⋆ J → Ψ ⊢⋆ J)
rename⋆ ρ (` α) = ` (ρ α)
rename⋆ ρ (Π B) = Π (rename⋆ (ext⋆ ρ) B)
rename⋆ ρ (A ⇒ B) = rename⋆ ρ A ⇒ rename⋆ ρ B
\end{code}
Weakening is a special case of renaming.
\begin{code}
weaken⋆ : ∀ {Φ J K}
→ Φ ⊢⋆ J
-------------
→ Φ ,⋆ K ⊢⋆ J
weaken⋆ = rename⋆ S_
\end{code}
## Type substitution
A type substitution is a mapping of type variables to types.
Extending a type substitution — used when going under a binder.
\begin{code}
exts⋆ : ∀ {Φ Ψ} → (∀ {J} → Φ ∋⋆ J → Ψ ⊢⋆ J)
-------------------------------------------
→ (∀ {J K} → Φ ,⋆ K ∋⋆ J → Ψ ,⋆ K ⊢⋆ J)
exts⋆ σ Z = ` Z
exts⋆ σ (S α) = weaken⋆ (σ α)
\end{code}
Apply a type substitution to a type.
\begin{code}
subst⋆ : ∀ {Φ Ψ}
→ (∀ {J} → Φ ∋⋆ J → Ψ ⊢⋆ J)
-----------------------------
→ (∀ {J} → Φ ⊢⋆ J → Ψ ⊢⋆ J)
subst⋆ σ (` α) = σ α
subst⋆ σ (Π B) = Π (subst⋆ (exts⋆ σ) B)
subst⋆ σ (A ⇒ B) = subst⋆ σ A ⇒ subst⋆ σ B
\end{code}
A special case is substitution a type for the
outermost free variable.
\begin{code}
_[_]⋆ : ∀ {Φ J K}
→ Φ ,⋆ K ⊢⋆ J
→ Φ ⊢⋆ K
-------------
→ Φ ⊢⋆ J
_[_]⋆ {Φ} {J} {K} B A = subst⋆ {Φ ,⋆ K} {Φ} σ {J} B
where
σ : ∀ {J} → Φ ,⋆ K ∋⋆ J → Φ ⊢⋆ J
σ Z = A
σ (S α) = ` α
\end{code}
## Contexts and erasure
We need to mutually define contexts and their
erasure to type contexts.
\begin{code}
data Ctx : Set
∥_∥ : Ctx → Ctx⋆
\end{code}
A context is either empty, or extends a context by
a type variable of a given kind, or extends a context
by a variable of a given type.
\begin{code}
data Ctx where
∅ : Ctx
_,⋆_ : Ctx → Kind → Ctx
_,_ : ∀ {J} (Γ : Ctx) → ∥ Γ ∥ ⊢⋆ J → Ctx
\end{code}
Let `Γ` range over contexts. In the last rule,
the type is indexed by the erasure of the previous
context to a type context and a kind.
The erasure of a context is a type context.
\begin{code}
∥ ∅ ∥ = ∅
∥ Γ ,⋆ J ∥ = ∥ Γ ∥ ,⋆ J
∥ Γ , A ∥ = ∥ Γ ∥
\end{code}
## Variables
A variable is indexed by its context and type.
\begin{code}
data _∋_ : ∀ {J} (Γ : Ctx) → ∥ Γ ∥ ⊢⋆ J → Set where
Z : ∀ {Γ J} {A : ∥ Γ ∥ ⊢⋆ J}
----------
→ Γ , A ∋ A
S_ : ∀ {Γ J K} {A : ∥ Γ ∥ ⊢⋆ J} {B : ∥ Γ ∥ ⊢⋆ K}
→ Γ ∋ A
----------
→ Γ , B ∋ A
T_ : ∀ {Γ J K} {A : ∥ Γ ∥ ⊢⋆ J}
→ Γ ∋ A
-------------------
→ Γ ,⋆ K ∋ weaken⋆ A
\end{code}
Let `x`, `y` range over variables.
## Terms
A term is indexed over by its context and type. A term is a variable,
an abstraction, an application, a type abstraction, or a type
application.
\begin{code}
data _⊢_ : ∀ {J} (Γ : Ctx) → ∥ Γ ∥ ⊢⋆ J → Set where
`_ : ∀ {Γ J} {A : ∥ Γ ∥ ⊢⋆ J}
→ Γ ∋ A
------
→ Γ ⊢ A
ƛ_ : ∀ {Γ A B}
→ Γ , A ⊢ B
-----------
→ Γ ⊢ A ⇒ B
_·_ : ∀ {Γ A B}
→ Γ ⊢ A ⇒ B
→ Γ ⊢ A
-----------
→ Γ ⊢ B
Λ_ : ∀ {Γ K} {B : ∥ Γ ∥ ,⋆ K ⊢⋆ ★}
→ Γ ,⋆ K ⊢ B
----------
→ Γ ⊢ Π B
_·⋆_ : ∀ {Γ B}
→ Γ ⊢ Π B
→ (A : ∥ Γ ∥ ⊢⋆ ★)
---------------
→ Γ ⊢ B [ A ]⋆
\end{code}
## Remainder
The development continues from here as in
Chapter [DeBruijn][plfa.DeBruijn],
defining renaming and substitution on terms and introducing reduction
rules for terms, proving progress, and applying progress to derive an
evaluator.

View file

@ -1,44 +0,0 @@
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong; cong₂; _≢_)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.List using (List; []; _∷_; takeWhile; dropWhile)
open import Data.List.All using (All; []; _∷_)
open import Data.Bool using (Bool; true; false; T)
open import Data.Unit using (; tt)
open import Relation.Nullary using (¬_)
open import Function using (_∘_)
module TakeDropBool (A : Set) (P : A Bool) where
Head : {A : Set} (A Bool) List A Set
Head P [] =
Head P (c s) = T (P c)
data Book (x : A) (b : Bool) : Set where
book : P x b Book x b
boo : (x : A) Book x (P x)
boo x = book refl
dropWhile-lemma : (s : List A) ¬ Head P (dropWhile P s)
dropWhile-lemma [] = λ()
dropWhile-lemma (c s) with P c | boo c
... | true | _ = dropWhile-lemma s
... | false | book eq rewrite eq = λ()
takeWhile-lemma : (s : List A) All (T P) (takeWhile P s)
takeWhile-lemma [] = []
takeWhile-lemma (c s) with P c | boo c
... | false | _ = []
... | true | book eq rewrite eq = {! tt!} takeWhile-lemma s
{- Hole 0
Goal: T (P c)
————————————————————————————————————————————————————————————
s : List A
eq : P c true
c : A
P : A Bool
A : Set
-}

View file

@ -1,54 +0,0 @@
module TakeDropDec where
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong; cong₂; _≢_)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.List using (List; []; _∷_)
open import Data.List.All using (All; []; _∷_)
open import Data.Bool using (Bool; true; false; T)
open import Data.Unit using (; tt)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Decidable using ()
open import Function using (_∘_)
module TakeDrop {A : Set} {P : A Set} (P? : (x : A) Dec (P x)) where
takeWhile : List A List A
takeWhile [] = []
takeWhile (x xs) with P? x
... | yes _ = x takeWhile xs
... | no _ = []
dropWhile : List A List A
dropWhile [] = []
dropWhile (x xs) with P? x
... | yes _ = dropWhile xs
... | no _ = x xs
Head : (A Set) List A Set
Head P [] =
Head P (x xs) = P x
takeWhile-lemma : (xs : List A) All P (takeWhile xs)
takeWhile-lemma [] = []
takeWhile-lemma (x xs) with P? x
... | yes px = px takeWhile-lemma xs
... | no _ = []
dropWhile-lemma : (xs : List A) ¬ Head P (dropWhile xs)
dropWhile-lemma [] = λ()
dropWhile-lemma (x xs) with P? x
... | yes _ = dropWhile-lemma xs
... | no ¬px = ¬px
open TakeDrop
open import Data.Nat using (; zero; suc; _≟_)
_ : takeWhile (0 ≟_) (0 0 1 []) (0 0 [])
_ = refl
_ : dropWhile (0 ≟_) (0 0 1 []) (1 [])
_ = refl

View file

@ -1,2 +0,0 @@
open import TakeDropDec

File diff suppressed because it is too large Load diff

View file

@ -1,788 +0,0 @@
---
title : "Typed: Typed Lambda term representation"
layout : page
permalink : /Typed
---
## Imports
\begin{code}
module Typed where
\end{code}
\begin{code}
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong; cong₂; _≢_)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.List using (List; []; _∷_; _++_; map; foldr; filter)
open import Data.Nat using (; zero; suc; _+_; _∸_; _≤_; _⊔_)
open import Data.Nat.Properties using (≤-refl; ≤-trans; m≤m⊔n; n≤m⊔n; 1+n≰n)
open import Data.String using (String)
open import Data.Product using (_×_; proj₁; proj₂) renaming (_,_ to ⟨_,_⟩)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Function using (_∘_)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Negation using (¬?)
open import Collections
import Data.Nat as Nat
import Data.String as String
pattern [_] x = x ∷ []
pattern [_,_] x y = x ∷ y ∷ []
pattern [_,_,_] x y z = x ∷ y ∷ z ∷ []
\end{code}
## Identifiers
\begin{code}
data Id : Set where
id : String → → Id
_≟_ : ∀ (x y : Id) → Dec (x ≡ y)
id s m ≟ id t n with s String.≟ t | m Nat.≟ n
... | yes refl | yes refl = yes refl
... | yes refl | no m≢n = no (λ {refl → m≢n refl})
... | no s≢t | _ = no (λ {refl → s≢t refl})
{-
_≠_ : ∀ (x y : Id) → x ≢ y
x ≠ y with x ≟ y
... | no x≢y = x≢y
... | yes _ = impossible
where postulate impossible : _
-}
\end{code}
## Syntax
\begin{code}
infixr 5 _⇒_
infixl 5 _,_⦂_
infix 4 _∋_⦂_
infix 4 _⊢_⦂_
infix 5 `λ_⇒_
infixl 6 `if0_then_else_
infix 7 `suc_ `pred_ `Y_
infixl 8 _·_
infix 9 `_
data Type : Set where
` : Type
_⇒_ : Type → Type → Type
data Env : Set where
ε : Env
_,_⦂_ : Env → Id → Type → Env
data Term : Set where
`_ : Id → Term
`λ_⇒_ : Id → Term → Term
_·_ : Term → Term → Term
`zero : Term
`suc_ : Term → Term
`pred_ : Term → Term
`if0_then_else_ : Term → Term → Term → Term
`Y_ : Term → Term
data _∋_⦂_ : Env → Id → Type → Set where
Z : ∀ {Γ A x}
-----------------
→ Γ , x ⦂ A ∋ x ⦂ A
S : ∀ {Γ A B x w}
→ w ≢ x
→ Γ ∋ w ⦂ B
-----------------
→ Γ , x ⦂ A ∋ w ⦂ B
data _⊢_⦂_ : Env → Term → Type → Set where
Ax : ∀ {Γ A x}
→ Γ ∋ x ⦂ A
---------------------
→ Γ ⊢ ` x ⦂ A
⊢λ : ∀ {Γ x N A B}
→ Γ , x ⦂ A ⊢ N ⦂ B
------------------------
→ Γ ⊢ (`λ x ⇒ N) ⦂ A ⇒ B
_·_ : ∀ {Γ L M A B}
→ Γ ⊢ L ⦂ A ⇒ B
→ Γ ⊢ M ⦂ A
--------------
→ Γ ⊢ L · M ⦂ B
⊢zero : ∀ {Γ}
--------------
→ Γ ⊢ `zero ⦂ `
⊢suc : ∀ {Γ M}
→ Γ ⊢ M ⦂ `
---------------
→ Γ ⊢ `suc M ⦂ `
⊢pred : ∀ {Γ M}
→ Γ ⊢ M ⦂ `
----------------
→ Γ ⊢ `pred M ⦂ `
⊢if0 : ∀ {Γ L M N A}
→ Γ ⊢ L ⦂ `
→ Γ ⊢ M ⦂ A
→ Γ ⊢ N ⦂ A
----------------------------
→ Γ ⊢ `if0 L then M else N ⦂ A
⊢Y : ∀ {Γ M A}
→ Γ ⊢ M ⦂ A ⇒ A
---------------
→ Γ ⊢ `Y M ⦂ A
\end{code}
## Test examples
\begin{code}
m n s z : Id
p = id "p" 0 -- 0
m = id "m" 0 -- 1
n = id "n" 0 -- 2
s = id "s" 0 -- 3
z = id "z" 0 -- 4
s≢z : s ≢ z
s≢z ()
n≢z : n ≢ z
n≢z ()
n≢s : n ≢ s
n≢s ()
m≢z : m ≢ z
m≢z ()
m≢s : m ≢ s
m≢s ()
m≢n : m ≢ n
m≢n ()
p≢n : p ≢ n
p≢n ()
p≢m : p ≢ m
p≢m ()
two : Term
two = `suc `suc `zero
⊢two : ε ⊢ two ⦂ `
⊢two = (⊢suc (⊢suc ⊢zero))
plus : Term
plus = `Y (`λ p ⇒ `λ m ⇒ `λ n ⇒ `if0 ` m then ` n else ` p · (`pred ` m) · ` n)
⊢plus : ε ⊢ plus ⦂ ` ⇒ ` ⇒ `
⊢plus = (⊢Y (⊢λ (⊢λ (⊢λ (⊢if0 (Ax ⊢m) (Ax ⊢n) (Ax ⊢p · (⊢pred (Ax ⊢m)) · Ax ⊢n))))))
where
⊢p = S p≢n (S p≢m Z)
⊢m = S m≢n Z
⊢n = Z
four : Term
four = plus · two · two
⊢four : ε ⊢ four ⦂ `
⊢four = ⊢plus · ⊢two · ⊢two
Ch : Type
Ch = (` ⇒ `) ⇒ ` ⇒ `
twoCh : Term
twoCh = `λ s ⇒ `λ z ⇒ (` s · (` s · ` z))
⊢twoCh : ε ⊢ twoCh ⦂ Ch
⊢twoCh = (⊢λ (⊢λ (Ax ⊢s · (Ax ⊢s · Ax ⊢z))))
where
⊢s = S s≢z Z
⊢z = Z
plusCh : Term
plusCh = `λ m ⇒ `λ n ⇒ `λ s ⇒ `λ z ⇒ ` m · ` s · (` n · ` s · ` z)
⊢plusCh : ε ⊢ plusCh ⦂ Ch ⇒ Ch ⇒ Ch
⊢plusCh = (⊢λ (⊢λ (⊢λ (⊢λ (Ax ⊢m · Ax ⊢s · (Ax ⊢n · Ax ⊢s · Ax ⊢z))))))
where
⊢m = S m≢z (S m≢s (S m≢n Z))
⊢n = S n≢z (S n≢s Z)
⊢s = S s≢z Z
⊢z = Z
fromCh : Term
fromCh = `λ m ⇒ ` m · (`λ s ⇒ `suc ` s) · `zero
⊢fromCh : ε ⊢ fromCh ⦂ Ch ⇒ `
⊢fromCh = (⊢λ (Ax ⊢m · (⊢λ (⊢suc (Ax ⊢s))) · ⊢zero))
where
⊢m = Z
⊢s = Z
fourCh : Term
fourCh = fromCh · (plusCh · twoCh · twoCh)
⊢fourCh : ε ⊢ fourCh ⦂ `
⊢fourCh = ⊢fromCh · (⊢plusCh · ⊢twoCh · ⊢twoCh)
\end{code}
## Erasure
\begin{code}
lookup : ∀ {Γ x A} → Γ ∋ x ⦂ A → Id
lookup {Γ , x ⦂ A} Z = x
lookup {Γ , x ⦂ A} (S _ ⊢w) = lookup {Γ} ⊢w
erase : ∀ {Γ M A} → Γ ⊢ M ⦂ A → Term
erase (Ax ⊢w) = ` lookup ⊢w
erase (⊢λ {x = x} ⊢N) = `λ x ⇒ erase ⊢N
erase (⊢L · ⊢M) = erase ⊢L · erase ⊢M
erase (⊢zero) = `zero
erase (⊢suc ⊢M) = `suc (erase ⊢M)
erase (⊢pred ⊢M) = `pred (erase ⊢M)
erase (⊢if0 ⊢L ⊢M ⊢N) = `if0 (erase ⊢L) then (erase ⊢M) else (erase ⊢N)
erase (⊢Y ⊢M) = `Y (erase ⊢M)
\end{code}
### Properties of erasure
\begin{code}
cong₃ : ∀ {A B C D : Set} (f : A → B → C → D) {s t u v x y} →
s ≡ t → u ≡ v → x ≡ y → f s u x ≡ f t v y
cong₃ f refl refl refl = refl
lookup-lemma : ∀ {Γ x A} → (⊢x : Γ ∋ x ⦂ A) → lookup ⊢x ≡ x
lookup-lemma Z = refl
lookup-lemma (S _ ⊢w) = lookup-lemma ⊢w
erase-lemma : ∀ {Γ M A} → (⊢M : Γ ⊢ M ⦂ A) → erase ⊢M ≡ M
erase-lemma (Ax ⊢x) = cong `_ (lookup-lemma ⊢x)
erase-lemma (⊢λ {x = x} ⊢N) = cong (`λ x ⇒_) (erase-lemma ⊢N)
erase-lemma (⊢L · ⊢M) = cong₂ _·_ (erase-lemma ⊢L) (erase-lemma ⊢M)
erase-lemma (⊢zero) = refl
erase-lemma (⊢suc ⊢M) = cong `suc_ (erase-lemma ⊢M)
erase-lemma (⊢pred ⊢M) = cong `pred_ (erase-lemma ⊢M)
erase-lemma (⊢if0 ⊢L ⊢M ⊢N) = cong₃ `if0_then_else_
(erase-lemma ⊢L) (erase-lemma ⊢M) (erase-lemma ⊢N)
erase-lemma (⊢Y ⊢M) = cong `Y_ (erase-lemma ⊢M)
\end{code}
## Substitution
### Lists as sets
\begin{code}
open Collections.CollectionDec (Id) (_≟_)
\end{code}
### Free variables
\begin{code}
free : Term → List Id
free (` x) = [ x ]
free (`λ x ⇒ N) = free N \\ x
free (L · M) = free L ++ free M
free (`zero) = []
free (`suc M) = free M
free (`pred M) = free M
free (`if0 L then M else N) = free L ++ free M ++ free N
free (`Y M) = free M
\end{code}
### Fresh identifier
\begin{code}
bump : String → Id →
bump s (id t n) with s String.≟ t
... | yes refl = suc n
... | no _ = 0
next : String → List Id →
next s = foldr _⊔_ 0 ∘ map (bump s)
⊔-lemma : ∀ {s w xs} → w ∈ xs → bump s w ≤ next s xs
⊔-lemma {s} {_} {_ ∷ xs} here = m≤m⊔n _ (next s xs)
⊔-lemma {s} {_} {_ ∷ xs} (there x∈) = ≤-trans (⊔-lemma x∈) (n≤m⊔n _ (next s xs))
fresh : Id → List Id → Id
fresh (id s _) xs = id s (next s xs)
fresh-lemma : ∀ {w x xs} → w ∈ xs → w ≢ fresh x xs
fresh-lemma {w @ (id t n)} {x @ (id s _)} {xs} w∈ w≢fr = {! (⊔-lemma {s} {w} {xs} w∈)!} -- with s String.≟ t
{-
... | yes refl = {! (⊔-lemma {s} {w} {xs} w∈)!}
... | no s≢t = {!!}
with s String.≟ t | fresh x xs
... | yes refl | fr = {! (⊔-lemma {s} {w} {xs} w∈)!}
... | no s≢t | _ = s≢t refl
next-lemma : ∀ {x xs} → x ∈ xs → x ≢ next xs
next-lemma x∈ refl = 1+n≰n (⊔-lemma x∈)
\end{code}
### Identifier maps
\begin{code}
∅ : Id → Term
∅ x = ` x
infixl 5 _,_↦_
_,_↦_ : (Id → Term) → Id → Term → (Id → Term)
(ρ , x ↦ M) w with w ≟ x
... | yes _ = M
... | no _ = ρ w
\end{code}
### Substitution
\begin{code}
subst : List Id → (Id → Term) → Term → Term
subst ys ρ (` x) = ρ x
subst ys ρ (`λ x ⇒ N) = `λ y ⇒ subst (y ∷ ys) (ρ , x ↦ ` y) N
where
y = fresh ys
subst ys ρ (L · M) = subst ys ρ L · subst ys ρ M
subst ys ρ (`zero) = `zero
subst ys ρ (`suc M) = `suc (subst ys ρ M)
subst ys ρ (`pred M) = `pred (subst ys ρ M)
subst ys ρ (`if0 L then M else N)
= `if0 (subst ys ρ L) then (subst ys ρ M) else (subst ys ρ N)
subst ys ρ (`Y M) = `Y (subst ys ρ M)
_[_:=_] : Term → Id → Term → Term
N [ x := M ] = subst (free M ++ (free N \\ x)) (∅ , x ↦ M) N
\end{code}
### Testing substitution
\begin{code}
_ : (` s · ` s · ` z) [ z := `zero ] ≡ (` s · ` s · `zero)
_ = refl
_ : (` s · ` s · ` z) [ s := (`λ m ⇒ `suc ` m) ] [ z := `zero ]
≡ ((`λ p ⇒ `suc ` p) · (`λ p ⇒ `suc ` p) · `zero)
_ = refl
_ : (`λ m ⇒ ` m · ` n) [ n := ` m ] ≡ (`λ n ⇒ ` n · ` m)
_ = refl
_ : subst [ m , n ] (∅ , m ↦ ` n , n ↦ ` m) (` m · ` n) ≡ (` n · ` m)
_ = refl
\end{code}
## Values
\begin{code}
data Value : Term → Set where
Zero :
----------
Value `zero
Suc : ∀ {V}
→ Value V
--------------
→ Value (`suc V)
Fun : ∀ {x N}
---------------
→ Value (`λ x ⇒ N)
\end{code}
## Reduction
\begin{code}
infix 4 _⟶_
data _⟶_ : Term → Term → Set where
ξ-·₁ : ∀ {L L M}
→ L ⟶ L
----------------
→ L · M ⟶ L · M
ξ-·₂ : ∀ {V M M}
→ Value V
→ M ⟶ M
----------------
→ V · M ⟶ V · M
β-⇒ : ∀ {x N V}
→ Value V
------------------------------
→ (`λ x ⇒ N) · V ⟶ N [ x := V ]
ξ-suc : ∀ {M M}
→ M ⟶ M
------------------
→ `suc M ⟶ `suc M
ξ-pred : ∀ {M M}
→ M ⟶ M
--------------------
→ `pred M ⟶ `pred M
β-pred-zero :
---------------------
`pred `zero ⟶ `zero
β-pred-suc : ∀ {V}
→ Value V
--------------------
→ `pred (`suc V) ⟶ V
ξ-if0 : ∀ {L L M N}
→ L ⟶ L
----------------------------------------------
→ `if0 L then M else N ⟶ `if0 L then M else N
β-if0-zero : ∀ {M N}
------------------------------
→ `if0 `zero then M else N ⟶ M
β-if0-suc : ∀ {V M N}
→ Value V
---------------------------------
→ `if0 (`suc V) then M else N ⟶ N
ξ-Y : ∀ {M M}
→ M ⟶ M
--------------
→ `Y M ⟶ `Y M
β-Y : ∀ {V x N}
→ Value V
→ V ≡ `λ x ⇒ N
------------------------
→ `Y V ⟶ N [ x := `Y V ]
\end{code}
## Reflexive and transitive closure
\begin{code}
infix 2 _⟶*_
infix 1 begin_
infixr 2 _⟶⟨_⟩_
infix 3 _∎
data _⟶*_ : Term → Term → Set where
_∎ : ∀ {M}
-------------
→ M ⟶* M
_⟶⟨_⟩_ : ∀ (L : Term) {M N}
→ L ⟶ M
→ M ⟶* N
---------
→ L ⟶* N
begin_ : ∀ {M N} → (M ⟶* N) → (M ⟶* N)
begin M⟶*N = M⟶*N
\end{code}
## Canonical forms
\begin{code}
data Canonical : Term → Type → Set where
Zero :
------------------
Canonical `zero `
Suc : ∀ {V}
→ Canonical V `
---------------------
→ Canonical (`suc V) `
Fun : ∀ {x N A B}
→ ε , x ⦂ A ⊢ N ⦂ B
------------------------------
→ Canonical (`λ x ⇒ N) (A ⇒ B)
\end{code}
## Canonical forms lemma
Every typed value is canonical.
\begin{code}
canonical : ∀ {V A}
→ ε ⊢ V ⦂ A
→ Value V
-------------
→ Canonical V A
canonical ⊢zero Zero = Zero
canonical (⊢suc ⊢V) (Suc VV) = Suc (canonical ⊢V VV)
canonical (⊢λ ⊢N) Fun = Fun ⊢N
\end{code}
Every canonical form has a type and a value.
\begin{code}
type : ∀ {V A}
→ Canonical V A
-------------
→ ε ⊢ V ⦂ A
type Zero = ⊢zero
type (Suc CV) = ⊢suc (type CV)
type (Fun ⊢N) = ⊢λ ⊢N
value : ∀ {V A}
→ Canonical V A
-------------
→ Value V
value Zero = Zero
value (Suc CV) = Suc (value CV)
value (Fun ⊢N) = Fun
\end{code}
## Progress
\begin{code}
data Progress (M : Term) (A : Type) : Set where
step : ∀ {N}
→ M ⟶ N
----------
→ Progress M A
done :
Canonical M A
-------------
→ Progress M A
progress : ∀ {M A} → ε ⊢ M ⦂ A → Progress M A
progress (Ax ())
progress (⊢λ ⊢N) = done (Fun ⊢N)
progress (⊢L · ⊢M) with progress ⊢L
... | step L⟶L = step (ξ-·₁ L⟶L)
... | done (Fun _) with progress ⊢M
... | step M⟶M = step (ξ-·₂ Fun M⟶M)
... | done CM = step (β-⇒ (value CM))
progress ⊢zero = done Zero
progress (⊢suc ⊢M) with progress ⊢M
... | step M⟶M = step (ξ-suc M⟶M)
... | done CM = done (Suc CM)
progress (⊢pred ⊢M) with progress ⊢M
... | step M⟶M = step (ξ-pred M⟶M)
... | done Zero = step β-pred-zero
... | done (Suc CM) = step (β-pred-suc (value CM))
progress (⊢if0 ⊢L ⊢M ⊢N) with progress ⊢L
... | step L⟶L = step (ξ-if0 L⟶L)
... | done Zero = step β-if0-zero
... | done (Suc CM) = step (β-if0-suc (value CM))
progress (⊢Y ⊢M) with progress ⊢M
... | step M⟶M = step (ξ-Y M⟶M)
... | done (Fun _) = step (β-Y Fun refl)
\end{code}
## Preservation
### Domain of an environment
\begin{code}
dom : Env → List Id
dom ε = []
dom (Γ , x ⦂ A) = x ∷ dom Γ
dom-lemma : ∀ {Γ y B} → Γ ∋ y ⦂ B → y ∈ dom Γ
dom-lemma Z = here
dom-lemma (S x≢y ⊢y) = there (dom-lemma ⊢y)
free-lemma : ∀ {Γ M A} → Γ ⊢ M ⦂ A → free M ⊆ dom Γ
free-lemma (Ax ⊢x) w∈ with w∈
... | here = dom-lemma ⊢x
... | there ()
free-lemma {Γ} (⊢λ {N = N} ⊢N) = ∷-to-\\ (free-lemma ⊢N)
free-lemma (⊢L · ⊢M) w∈ with ++-to-⊎ w∈
... | inj₁ ∈L = free-lemma ⊢L ∈L
... | inj₂ ∈M = free-lemma ⊢M ∈M
free-lemma ⊢zero ()
free-lemma (⊢suc ⊢M) w∈ = free-lemma ⊢M w∈
free-lemma (⊢pred ⊢M) w∈ = free-lemma ⊢M w∈
free-lemma (⊢if0 ⊢L ⊢M ⊢N) w∈
with ++-to-⊎ w∈
... | inj₁ ∈L = free-lemma ⊢L ∈L
... | inj₂ ∈MN with ++-to-⊎ ∈MN
... | inj₁ ∈M = free-lemma ⊢M ∈M
... | inj₂ ∈N = free-lemma ⊢N ∈N
free-lemma (⊢Y ⊢M) w∈ = free-lemma ⊢M w∈
\end{code}
### Renaming
\begin{code}
⊢rename : ∀ {Γ Δ xs}
→ (∀ {x A} → x ∈ xs → Γ ∋ x ⦂ A → Δ ∋ x ⦂ A)
--------------------------------------------------
→ (∀ {M A} → free M ⊆ xs → Γ ⊢ M ⦂ A → Δ ⊢ M ⦂ A)
⊢rename ⊢σ ⊆xs (Ax ⊢x) = Ax (⊢σ ∈xs ⊢x)
where
∈xs = ⊆xs here
⊢rename {Γ} {Δ} {xs} ⊢σ ⊆xs (⊢λ {x = x} {N = N} {A = A} ⊢N)
= ⊢λ (⊢rename {Γ′} {Δ′} {xs} ⊢σ′ ⊆xs ⊢N)
where
Γ′ = Γ , x ⦂ A
Δ′ = Δ , x ⦂ A
xs = x ∷ xs
⊢σ′ : ∀ {w B} → w ∈ xs → Γ′ ∋ w ⦂ B → Δ′ ∋ w ⦂ B
⊢σ′ w∈ Z = Z
⊢σ′ w∈ (S w≢ ⊢w) = S w≢ (⊢σ ∈w ⊢w)
where
∈w = there⁻¹ w∈ w≢
⊆xs : free N ⊆ xs
⊆xs = \\-to-∷ ⊆xs
⊢rename ⊢σ ⊆xs (⊢L · ⊢M) = ⊢rename ⊢σ L⊆ ⊢L · ⊢rename ⊢σ M⊆ ⊢M
where
L⊆ = trans-⊆ ⊆-++₁ ⊆xs
M⊆ = trans-⊆ ⊆-++₂ ⊆xs
⊢rename ⊢σ ⊆xs (⊢zero) = ⊢zero
⊢rename ⊢σ ⊆xs (⊢suc ⊢M) = ⊢suc (⊢rename ⊢σ ⊆xs ⊢M)
⊢rename ⊢σ ⊆xs (⊢pred ⊢M) = ⊢pred (⊢rename ⊢σ ⊆xs ⊢M)
⊢rename ⊢σ ⊆xs (⊢if0 {L = L} ⊢L ⊢M ⊢N)
= ⊢if0 (⊢rename ⊢σ L⊆ ⊢L) (⊢rename ⊢σ M⊆ ⊢M) (⊢rename ⊢σ N⊆ ⊢N)
where
L⊆ = trans-⊆ ⊆-++₁ ⊆xs
M⊆ = trans-⊆ ⊆-++₁ (trans-⊆ (⊆-++₂ {free L}) ⊆xs)
N⊆ = trans-⊆ ⊆-++₂ (trans-⊆ (⊆-++₂ {free L}) ⊆xs)
⊢rename ⊢σ ⊆xs (⊢Y ⊢M) = ⊢Y (⊢rename ⊢σ ⊆xs ⊢M)
\end{code}
### Substitution preserves types
\begin{code}
⊢subst : ∀ {Γ Δ xs ys ρ}
→ (∀ {x} → x ∈ xs → free (ρ x) ⊆ ys)
→ (∀ {x A} → x ∈ xs → Γ ∋ x ⦂ A → Δ ⊢ ρ x ⦂ A)
-------------------------------------------------------------
→ (∀ {M A} → free M ⊆ xs → Γ ⊢ M ⦂ A → Δ ⊢ subst ys ρ M ⦂ A)
⊢subst Σ ⊢ρ ⊆xs (Ax ⊢x)
= ⊢ρ (⊆xs here) ⊢x
⊢subst {Γ} {Δ} {xs} {ys} {ρ} Σ ⊢ρ ⊆xs (⊢λ {x = x} {N = N} {A = A} ⊢N)
= ⊢λ {x = y} {A = A} (⊢subst {Γ′} {Δ′} {xs} {ys} {ρ} Σ′ ⊢ρ′ ⊆xs ⊢N)
where
y = fresh ys
Γ′ = Γ , x ⦂ A
Δ′ = Δ , y ⦂ A
xs = x ∷ xs
ys = y ∷ ys
ρ = ρ , x ↦ ` y
Σ′ : ∀ {w} → w ∈ xs → free (ρ w) ⊆ ys
Σ′ {w} w∈ with w ≟ x
... | yes refl = ⊆-++₁
... | no w≢ = ⊆-++₂ ∘ Σ (there⁻¹ w∈ w≢)
⊆xs : free N ⊆ xs
⊆xs = \\-to-∷ ⊆xs
⊢σ : ∀ {w C} → w ∈ ys → Δ ∋ w ⦂ C → Δ′ ∋ w ⦂ C
⊢σ w∈ ⊢w = S (fresh-lemma w∈) ⊢w
⊢ρ′ : ∀ {w C} → w ∈ xs → Γ′ ∋ w ⦂ C → Δ′ ⊢ ρ w ⦂ C
⊢ρ′ {w} _ Z with w ≟ x
... | yes _ = Ax Z
... | no w≢ = ⊥-elim (w≢ refl)
⊢ρ′ {w} w∈ (S w≢ ⊢w) with w ≟ x
... | yes refl = ⊥-elim (w≢ refl)
... | no _ = ⊢rename {Δ} {Δ′} {ys} ⊢σ (Σ w∈) (⊢ρ w∈ ⊢w)
where
w∈ = there⁻¹ w∈ w≢
⊢subst Σ ⊢ρ ⊆xs (⊢L · ⊢M)
= ⊢subst Σ ⊢ρ L⊆ ⊢L · ⊢subst Σ ⊢ρ M⊆ ⊢M
where
L⊆ = trans-⊆ ⊆-++₁ ⊆xs
M⊆ = trans-⊆ ⊆-++₂ ⊆xs
⊢subst Σ ⊢ρ ⊆xs ⊢zero = ⊢zero
⊢subst Σ ⊢ρ ⊆xs (⊢suc ⊢M) = ⊢suc (⊢subst Σ ⊢ρ ⊆xs ⊢M)
⊢subst Σ ⊢ρ ⊆xs (⊢pred ⊢M) = ⊢pred (⊢subst Σ ⊢ρ ⊆xs ⊢M)
⊢subst Σ ⊢ρ ⊆xs (⊢if0 {L = L} ⊢L ⊢M ⊢N)
= ⊢if0 (⊢subst Σ ⊢ρ L⊆ ⊢L) (⊢subst Σ ⊢ρ M⊆ ⊢M) (⊢subst Σ ⊢ρ N⊆ ⊢N)
where
L⊆ = trans-⊆ ⊆-++₁ ⊆xs
M⊆ = trans-⊆ ⊆-++₁ (trans-⊆ (⊆-++₂ {free L}) ⊆xs)
N⊆ = trans-⊆ ⊆-++₂ (trans-⊆ (⊆-++₂ {free L}) ⊆xs)
⊢subst Σ ⊢ρ ⊆xs (⊢Y ⊢M) = ⊢Y (⊢subst Σ ⊢ρ ⊆xs ⊢M)
⊢substitution : ∀ {Γ x A N B M} →
Γ , x ⦂ A ⊢ N ⦂ B →
Γ ⊢ M ⦂ A →
--------------------
Γ ⊢ N [ x := M ] ⦂ B
⊢substitution {Γ} {x} {A} {N} {B} {M} ⊢N ⊢M =
⊢subst {Γ′} {Γ} {xs} {ys} {ρ} Σ ⊢ρ {N} {B} ⊆xs ⊢N
where
Γ′ = Γ , x ⦂ A
xs = free N
ys = free M ++ (free N \\ x)
ρ = ∅ , x ↦ M
Σ : ∀ {w} → w ∈ xs → free (ρ w) ⊆ ys
Σ {w} w∈ y∈ with w ≟ x
... | yes _ = ⊆-++₁ y∈
... | no w≢ rewrite ∈-[_] y∈ = ⊆-++₂ (∈-≢-to-\\ w∈ w≢)
⊢ρ : ∀ {w B} → w ∈ xs → Γ′ ∋ w ⦂ B → Γ ⊢ ρ w ⦂ B
⊢ρ {w} w∈ Z with w ≟ x
... | yes _ = ⊢M
... | no w≢ = ⊥-elim (w≢ refl)
⊢ρ {w} w∈ (S w≢ ⊢w) with w ≟ x
... | yes refl = ⊥-elim (w≢ refl)
... | no _ = Ax ⊢w
⊆xs : free N ⊆ xs
⊆xs x∈ = x∈
\end{code}
### Preservation
\begin{code}
preservation : ∀ {Γ M N A}
→ Γ ⊢ M ⦂ A
→ M ⟶ N
---------
→ Γ ⊢ N ⦂ A
preservation (Ax ⊢x) ()
preservation (⊢λ ⊢N) ()
preservation (⊢L · ⊢M) (ξ-·₁ L⟶) = preservation ⊢L L⟶ · ⊢M
preservation (⊢V · ⊢M) (ξ-·₂ _ M⟶) = ⊢V · preservation ⊢M M⟶
preservation ((⊢λ ⊢N) · ⊢W) (β-⇒ _) = ⊢substitution ⊢N ⊢W
preservation (⊢zero) ()
preservation (⊢suc ⊢M) (ξ-suc M⟶) = ⊢suc (preservation ⊢M M⟶)
preservation (⊢pred ⊢M) (ξ-pred M⟶) = ⊢pred (preservation ⊢M M⟶)
preservation (⊢pred ⊢zero) (β-pred-zero) = ⊢zero
preservation (⊢pred (⊢suc ⊢M)) (β-pred-suc _) = ⊢M
preservation (⊢if0 ⊢L ⊢M ⊢N) (ξ-if0 L⟶) = ⊢if0 (preservation ⊢L L⟶) ⊢M ⊢N
preservation (⊢if0 ⊢zero ⊢M ⊢N) β-if0-zero = ⊢M
preservation (⊢if0 (⊢suc ⊢V) ⊢M ⊢N) (β-if0-suc _) = ⊢N
preservation (⊢Y ⊢M) (ξ-Y M⟶) = ⊢Y (preservation ⊢M M⟶)
preservation (⊢Y (⊢λ ⊢N)) (β-Y _ refl) = ⊢substitution ⊢N (⊢Y (⊢λ ⊢N))
-}
\end{code}

View file

@ -1,841 +0,0 @@
---
title : "Typed: Typed Lambda term representation"
layout : page
permalink : /Typed
---
## Imports
\begin{code}
module Typed where
\end{code}
\begin{code}
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong; cong₂; _≢_)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.List using (List; []; _∷_; _++_; map; foldr; filter)
open import Data.Nat using (; zero; suc; _+_)
open import Data.String using (String; _≟_)
open import Data.Product using (_×_; proj₁; proj₂) renaming (_,_ to ⟨_,_⟩)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Function using (_∘_)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Negation using (¬?)
open import Collections
pattern [_] x = x ∷ []
pattern [_,_] x y = x ∷ y ∷ []
pattern [_,_,_] x y z = x ∷ y ∷ z ∷ []
\end{code}
## Syntax
\begin{code}
infix 4 _wf
infix 4 _∉_
infix 4 _∋_`:_
infix 4 _⊢_`:_
infixl 5 _,_`:_
infixr 6 _`→_
infix 6 `λ_`→_
infixl 7 `if0_then_else_
infix 8 `suc_ `pred_ `Y_
infixl 9 _·_
infix 10 S_
Id : Set
Id = String
data Type : Set where
` : Type
_`→_ : Type → Type → Type
data Env : Set where
ε : Env
_,_`:_ : Env → Id → Type → Env
data Term : Set where
`_ : Id → Term
`λ_`→_ : Id → Term → Term
_·_ : Term → Term → Term
`zero : Term
`suc_ : Term → Term
`pred_ : Term → Term
`if0_then_else_ : Term → Term → Term → Term
`Y_ : Term → Term
data _∋_`:_ : Env → Id → Type → Set where
Z : ∀ {Γ A x}
--------------------
→ Γ , x `: A ∋ x `: A
S_ : ∀ {Γ A B x w}
→ Γ ∋ w `: B
--------------------
→ Γ , x `: A ∋ w `: B
_∉_ : Id → Env → Set
x ∉ Γ = ∀ {A} → ¬ (Γ ∋ x `: A)
data _⊢_`:_ : Env → Term → Type → Set where
Ax : ∀ {Γ A x}
→ Γ ∋ x `: A
--------------
→ Γ ⊢ ` x `: A
⊢λ : ∀ {Γ x N A B}
→ x ∉ Γ
→ Γ , x `: A ⊢ N `: B
--------------------------
→ Γ ⊢ (`λ x `→ N) `: A `→ B
_·_ : ∀ {Γ L M A B}
→ Γ ⊢ L `: A `→ B
→ Γ ⊢ M `: A
----------------
→ Γ ⊢ L · M `: B
⊢zero : ∀ {Γ}
----------------
→ Γ ⊢ `zero `: `
⊢suc : ∀ {Γ M}
→ Γ ⊢ M `: `
-----------------
→ Γ ⊢ `suc M `: `
⊢pred : ∀ {Γ M}
→ Γ ⊢ M `: `
------------------
→ Γ ⊢ `pred M `: `
⊢if0 : ∀ {Γ L M N A}
→ Γ ⊢ L `: `
→ Γ ⊢ M `: A
→ Γ ⊢ N `: A
------------------------------
→ Γ ⊢ `if0 L then M else N `: A
⊢Y : ∀ {Γ M A}
→ Γ ⊢ M `: A `→ A
----------------
→ Γ ⊢ `Y M `: A
data _wf : Env → Set where
empty :
-----
ε wf
extend : ∀ {Γ x A}
→ Γ wf
→ x ∉ Γ
-------------------------
→ (Γ , x `: A) wf
\end{code}
## Test examples
\begin{code}
two : Term
two = `suc `suc `zero
⊢two : ε ⊢ two `: `
⊢two = (⊢suc (⊢suc ⊢zero))
plus : Term
plus = `Y (`λ "p" `→ `λ "m" `→ `λ "n" `→ `if0 ` "m" then ` "n" else ` "p" · (`pred ` "m") · ` "n")
⊢plus : ε ⊢ plus `: ` `→ ` `→ `
⊢plus = (⊢Y (⊢λ p∉ (⊢λ m∉ (⊢λ n∉
(⊢if0 (Ax ⊢m) (Ax ⊢n) (Ax ⊢p · (⊢pred (Ax ⊢m)) · Ax ⊢n))))))
where
⊢p = S S Z
⊢m = S Z
⊢n = Z
Γ₀ = ε
Γ₁ = Γ₀ , "p" `: ` `→ ` `→ `
Γ₂ = Γ₁ , "m" `: `
p∉ : "p" ∉ Γ₀
p∉ ()
m∉ : "m" ∉ Γ₁
m∉ (S ())
n∉ : "n" ∉ Γ₂
n∉ (S S ())
four : Term
four = plus · two · two
⊢four : ε ⊢ four `: `
⊢four = ⊢plus · ⊢two · ⊢two
Ch : Type
Ch = (` `→ `) `→ ` `→ `
twoCh : Term
twoCh = `λ "s" `→ `λ "z" `→ (` "s" · (` "s" · ` "z"))
⊢twoCh : ε ⊢ twoCh `: Ch
⊢twoCh = (⊢λ s∉ (⊢λ z∉ (Ax ⊢s · (Ax ⊢s · Ax ⊢z))))
where
⊢s = S Z
⊢z = Z
Γ₀ = ε
Γ₁ = Γ₀ , "s" `: ` `→ `
s∉ : "s" ∉ ε
s∉ ()
z∉ : "z" ∉ Γ₁
z∉ (S ())
plusCh : Term
plusCh = `λ "m" `→ `λ "n" `→ `λ "s" `→ `λ "z" `→
` "m" · ` "s" · (` "n" · ` "s" · ` "z")
⊢plusCh : ε ⊢ plusCh `: Ch `→ Ch `→ Ch
⊢plusCh = (⊢λ m∉ (⊢λ n∉ (⊢λ s∉ (⊢λ z∉ (Ax ⊢m · Ax ⊢s · (Ax ⊢n · Ax ⊢s · Ax ⊢z))))))
where
⊢m = S S S Z
⊢n = S S Z
⊢s = S Z
⊢z = Z
Γ₀ = ε
Γ₁ = Γ₀ , "m" `: Ch
Γ₂ = Γ₁ , "n" `: Ch
Γ₃ = Γ₂ , "s" `: ` `→ `
m∉ : "m" ∉ Γ₀
m∉ ()
n∉ : "n" ∉ Γ₁
n∉ (S ())
s∉ : "s" ∉ Γ₂
s∉ (S S ())
z∉ : "z" ∉ Γ₃
z∉ (S S S ())
fromCh : Term
fromCh = `λ "m" `→ ` "m" · (`λ "s" `→ `suc ` "s") · `zero
⊢fromCh : ε ⊢ fromCh `: Ch `→ `
⊢fromCh = (⊢λ m∉ (Ax ⊢m · (⊢λ s∉ (⊢suc (Ax ⊢s))) · ⊢zero))
where
⊢m = Z
⊢s = Z
Γ₀ = ε
Γ₁ = Γ₀ , "m" `: Ch
m∉ : "m" ∉ Γ₀
m∉ ()
s∉ : "s" ∉ Γ₁
s∉ (S ())
fourCh : Term
fourCh = fromCh · (plusCh · twoCh · twoCh)
⊢fourCh : ε ⊢ fourCh `: `
⊢fourCh = ⊢fromCh · (⊢plusCh · ⊢twoCh · ⊢twoCh)
\end{code}
## Erasure
\begin{code}
lookup : ∀ {Γ x A} → Γ ∋ x `: A → Id
lookup {Γ , x `: A} Z = x
lookup {Γ , x `: A} (S ⊢w) = lookup {Γ} ⊢w
erase : ∀ {Γ M A} → Γ ⊢ M `: A → Term
erase (Ax ⊢w) = ` lookup ⊢w
erase (⊢λ {x = x} x∉ ⊢N) = `λ x `→ erase ⊢N
erase (⊢L · ⊢M) = erase ⊢L · erase ⊢M
erase (⊢zero) = `zero
erase (⊢suc ⊢M) = `suc (erase ⊢M)
erase (⊢pred ⊢M) = `pred (erase ⊢M)
erase (⊢if0 ⊢L ⊢M ⊢N) = `if0 (erase ⊢L) then (erase ⊢M) else (erase ⊢N)
erase (⊢Y ⊢M) = `Y (erase ⊢M)
\end{code}
### Properties of erasure
\begin{code}
cong₃ : ∀ {A B C D : Set} (f : A → B → C → D) {s t u v x y} →
s ≡ t → u ≡ v → x ≡ y → f s u x ≡ f t v y
cong₃ f refl refl refl = refl
lookup-lemma : ∀ {Γ x A} → (⊢x : Γ ∋ x `: A) → lookup ⊢x ≡ x
lookup-lemma Z = refl
lookup-lemma (S ⊢w) = lookup-lemma ⊢w
erase-lemma : ∀ {Γ M A} → (⊢M : Γ ⊢ M `: A) → erase ⊢M ≡ M
erase-lemma (Ax ⊢x) = cong `_ (lookup-lemma ⊢x)
erase-lemma (⊢λ {x = x} x∉ ⊢N) = cong (`λ x `→_) (erase-lemma ⊢N)
erase-lemma (⊢L · ⊢M) = cong₂ _·_ (erase-lemma ⊢L) (erase-lemma ⊢M)
erase-lemma (⊢zero) = refl
erase-lemma (⊢suc ⊢M) = cong `suc_ (erase-lemma ⊢M)
erase-lemma (⊢pred ⊢M) = cong `pred_ (erase-lemma ⊢M)
erase-lemma (⊢if0 ⊢L ⊢M ⊢N) = cong₃ `if0_then_else_
(erase-lemma ⊢L) (erase-lemma ⊢M) (erase-lemma ⊢N)
erase-lemma (⊢Y ⊢M) = cong `Y_ (erase-lemma ⊢M)
\end{code}
## Substitution
### Lists as sets
\begin{code}
open Collections.CollectionDec (Id) (_≟_)
\end{code}
### Free variables
\begin{code}
free : Term → List Id
free (` x) = [ x ]
free (`λ x `→ N) = free N \\ x
free (L · M) = free L ++ free M
free (`zero) = []
free (`suc M) = free M
free (`pred M) = free M
free (`if0 L then M else N) = free L ++ free M ++ free N
free (`Y M) = free M
\end{code}
### Identifier maps
\begin{code}
∅ : Id → Term
∅ x = ` x
infixl 5 _,_↦_
_,_↦_ : (Id → Term) → Id → Term → (Id → Term)
(ρ , x ↦ M) w with w ≟ x
... | yes _ = M
... | no _ = ρ w
\end{code}
### Substitution
\begin{code}
subst : (Id → Term) → Term → Term
subst ρ (` x) = ρ x
subst ρ (`λ x `→ N) = `λ x `→ subst (ρ , x ↦ ` x) N
subst ρ (L · M) = subst ρ L · subst ρ M
subst ρ (`zero) = `zero
subst ρ (`suc M) = `suc (subst ρ M)
subst ρ (`pred M) = `pred (subst ρ M)
subst ρ (`if0 L then M else N)
= `if0 (subst ρ L) then (subst ρ M) else (subst ρ N)
subst ρ (`Y M) = `Y (subst ρ M)
_[_:=_] : Term → Id → Term → Term
N [ x := M ] = subst (∅ , x ↦ M) N
\end{code}
### Testing substitution
\begin{code}
_ : (` "s" · ` "s" · ` "z") [ "z" := `zero ] ≡ (` "s" · ` "s" · `zero)
_ = refl
_ : (` "s" · ` "s" · ` "z") [ "s" := (`λ "m" `→ `suc ` "m") ] [ "z" := `zero ]
≡ (`λ "m" `→ `suc ` "m") · (`λ "m" `→ `suc ` "m") · `zero
_ = refl
_ : (`λ "m" `→ ` "m" · ` "n") [ "n" := ` "p" · ` "q" ]
≡ `λ "m" `→ ` "m" · (` "p" · ` "q")
_ = refl
_ : subst (∅ , "m" ↦ ` "p" , "n" ↦ ` "q") (` "m" · ` "n") ≡ (` "p" · ` "q")
_ = refl
\end{code}
## Values
\begin{code}
data Value : Term → Set where
Zero :
----------
Value `zero
Suc : ∀ {V}
→ Value V
--------------
→ Value (`suc V)
Fun : ∀ {x N}
---------------
→ Value (`λ x `→ N)
\end{code}
## Reduction
\begin{code}
infix 4 _⟶_
data _⟶_ : Term → Term → Set where
ξ-·₁ : ∀ {L L M}
→ L ⟶ L
-----------------
→ L · M ⟶ L · M
ξ-·₂ : ∀ {V M M}
→ Value V
→ M ⟶ M
-----------------
→ V · M ⟶ V · M
β-`→ : ∀ {x N V}
→ Value V
---------------------------------
→ (`λ x `→ N) · V ⟶ N [ x := V ]
ξ-suc : ∀ {M M}
→ M ⟶ M
-------------------
→ `suc M ⟶ `suc M
ξ-pred : ∀ {M M}
→ M ⟶ M
---------------------
→ `pred M ⟶ `pred M
β-pred-zero :
----------------------
`pred `zero ⟶ `zero
β-pred-suc : ∀ {V}
→ Value V
---------------------
→ `pred (`suc V) ⟶ V
ξ-if0 : ∀ {L L M N}
→ L ⟶ L
-----------------------------------------------
→ `if0 L then M else N ⟶ `if0 L then M else N
β-if0-zero : ∀ {M N}
-------------------------------
→ `if0 `zero then M else N ⟶ M
β-if0-suc : ∀ {V M N}
→ Value V
----------------------------------
→ `if0 (`suc V) then M else N ⟶ N
ξ-Y : ∀ {M M}
→ M ⟶ M
---------------
→ `Y M ⟶ `Y M
β-Y : ∀ {V x N}
→ Value V
→ V ≡ `λ x `→ N
-------------------------
→ `Y V ⟶ N [ x := `Y V ]
\end{code}
## Reflexive and transitive closure
\begin{code}
infix 2 _⟶*_
infix 1 begin_
infixr 2 _⟶⟨_⟩_
infix 3 _∎
data _⟶*_ : Term → Term → Set where
_∎ : ∀ (M : Term)
-------------
→ M ⟶* M
_⟶⟨_⟩_ : ∀ (L : Term) {M N}
→ L ⟶ M
→ M ⟶* N
---------
→ L ⟶* N
begin_ : ∀ {M N} → (M ⟶* N) → (M ⟶* N)
begin M⟶*N = M⟶*N
\end{code}
## Canonical forms
\begin{code}
data Canonical : Term → Type → Set where
Zero :
-------------------
Canonical `zero `
Suc : ∀ {V}
→ Canonical V `
----------------------
→ Canonical (`suc V) `
Fun : ∀ {x N A B}
→ ε , x `: A ⊢ N `: B
-------------------------------
→ Canonical (`λ x `→ N) (A `→ B)
\end{code}
## Canonical forms lemma
Every typed value is canonical.
\begin{code}
canonical : ∀ {V A}
→ ε ⊢ V `: A
→ Value V
-------------
→ Canonical V A
canonical ⊢zero Zero = Zero
canonical (⊢suc ⊢V) (Suc VV) = Suc (canonical ⊢V VV)
canonical (⊢λ x∉ ⊢N) Fun = Fun ⊢N
\end{code}
Every canonical form has a type and a value.
\begin{code}
type : ∀ {V A}
→ Canonical V A
--------------
→ ε ⊢ V `: A
type Zero = ⊢zero
type (Suc CV) = ⊢suc (type CV)
type (Fun {x = x} ⊢N) = ⊢λ x∉ ⊢N
where
x∉ : x ∉ ε
x∉ ()
value : ∀ {V A}
→ Canonical V A
-------------
→ Value V
value Zero = Zero
value (Suc CV) = Suc (value CV)
value (Fun ⊢N) = Fun
\end{code}
## Progress
\begin{code}
data Progress (M : Term) (A : Type) : Set where
step : ∀ {N}
→ M ⟶ N
----------
→ Progress M A
done :
Canonical M A
-------------
→ Progress M A
progress : ∀ {M A} → ε ⊢ M `: A → Progress M A
progress (Ax ())
progress (⊢λ x∉ ⊢N) = done (Fun ⊢N)
progress (⊢L · ⊢M) with progress ⊢L
... | step L⟶L = step (ξ-·₁ L⟶L)
... | done (Fun _) with progress ⊢M
... | step M⟶M = step (ξ-·₂ Fun M⟶M)
... | done CM = step (β-`→ (value CM))
progress ⊢zero = done Zero
progress (⊢suc ⊢M) with progress ⊢M
... | step M⟶M = step (ξ-suc M⟶M)
... | done CM = done (Suc CM)
progress (⊢pred ⊢M) with progress ⊢M
... | step M⟶M = step (ξ-pred M⟶M)
... | done Zero = step β-pred-zero
... | done (Suc CM) = step (β-pred-suc (value CM))
progress (⊢if0 ⊢L ⊢M ⊢N) with progress ⊢L
... | step L⟶L = step (ξ-if0 L⟶L)
... | done Zero = step β-if0-zero
... | done (Suc CM) = step (β-if0-suc (value CM))
progress (⊢Y ⊢M) with progress ⊢M
... | step M⟶M = step (ξ-Y M⟶M)
... | done (Fun _) = step (β-Y Fun refl)
\end{code}
## Preservation
### Domain of an environment
\begin{code}
{-
dom : Env → List Id
dom ε = []
dom (Γ , x `: A) = x ∷ dom Γ
dom-lemma : ∀ {Γ y B} → Γ ∋ y `: B → y ∈ dom Γ
dom-lemma Z = here
dom-lemma (S x≢y ⊢y) = there (dom-lemma ⊢y)
free-lemma : ∀ {Γ M A} → Γ ⊢ M `: A → free M ⊆ dom Γ
free-lemma (Ax ⊢x) w∈ with w∈
... | here = dom-lemma ⊢x
... | there ()
free-lemma {Γ} (⊢λ {N = N} ⊢N) = ∷-to-\\ (free-lemma ⊢N)
free-lemma (⊢L · ⊢M) w∈ with ++-to-⊎ w∈
... | inj₁ ∈L = free-lemma ⊢L ∈L
... | inj₂ ∈M = free-lemma ⊢M ∈M
free-lemma ⊢zero ()
free-lemma (⊢suc ⊢M) w∈ = free-lemma ⊢M w∈
free-lemma (⊢pred ⊢M) w∈ = free-lemma ⊢M w∈
free-lemma (⊢if0 ⊢L ⊢M ⊢N) w∈
with ++-to-⊎ w∈
... | inj₁ ∈L = free-lemma ⊢L ∈L
... | inj₂ ∈MN with ++-to-⊎ ∈MN
... | inj₁ ∈M = free-lemma ⊢M ∈M
... | inj₂ ∈N = free-lemma ⊢N ∈N
free-lemma (⊢Y ⊢M) w∈ = free-lemma ⊢M w∈
-}
\end{code}
### Renaming
Let's try an example. The result I want to prove is:
⊢subst : ∀ {Γ Δ ρ}
→ (∀ {x A} → Γ ∋ x `: A → Δ ⊢ ρ x `: A)
-----------------------------------------------
→ (∀ {M A} → Γ ⊢ M `: A → Δ ⊢ subst ρ M `: A)
For this to work, I need to know that neither `Δ` or any of the
bound variables in `ρ x` will collide with any bound variable in `M`.
How can I establish this?
In particular, I need to check that the conditions for ordinary
substitution are sufficient to establish the required invariants.
In that case we have:
⊢substitution : ∀ {Γ x A N B M} →
Γ , x `: A ⊢ N `: B →
Γ ⊢ M `: A →
--------------------
Γ ⊢ N [ x := M ] `: B
Here, since `N` is well-typed, none of it's bound variables collide
with `Γ`, and hence cannot collide with any free variable of `M`.
*But* we can't make a similar guarantee for the *bound* variables
of `M`, so substitution may break the invariants. Here are examples:
(`λ "x" `→ `λ "y" `→ ` "x") (`λ "y" `→ ` "y")
(`λ "y" → (`λ "y" `→ ` "y"))
ε , "z" `: ` ⊢ (`λ "x" `→ `λ "y" → ` "x" · ` "y" · ` "z") (`λ "y" `→ ` "y" · ` "z")
ε , "z" `: ` ⊢ (`λ "y" → (`λ "y" `→ ` "y" · ` "z") · ` "y" · ` "z")
This doesn't maintain the invariant, but doesn't break either.
But I don't know how to prove it never breaks. Maybe I can come
up with an example that does break after a few steps. Or, maybe
I don't need the nested variables to be unique. Maybe all I need
is for the free variables in each `ρ x` to be distinct from any
of the bound variables in `N`. But this requires every bound
variable in `N` to not appear in `Γ`. Not clear how to maintain
such a condition without the invariant, so I don't know how
the proof works. Bugger!
Consider a term with free variables, where every bound
variable of the term is distinct from any free variable.
(This is trivially true for a closed term.) Question: if
I never reduce under lambda, do I ever need
to perform renaming?
It's easy to come up with a counter-example if I allow
reduction under lambda.
(λ y → (λ x → λ y → x y) y) ⟶ (λ y → (λ y → y y))
The above requires renaming. But if I remove the outer lambda
(λ x → λ y → x y) y ⟶ (λ y → (λ y → y y))
then the term on the left violates the condition on free
variables, and any term I can think of that causes problems
also violates the condition. So I may be able to do something
here.
\begin{code}
{-
⊢rename : ∀ {Γ Δ xs}
→ (∀ {x A} → Γ ∋ x `: A → Δ ∋ x `: A)
--------------------------------------------------
→ (∀ {M A} → Γ ⊢ M `: A → Δ ⊢ M `: A)
⊢rename ⊢σ (Ax ⊢x) = Ax (⊢σ ⊢x)
⊢rename {Γ} {Δ} ⊢σ (⊢λ {x = x} {N = N} {A = A} x∉Γ ⊢N)
= ⊢λ x∉Δ (⊢rename {Γ′} {Δ′} ⊢σ′ ⊢N)
where
Γ′ = Γ , x `: A
Δ′ = Δ , x `: A
xs = x ∷ xs
⊢σ′ : ∀ {w B} → w ∈ xs → Γ′ ∋ w `: B → Δ′ ∋ w `: B
⊢σ′ w∈ Z = Z
⊢σ′ w∈ (S w≢ ⊢w) = S w≢ (⊢σ ∈w ⊢w)
where
∈w = there⁻¹ w∈ w≢
⊆xs : free N ⊆ xs
⊆xs = \\-to-∷ ⊆xs
⊢rename ⊢σ ⊆xs (⊢L · ⊢M) = ⊢rename ⊢σ L⊆ ⊢L · ⊢rename ⊢σ M⊆ ⊢M
where
L⊆ = trans-⊆ ⊆-++₁ ⊆xs
M⊆ = trans-⊆ ⊆-++₂ ⊆xs
⊢rename ⊢σ ⊆xs (⊢zero) = ⊢zero
⊢rename ⊢σ ⊆xs (⊢suc ⊢M) = ⊢suc (⊢rename ⊢σ ⊆xs ⊢M)
⊢rename ⊢σ ⊆xs (⊢pred ⊢M) = ⊢pred (⊢rename ⊢σ ⊆xs ⊢M)
⊢rename ⊢σ ⊆xs (⊢if0 {L = L} ⊢L ⊢M ⊢N)
= ⊢if0 (⊢rename ⊢σ L⊆ ⊢L) (⊢rename ⊢σ M⊆ ⊢M) (⊢rename ⊢σ N⊆ ⊢N)
where
L⊆ = trans-⊆ ⊆-++₁ ⊆xs
M⊆ = trans-⊆ ⊆-++₁ (trans-⊆ (⊆-++₂ {free L}) ⊆xs)
N⊆ = trans-⊆ ⊆-++₂ (trans-⊆ (⊆-++₂ {free L}) ⊆xs)
⊢rename ⊢σ ⊆xs (⊢Y ⊢M) = ⊢Y (⊢rename ⊢σ ⊆xs ⊢M)
-}
\end{code}
### Substitution preserves types
\begin{code}
{-
⊢subst : ∀ {Γ Δ xs ys ρ}
→ (∀ {x} → x ∈ xs → free (ρ x) ⊆ ys)
→ (∀ {x A} → x ∈ xs → Γ ∋ x `: A → Δ ⊢ ρ x `: A)
-------------------------------------------------------------
→ (∀ {M A} → free M ⊆ xs → Γ ⊢ M `: A → Δ ⊢ subst ys ρ M `: A)
⊢subst Σ ⊢ρ ⊆xs (Ax ⊢x)
= ⊢ρ (⊆xs here) ⊢x
⊢subst {Γ} {Δ} {xs} {ys} {ρ} Σ ⊢ρ ⊆xs (⊢λ {x = x} {N = N} {A = A} ⊢N)
= ⊢λ {x = y} {A = A} (⊢subst {Γ′} {Δ′} {xs} {ys} {ρ} Σ′ ⊢ρ′ ⊆xs ⊢N)
where
y = fresh ys
Γ′ = Γ , x `: A
Δ′ = Δ , y `: A
xs = x ∷ xs
ys = y ∷ ys
ρ = ρ , x ↦ ` y
Σ′ : ∀ {w} → w ∈ xs → free (ρ w) ⊆ ys
Σ′ {w} w∈ with w ≟ x
... | yes refl = ⊆-++₁
... | no w≢ = ⊆-++₂ ∘ Σ (there⁻¹ w∈ w≢)
⊆xs : free N ⊆ xs
⊆xs = \\-to-∷ ⊆xs
⊢σ : ∀ {w C} → w ∈ ys → Δ ∋ w `: C → Δ′ ∋ w `: C
⊢σ w∈ ⊢w = S (fresh-lemma w∈) ⊢w
⊢ρ′ : ∀ {w C} → w ∈ xs → Γ′ ∋ w `: C → Δ′ ⊢ ρ w `: C
⊢ρ′ {w} _ Z with w ≟ x
... | yes _ = Ax Z
... | no w≢ = ⊥-elim (w≢ refl)
⊢ρ′ {w} w∈ (S w≢ ⊢w) with w ≟ x
... | yes refl = ⊥-elim (w≢ refl)
... | no _ = ⊢rename {Δ} {Δ′} {ys} ⊢σ (Σ w∈) (⊢ρ w∈ ⊢w)
where
w∈ = there⁻¹ w∈ w≢
⊢subst Σ ⊢ρ ⊆xs (⊢L · ⊢M)
= ⊢subst Σ ⊢ρ L⊆ ⊢L · ⊢subst Σ ⊢ρ M⊆ ⊢M
where
L⊆ = trans-⊆ ⊆-++₁ ⊆xs
M⊆ = trans-⊆ ⊆-++₂ ⊆xs
⊢subst Σ ⊢ρ ⊆xs ⊢zero = ⊢zero
⊢subst Σ ⊢ρ ⊆xs (⊢suc ⊢M) = ⊢suc (⊢subst Σ ⊢ρ ⊆xs ⊢M)
⊢subst Σ ⊢ρ ⊆xs (⊢pred ⊢M) = ⊢pred (⊢subst Σ ⊢ρ ⊆xs ⊢M)
⊢subst Σ ⊢ρ ⊆xs (⊢if0 {L = L} ⊢L ⊢M ⊢N)
= ⊢if0 (⊢subst Σ ⊢ρ L⊆ ⊢L) (⊢subst Σ ⊢ρ M⊆ ⊢M) (⊢subst Σ ⊢ρ N⊆ ⊢N)
where
L⊆ = trans-⊆ ⊆-++₁ ⊆xs
M⊆ = trans-⊆ ⊆-++₁ (trans-⊆ (⊆-++₂ {free L}) ⊆xs)
N⊆ = trans-⊆ ⊆-++₂ (trans-⊆ (⊆-++₂ {free L}) ⊆xs)
⊢subst Σ ⊢ρ ⊆xs (⊢Y ⊢M) = ⊢Y (⊢subst Σ ⊢ρ ⊆xs ⊢M)
⊢substitution : ∀ {Γ x A N B M} →
Γ , x `: A ⊢ N `: B →
Γ ⊢ M `: A →
--------------------
Γ ⊢ N [ x := M ] `: B
⊢substitution {Γ} {x} {A} {N} {B} {M} ⊢N ⊢M =
⊢subst {Γ′} {Γ} {xs} {ys} {ρ} Σ ⊢ρ {N} {B} ⊆xs ⊢N
where
Γ′ = Γ , x `: A
xs = free N
ys = free M ++ (free N \\ x)
ρ = ∅ , x ↦ M
Σ : ∀ {w} → w ∈ xs → free (ρ w) ⊆ ys
Σ {w} w∈ y∈ with w ≟ x
... | yes _ = ⊆-++₁ y∈
... | no w≢ rewrite ∈-[_] y∈ = ⊆-++₂ (∈-≢-to-\\ w∈ w≢)
⊢ρ : ∀ {w B} → w ∈ xs → Γ′ ∋ w `: B → Γ ⊢ ρ w `: B
⊢ρ {w} w∈ Z with w ≟ x
... | yes _ = ⊢M
... | no w≢ = ⊥-elim (w≢ refl)
⊢ρ {w} w∈ (S w≢ ⊢w) with w ≟ x
... | yes refl = ⊥-elim (w≢ refl)
... | no _ = Ax ⊢w
⊆xs : free N ⊆ xs
⊆xs x∈ = x∈
-}
\end{code}
### Preservation
\begin{code}
{-
preservation : ∀ {Γ M N A}
→ Γ ⊢ M `: A
→ M ⟶ N
---------
→ Γ ⊢ N `: A
preservation (Ax ⊢x) ()
preservation (⊢λ ⊢N) ()
preservation (⊢L · ⊢M) (ξ-·₁ L⟶) = preservation ⊢L L⟶ · ⊢M
preservation (⊢V · ⊢M) (ξ-·₂ _ M⟶) = ⊢V · preservation ⊢M M⟶
preservation ((⊢λ ⊢N) · ⊢W) (β-`→ _) = ⊢substitution ⊢N ⊢W
preservation (⊢zero) ()
preservation (⊢suc ⊢M) (ξ-suc M⟶) = ⊢suc (preservation ⊢M M⟶)
preservation (⊢pred ⊢M) (ξ-pred M⟶) = ⊢pred (preservation ⊢M M⟶)
preservation (⊢pred ⊢zero) (β-pred-zero) = ⊢zero
preservation (⊢pred (⊢suc ⊢M)) (β-pred-suc _) = ⊢M
preservation (⊢if0 ⊢L ⊢M ⊢N) (ξ-if0 L⟶) = ⊢if0 (preservation ⊢L L⟶) ⊢M ⊢N
preservation (⊢if0 ⊢zero ⊢M ⊢N) β-if0-zero = ⊢M
preservation (⊢if0 (⊢suc ⊢V) ⊢M ⊢N) (β-if0-suc _) = ⊢N
preservation (⊢Y ⊢M) (ξ-Y M⟶) = ⊢Y (preservation ⊢M M⟶)
preservation (⊢Y (⊢λ ⊢N)) (β-Y _ refl) = ⊢substitution ⊢N (⊢Y (⊢λ ⊢N))
-}
\end{code}
## Normalise
\begin{code}
{-
data Normalise {M A} (⊢M : ε ⊢ M `: A) : Set where
out-of-gas : ∀ {N} → M ⟶* N → ε ⊢ N `: A → Normalise ⊢M
normal : ∀ {V} → → Canonical V A → M ⟶* V → Normalise ⊢M
normalise : ∀ {L A} → → (⊢L : ε ⊢ L `: A) → Normalise ⊢L
normalise {L} zero ⊢L = out-of-gas (L ∎) ⊢L
normalise {L} (suc m) ⊢L with progress ⊢L
... | done CL = normal (suc m) CL (L ∎)
... | step L⟶M with preservation ⊢L L⟶M
... | ⊢M with normalise m ⊢M
... | out-of-gas M⟶*N ⊢N = out-of-gas (L ⟶⟨ L⟶M ⟩ M⟶*N) ⊢N
... | normal n CV M⟶*V = normal n CV (L ⟶⟨ L⟶M ⟩ M⟶*V)
-}
\end{code}

View file

@ -1,843 +0,0 @@
---
title : "Typed: Raw terms with types (broken)"
layout : page
permalink : /Typed
---
This version uses raw terms. Substitution presumes that no
generation of fresh names is required.
The substitution algorithm is based on one by McBride.
It is given a map from names to terms. Say the mapping of a
name is trivial if it takes a name to a term consisting of
just the variable with that name. No fresh names are required
if the mapping on each variable is either trivial or to a
closed term. However, the proof of correctness currently
contains a hole, and may be difficult to repair.
## Imports
\begin{code}
module Typed where
\end{code}
\begin{code}
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong; cong₂; _≢_)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.List using (List; []; _∷_; _++_; map; foldr; filter)
open import Data.Nat using (; zero; suc; _+_)
open import Data.String using (String; _≟_)
open import Data.Product using (_×_; proj₁; proj₂) renaming (_,_ to ⟨_,_⟩)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Function using (_∘_)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Negation using (¬?)
import Collections
pattern [_] x = x ∷ []
pattern [_,_] x y = x ∷ y ∷ []
pattern [_,_,_] x y z = x ∷ y ∷ z ∷ []
\end{code}
## Syntax
\begin{code}
infix 4 _∋_`:_
infix 4 _⊢_`:_
infixl 5 _,_`:_
infixr 6 _`→_
infix 6 `λ_`→_
infixl 7 `if0_then_else_
infix 8 `suc_ `pred_ `Y_
infixl 9 _·_
Id : Set
Id = String
data Type : Set where
` : Type
_`→_ : Type → Type → Type
data Env : Set where
ε : Env
_,_`:_ : Env → Id → Type → Env
data Term : Set where
`_ : Id → Term
`λ_`→_ : Id → Term → Term
_·_ : Term → Term → Term
`zero : Term
`suc_ : Term → Term
`pred_ : Term → Term
`if0_then_else_ : Term → Term → Term → Term
`Y_ : Term → Term
data _∋_`:_ : Env → Id → Type → Set where
Z : ∀ {Γ A x}
--------------------
→ Γ , x `: A ∋ x `: A
S : ∀ {Γ A B x w}
→ w ≢ x
→ Γ ∋ w `: B
--------------------
→ Γ , x `: A ∋ w `: B
data _⊢_`:_ : Env → Term → Type → Set where
Ax : ∀ {Γ A x}
→ Γ ∋ x `: A
--------------
→ Γ ⊢ ` x `: A
⊢λ : ∀ {Γ x N A B}
→ Γ , x `: A ⊢ N `: B
--------------------------
→ Γ ⊢ (`λ x `→ N) `: A `→ B
_·_ : ∀ {Γ L M A B}
→ Γ ⊢ L `: A `→ B
→ Γ ⊢ M `: A
----------------
→ Γ ⊢ L · M `: B
⊢zero : ∀ {Γ}
----------------
→ Γ ⊢ `zero `: `
⊢suc : ∀ {Γ M}
→ Γ ⊢ M `: `
-----------------
→ Γ ⊢ `suc M `: `
⊢pred : ∀ {Γ M}
→ Γ ⊢ M `: `
------------------
→ Γ ⊢ `pred M `: `
⊢if0 : ∀ {Γ L M N A}
→ Γ ⊢ L `: `
→ Γ ⊢ M `: A
→ Γ ⊢ N `: A
------------------------------
→ Γ ⊢ `if0 L then M else N `: A
⊢Y : ∀ {Γ M A}
→ Γ ⊢ M `: A `→ A
----------------
→ Γ ⊢ `Y M `: A
\end{code}
## Test examples
\begin{code}
s≢z : "s" ≢ "z"
s≢z ()
n≢z : "n" ≢ "z"
n≢z ()
n≢s : "n" ≢ "s"
n≢s ()
m≢z : "m" ≢ "z"
m≢z ()
m≢s : "m" ≢ "s"
m≢s ()
m≢n : "m" ≢ "n"
m≢n ()
p≢n : "p" ≢ "n"
p≢n ()
p≢m : "p" ≢ "m"
p≢m ()
two : Term
two = `suc `suc `zero
⊢two : ε ⊢ two `: `
⊢two = ⊢suc (⊢suc ⊢zero)
plus : Term
plus = `Y (`λ "p" `→ `λ "m" `→ `λ "n" `→
`if0 ` "m" then ` "n" else `suc (` "p" · (`pred (` "m")) · ` "n"))
⊢plus : ε ⊢ plus `: ` `→ ` `→ `
⊢plus = (⊢Y (⊢λ (⊢λ (⊢λ (⊢if0 (Ax ⊢m) (Ax ⊢n) (⊢suc (Ax ⊢p · (⊢pred (Ax ⊢m)) · Ax ⊢n)))))))
where
⊢p = S p≢n (S p≢m Z)
⊢m = S m≢n Z
⊢n = Z
four : Term
four = plus · two · two
⊢four : ε ⊢ four `: `
⊢four = ⊢plus · ⊢two · ⊢two
Ch : Type
Ch = (` `→ `) `→ ` `→ `
twoCh : Term
twoCh = `λ "s" `→ `λ "z" `→ (` "s" · (` "s" · ` "z"))
⊢twoCh : ε ⊢ twoCh `: Ch
⊢twoCh = (⊢λ (⊢λ (Ax ⊢s · (Ax ⊢s · Ax ⊢z))))
where
⊢s = S s≢z Z
⊢z = Z
plusCh : Term
plusCh = `λ "m" `→ `λ "n" `→ `λ "s" `→ `λ "z" `→
` "m" · ` "s" · (` "n" · ` "s" · ` "z")
⊢plusCh : ε ⊢ plusCh `: Ch `→ Ch `→ Ch
⊢plusCh = (⊢λ (⊢λ (⊢λ (⊢λ (Ax ⊢m · Ax ⊢s · (Ax ⊢n · Ax ⊢s · Ax ⊢z))))))
where
⊢m = S m≢z (S m≢s (S m≢n Z))
⊢n = S n≢z (S n≢s Z)
⊢s = S s≢z Z
⊢z = Z
fromCh : Term
fromCh = `λ "m" `→ ` "m" · (`λ "s" `→ `suc ` "s") · `zero
⊢fromCh : ε ⊢ fromCh `: Ch `→ `
⊢fromCh = (⊢λ (Ax ⊢m · (⊢λ (⊢suc (Ax ⊢s))) · ⊢zero))
where
⊢m = Z
⊢s = Z
fourCh : Term
fourCh = fromCh · (plusCh · twoCh · twoCh)
⊢fourCh : ε ⊢ fourCh `: `
⊢fourCh = ⊢fromCh · (⊢plusCh · ⊢twoCh · ⊢twoCh)
\end{code}
## Erasure
\begin{code}
lookup : ∀ {Γ x A} → Γ ∋ x `: A → Id
lookup {Γ , x `: A} Z = x
lookup {Γ , x `: A} (S w≢ ⊢w) = lookup {Γ} ⊢w
erase : ∀ {Γ M A} → Γ ⊢ M `: A → Term
erase (Ax ⊢w) = ` lookup ⊢w
erase (⊢λ {x = x} ⊢N) = `λ x `→ erase ⊢N
erase (⊢L · ⊢M) = erase ⊢L · erase ⊢M
erase (⊢zero) = `zero
erase (⊢suc ⊢M) = `suc (erase ⊢M)
erase (⊢pred ⊢M) = `pred (erase ⊢M)
erase (⊢if0 ⊢L ⊢M ⊢N) = `if0 (erase ⊢L) then (erase ⊢M) else (erase ⊢N)
erase (⊢Y ⊢M) = `Y (erase ⊢M)
\end{code}
### Properties of erasure
\begin{code}
cong₃ : ∀ {A B C D : Set} (f : A → B → C → D) {s t u v x y} →
s ≡ t → u ≡ v → x ≡ y → f s u x ≡ f t v y
cong₃ f refl refl refl = refl
lookup-lemma : ∀ {Γ x A} → (⊢x : Γ ∋ x `: A) → lookup ⊢x ≡ x
lookup-lemma Z = refl
lookup-lemma (S w≢ ⊢w) = lookup-lemma ⊢w
erase-lemma : ∀ {Γ M A} → (⊢M : Γ ⊢ M `: A) → erase ⊢M ≡ M
erase-lemma (Ax ⊢x) = cong `_ (lookup-lemma ⊢x)
erase-lemma (⊢λ {x = x} ⊢N) = cong (`λ x `→_) (erase-lemma ⊢N)
erase-lemma (⊢L · ⊢M) = cong₂ _·_ (erase-lemma ⊢L) (erase-lemma ⊢M)
erase-lemma (⊢zero) = refl
erase-lemma (⊢suc ⊢M) = cong `suc_ (erase-lemma ⊢M)
erase-lemma (⊢pred ⊢M) = cong `pred_ (erase-lemma ⊢M)
erase-lemma (⊢if0 ⊢L ⊢M ⊢N) = cong₃ `if0_then_else_
(erase-lemma ⊢L) (erase-lemma ⊢M) (erase-lemma ⊢N)
erase-lemma (⊢Y ⊢M) = cong `Y_ (erase-lemma ⊢M)
\end{code}
## Substitution
### Lists as sets
\begin{code}
open Collections (Id) (_≟_)
\end{code}
### Free variables
\begin{code}
free : Term → List Id
free (` x) = [ x ]
free (`λ x `→ N) = free N \\ x
free (L · M) = free L ++ free M
free (`zero) = []
free (`suc M) = free M
free (`pred M) = free M
free (`if0 L then M else N) = free L ++ free M ++ free N
free (`Y M) = free M
\end{code}
### Identifier maps
\begin{code}
∅ : Id → Term
∅ x = ` x
infixl 5 _,_↦_
_,_↦_ : (Id → Term) → Id → Term → (Id → Term)
(ρ , x ↦ M) w with w ≟ x
... | yes _ = M
... | no _ = ρ w
\end{code}
### Substitution
\begin{code}
subst : (Id → Term) → Term → Term
subst ρ (` x) = ρ x
subst ρ (`λ x `→ N) = `λ x `→ subst (ρ , x ↦ ` x) N
subst ρ (L · M) = subst ρ L · subst ρ M
subst ρ (`zero) = `zero
subst ρ (`suc M) = `suc (subst ρ M)
subst ρ (`pred M) = `pred (subst ρ M)
subst ρ (`if0 L then M else N)
= `if0 (subst ρ L) then (subst ρ M) else (subst ρ N)
subst ρ (`Y M) = `Y (subst ρ M)
_[_:=_] : Term → Id → Term → Term
N [ x := M ] = subst (∅ , x ↦ M) N
\end{code}
### Testing substitution
\begin{code}
_ : (` "s" · ` "s" · ` "z") [ "z" := `zero ] ≡ (` "s" · ` "s" · `zero)
_ = refl
_ : (` "s" · ` "s" · ` "z") [ "s" := (`λ "m" `→ `suc ` "m") ] [ "z" := `zero ]
≡ (`λ "m" `→ `suc ` "m") · (`λ "m" `→ `suc ` "m") · `zero
_ = refl
_ : (`λ "m" `→ ` "m" · ` "n") [ "n" := ` "p" · ` "q" ]
≡ `λ "m" `→ ` "m" · (` "p" · ` "q")
_ = refl
_ : subst (∅ , "m" ↦ two , "n" ↦ four) (` "m" · ` "n") ≡ (two · four)
_ = refl
\end{code}
## Values
\begin{code}
data Value : Term → Set where
Zero :
----------
Value `zero
Suc : ∀ {V}
→ Value V
--------------
→ Value (`suc V)
Fun : ∀ {x N}
---------------
→ Value (`λ x `→ N)
\end{code}
## Reduction
\begin{code}
infix 4 _⟶_
data _⟶_ : Term → Term → Set where
ξ-·₁ : ∀ {L L M}
→ L ⟶ L
-----------------
→ L · M ⟶ L · M
ξ-·₂ : ∀ {V M M}
→ Value V
→ M ⟶ M
-----------------
→ V · M ⟶ V · M
β-→ : ∀ {x N V}
→ Value V
---------------------------------
→ (`λ x `→ N) · V ⟶ N [ x := V ]
ξ-suc : ∀ {M M}
→ M ⟶ M
-------------------
→ `suc M ⟶ `suc M
ξ-pred : ∀ {M M}
→ M ⟶ M
---------------------
→ `pred M ⟶ `pred M
β-pred-zero :
----------------------
`pred `zero ⟶ `zero
β-pred-suc : ∀ {V}
→ Value V
---------------------
→ `pred (`suc V) ⟶ V
ξ-if0 : ∀ {L L M N}
→ L ⟶ L
-----------------------------------------------
→ `if0 L then M else N ⟶ `if0 L then M else N
β-if0-zero : ∀ {M N}
-------------------------------
→ `if0 `zero then M else N ⟶ M
β-if0-suc : ∀ {V M N}
→ Value V
----------------------------------
→ `if0 (`suc V) then M else N ⟶ N
ξ-Y : ∀ {M M}
→ M ⟶ M
---------------
→ `Y M ⟶ `Y M
β-Y : ∀ {F x N}
→ F ≡ `λ x `→ N
-------------------------
→ `Y F ⟶ N [ x := `Y F ]
\end{code}
## Reflexive and transitive closure
\begin{code}
infix 2 _⟶*_
infix 1 begin_
infixr 2 _⟶⟨_⟩_
infix 3 _∎
data _⟶*_ : Term → Term → Set where
_∎ : ∀ (M : Term)
-------------
→ M ⟶* M
_⟶⟨_⟩_ : ∀ (L : Term) {M N}
→ L ⟶ M
→ M ⟶* N
---------
→ L ⟶* N
begin_ : ∀ {M N} → (M ⟶* N) → (M ⟶* N)
begin M⟶*N = M⟶*N
\end{code}
## Sample execution
\begin{code}
_ : plus · two · two ⟶* (`suc (`suc (`suc (`suc `zero))))
_ =
begin
plus · two · two
⟶⟨ ξ-·₁ (ξ-·₁ (β-Y refl)) ⟩
(`λ "m" `→ (`λ "n" `→ `if0 ` "m" then ` "n" else
`suc (plus · (`pred (` "m")) · (` "n")))) · two · two
⟶⟨ ξ-·₁ (β-→ (Suc (Suc Zero))) ⟩
(`λ "n" `→ `if0 two then ` "n" else
`suc (plus · (`pred two) · (` "n"))) · two
⟶⟨ β-→ (Suc (Suc Zero)) ⟩
`if0 two then two else
`suc (plus · (`pred two) · two)
⟶⟨ β-if0-suc (Suc Zero) ⟩
`suc (plus · (`pred two) · two)
⟶⟨ ξ-suc (ξ-·₁ (ξ-·₁ (β-Y refl))) ⟩
`suc ((`λ "m" `→ (`λ "n" `→ `if0 ` "m" then ` "n" else
`suc (plus · (`pred (` "m")) · (` "n")))) · (`pred two) · two)
⟶⟨ ξ-suc (ξ-·₁ (ξ-·₂ Fun (β-pred-suc (Suc Zero)))) ⟩
`suc ((`λ "m" `→ (`λ "n" `→ `if0 ` "m" then ` "n" else
`suc (plus · (`pred (` "m")) · (` "n")))) · (`suc `zero) · two)
⟶⟨ ξ-suc (ξ-·₁ (β-→ (Suc Zero))) ⟩
`suc ((`λ "n" `→ `if0 `suc `zero then ` "n" else
`suc (plus · (`pred (`suc `zero)) · (` "n")))) · two
⟶⟨ ξ-suc (β-→ (Suc (Suc Zero))) ⟩
`suc (`if0 `suc `zero then two else
`suc (plus · (`pred (`suc `zero)) · two))
⟶⟨ ξ-suc (β-if0-suc Zero) ⟩
`suc (`suc (plus · (`pred (`suc `zero)) · two))
⟶⟨ ξ-suc (ξ-suc (ξ-·₁ (ξ-·₁ (β-Y refl)))) ⟩
`suc (`suc ((`λ "m" `→ (`λ "n" `→ `if0 ` "m" then ` "n" else
`suc (plus · (`pred (` "m")) · (` "n")))) · (`pred (`suc `zero)) · two))
⟶⟨ ξ-suc (ξ-suc (ξ-·₁ (ξ-·₂ Fun (β-pred-suc Zero)))) ⟩
`suc (`suc ((`λ "m" `→ (`λ "n" `→ `if0 ` "m" then ` "n" else
`suc (plus · (`pred (` "m")) · (` "n")))) · `zero · two))
⟶⟨ ξ-suc (ξ-suc (ξ-·₁ (β-→ Zero))) ⟩
`suc (`suc ((`λ "n" `→ `if0 `zero then ` "n" else
`suc (plus · (`pred `zero) · (` "n"))) · two))
⟶⟨ ξ-suc (ξ-suc (β-→ (Suc (Suc Zero)))) ⟩
`suc (`suc (`if0 `zero then two else
`suc (plus · (`pred `zero) · two)))
⟶⟨ ξ-suc (ξ-suc β-if0-zero) ⟩
`suc (`suc (`suc (`suc `zero)))
\end{code}
## Values do not reduce
Values do not reduce.
\begin{code}
Val-⟶ : ∀ {M N} → Value M → ¬ (M ⟶ N)
Val-⟶ Fun ()
Val-⟶ Zero ()
Val-⟶ (Suc VM) (ξ-suc M⟶N) = Val-⟶ VM M⟶N
\end{code}
As a corollary, terms that reduce are not values.
\begin{code}
⟶-Val : ∀ {M N} → (M ⟶ N) → ¬ Value M
⟶-Val M⟶N VM = Val-⟶ VM M⟶N
\end{code}
## Reduction is deterministic
\begin{code}
det : ∀ {M M M″}
→ (M ⟶ M)
→ (M ⟶ M″)
----------
→ M ≡ M″
det (ξ-·₁ L⟶L) (ξ-·₁ L⟶L″) = cong₂ _·_ (det L⟶L L⟶L″) refl
det (ξ-·₁ L⟶L) (ξ-·₂ VL _) = ⊥-elim (Val-⟶ VL L⟶L)
det (ξ-·₁ L⟶L) (β-→ _) = ⊥-elim (Val-⟶ Fun L⟶L)
det (ξ-·₂ VL _) (ξ-·₁ L⟶L″) = ⊥-elim (Val-⟶ VL L⟶L″)
det (ξ-·₂ _ M⟶M) (ξ-·₂ _ M⟶M″) = cong₂ _·_ refl (det M⟶M M⟶M″)
det (ξ-·₂ _ M⟶M) (β-→ VM) = ⊥-elim (Val-⟶ VM M⟶M)
det (β-→ VM) (ξ-·₁ L⟶L″) = ⊥-elim (Val-⟶ Fun L⟶L″)
det (β-→ VM) (ξ-·₂ _ M⟶M″) = ⊥-elim (Val-⟶ VM M⟶M″)
det (β-→ _) (β-→ _) = refl
det (ξ-suc M⟶M) (ξ-suc M⟶M″) = cong `suc_ (det M⟶M M⟶M″)
det (ξ-pred M⟶M) (ξ-pred M⟶M″) = cong `pred_ (det M⟶M M⟶M″)
det (ξ-pred M⟶M) β-pred-zero = ⊥-elim (Val-⟶ Zero M⟶M)
det (ξ-pred M⟶M) (β-pred-suc VM) = ⊥-elim (Val-⟶ (Suc VM) M⟶M)
det β-pred-zero (ξ-pred M⟶M) = ⊥-elim (Val-⟶ Zero M⟶M)
det β-pred-zero β-pred-zero = refl
det (β-pred-suc VM) (ξ-pred M⟶M) = ⊥-elim (Val-⟶ (Suc VM) M⟶M)
det (β-pred-suc _) (β-pred-suc _) = refl
det (ξ-if0 L⟶L) (ξ-if0 L⟶L″) = cong₃ `if0_then_else_ (det L⟶L L⟶L″) refl refl
det (ξ-if0 L⟶L) β-if0-zero = ⊥-elim (Val-⟶ Zero L⟶L)
det (ξ-if0 L⟶L) (β-if0-suc VL) = ⊥-elim (Val-⟶ (Suc VL) L⟶L)
det β-if0-zero (ξ-if0 L⟶L″) = ⊥-elim (Val-⟶ Zero L⟶L″)
det β-if0-zero β-if0-zero = refl
det (β-if0-suc VL) (ξ-if0 L⟶L″) = ⊥-elim (Val-⟶ (Suc VL) L⟶L″)
det (β-if0-suc _) (β-if0-suc _) = refl
det (ξ-Y M⟶M) (ξ-Y M⟶M″) = cong `Y_ (det M⟶M M⟶M″)
det (ξ-Y M⟶M) (β-Y refl) = ⊥-elim (Val-⟶ Fun M⟶M)
det (β-Y refl) (ξ-Y M⟶M″) = ⊥-elim (Val-⟶ Fun M⟶M″)
det (β-Y refl) (β-Y refl) = refl
\end{code}
Almost half the lines in the above proof are redundant, for example
det (ξ-·₁ L⟶L) (ξ-·₂ VL _) = ⊥-elim (Val-⟶ VL L⟶L)
det (ξ-·₂ VL _) (ξ-·₁ L⟶L″) = ⊥-elim (Val-⟶ VL L⟶L″)
are essentially identical. What we might like to do is delete the
redundant lines and add
det M⟶M M⟶M″ = sym (det M⟶M″ M⟶M)
to the bottom of the proof. But this does not work. The termination
checker complains, because the arguments have merely switched order
and neither is smaller.
## Canonical forms
\begin{code}
data Canonical : Term → Type → Set where
Zero :
-------------------
Canonical `zero `
Suc : ∀ {V}
→ Canonical V `
----------------------
→ Canonical (`suc V) `
Fun : ∀ {x N A B}
→ ε , x `: A ⊢ N `: B
-------------------------------
→ Canonical (`λ x `→ N) (A `→ B)
\end{code}
## Canonical forms lemma
Every typed value is canonical.
\begin{code}
canonical : ∀ {V A}
→ ε ⊢ V `: A
→ Value V
-------------
→ Canonical V A
canonical ⊢zero Zero = Zero
canonical (⊢suc ⊢V) (Suc VV) = Suc (canonical ⊢V VV)
canonical (⊢λ ⊢N) Fun = Fun ⊢N
\end{code}
Every canonical form has a type and a value.
\begin{code}
type : ∀ {V A}
→ Canonical V A
--------------
→ ε ⊢ V `: A
type Zero = ⊢zero
type (Suc CV) = ⊢suc (type CV)
type (Fun {x = x} ⊢N) = ⊢λ ⊢N
value : ∀ {V A}
→ Canonical V A
-------------
→ Value V
value Zero = Zero
value (Suc CV) = Suc (value CV)
value (Fun ⊢N) = Fun
\end{code}
## Progress
\begin{code}
data Progress (M : Term) (A : Type) : Set where
step : ∀ {N}
→ M ⟶ N
----------
→ Progress M A
done :
Canonical M A
-------------
→ Progress M A
progress : ∀ {M A} → ε ⊢ M `: A → Progress M A
progress (Ax ())
progress (⊢λ ⊢N) = done (Fun ⊢N)
progress (⊢L · ⊢M) with progress ⊢L
... | step L⟶L = step (ξ-·₁ L⟶L)
... | done (Fun _) with progress ⊢M
... | step M⟶M = step (ξ-·₂ Fun M⟶M)
... | done CM = step (β-→ (value CM))
progress ⊢zero = done Zero
progress (⊢suc ⊢M) with progress ⊢M
... | step M⟶M = step (ξ-suc M⟶M)
... | done CM = done (Suc CM)
progress (⊢pred ⊢M) with progress ⊢M
... | step M⟶M = step (ξ-pred M⟶M)
... | done Zero = step β-pred-zero
... | done (Suc CM) = step (β-pred-suc (value CM))
progress (⊢if0 ⊢L ⊢M ⊢N) with progress ⊢L
... | step L⟶L = step (ξ-if0 L⟶L)
... | done Zero = step β-if0-zero
... | done (Suc CM) = step (β-if0-suc (value CM))
progress (⊢Y ⊢M) with progress ⊢M
... | step M⟶M = step (ξ-Y M⟶M)
... | done (Fun _) = step (β-Y refl)
\end{code}
## Preservation
### Domain of an environment
\begin{code}
{-
dom : Env → List Id
dom ε = []
dom (Γ , x `: A) = x ∷ dom Γ
dom-lemma : ∀ {Γ y B} → Γ ∋ y `: B → y ∈ dom Γ
dom-lemma Z = here
dom-lemma (S x≢y ⊢y) = there (dom-lemma ⊢y)
free-lemma : ∀ {Γ M A} → Γ ⊢ M `: A → free M ⊆ dom Γ
free-lemma (Ax ⊢x) w∈ with w∈
... | here = dom-lemma ⊢x
... | there ()
free-lemma {Γ} (⊢λ {N = N} ⊢N) = ∷-to-\\ (free-lemma ⊢N)
free-lemma (⊢L · ⊢M) w∈ with ++-to-⊎ w∈
... | inj₁ ∈L = free-lemma ⊢L ∈L
... | inj₂ ∈M = free-lemma ⊢M ∈M
free-lemma ⊢zero ()
free-lemma (⊢suc ⊢M) w∈ = free-lemma ⊢M w∈
free-lemma (⊢pred ⊢M) w∈ = free-lemma ⊢M w∈
free-lemma (⊢if0 ⊢L ⊢M ⊢N) w∈
with ++-to-⊎ w∈
... | inj₁ ∈L = free-lemma ⊢L ∈L
... | inj₂ ∈MN with ++-to-⊎ ∈MN
... | inj₁ ∈M = free-lemma ⊢M ∈M
... | inj₂ ∈N = free-lemma ⊢N ∈N
free-lemma (⊢Y ⊢M) w∈ = free-lemma ⊢M w∈
-}
\end{code}
### Renaming
\begin{code}
⊢rename : ∀ {Γ Δ}
→ (∀ {x A} → Γ ∋ x `: A → Δ ∋ x `: A)
--------------------------------------------------
→ (∀ {M A} → Γ ⊢ M `: A → Δ ⊢ M `: A)
⊢rename ⊢σ (Ax ⊢x) = Ax (⊢σ ⊢x)
⊢rename {Γ} {Δ} ⊢σ (⊢λ {x = x} {N = N} {A = A} ⊢N)
= ⊢λ (⊢rename {Γ′} {Δ′} ⊢σ′ ⊢N)
where
Γ′ = Γ , x `: A
Δ′ = Δ , x `: A
⊢σ′ : ∀ {w B} → Γ′ ∋ w `: B → Δ′ ∋ w `: B
⊢σ′ Z = Z
⊢σ′ (S w≢ ⊢w) = S w≢ (⊢σ ⊢w)
⊢rename ⊢σ (⊢L · ⊢M) = ⊢rename ⊢σ ⊢L · ⊢rename ⊢σ ⊢M
⊢rename ⊢σ (⊢zero) = ⊢zero
⊢rename ⊢σ (⊢suc ⊢M) = ⊢suc (⊢rename ⊢σ ⊢M)
⊢rename ⊢σ (⊢pred ⊢M) = ⊢pred (⊢rename ⊢σ ⊢M)
⊢rename ⊢σ (⊢if0 ⊢L ⊢M ⊢N)
= ⊢if0 (⊢rename ⊢σ ⊢L) (⊢rename ⊢σ ⊢M) (⊢rename ⊢σ ⊢N)
⊢rename ⊢σ (⊢Y ⊢M) = ⊢Y (⊢rename ⊢σ ⊢M)
\end{code}
### Substitution preserves types
\begin{code}
-- trivial : Set
-- trivial = ∀ ρ x → ρ x ≡ ` x ⊎ closed (ρ x)
⊢subst : ∀ {Γ Δ ρ}
-- → (∀ {x A} → Γ ∋ x `: A → trivial ρ x)
→ (∀ {x A} → Γ ∋ x `: A → Δ ⊢ ρ x `: A)
-------------------------------------------------
→ (∀ {M A} → Γ ⊢ M `: A → Δ ⊢ subst ρ M `: A)
⊢subst ⊢ρ (Ax ⊢x) = ⊢ρ ⊢x
⊢subst {Γ} {Δ} {ρ} ⊢ρ (⊢λ {x = x} {N = N} {A = A} ⊢N)
= ⊢λ {x = x} {A = A} (⊢subst {Γ′} {Δ′} {ρ} ⊢ρ′ ⊢N)
where
Γ′ = Γ , x `: A
Δ′ = Δ , x `: A
ρ = ρ , x ↦ ` x
⊢σ : ∀ {w C} → Δ ∋ w `: C → Δ′ ∋ w `: C
⊢σ ⊢w = S {!!} ⊢w
⊢ρ′ : ∀ {w C} → Γ′ ∋ w `: C → Δ′ ⊢ ρ w `: C
⊢ρ′ {w} Z with w ≟ x
... | yes _ = Ax Z
... | no w≢ = ⊥-elim (w≢ refl)
⊢ρ′ {w} (S w≢ ⊢w) with w ≟ x
... | yes refl = ⊥-elim (w≢ refl)
... | no _ = ⊢rename {Δ} {Δ′} ⊢σ (⊢ρ ⊢w)
⊢subst ⊢ρ (⊢L · ⊢M) = ⊢subst ⊢ρ ⊢L · ⊢subst ⊢ρ ⊢M
⊢subst ⊢ρ ⊢zero = ⊢zero
⊢subst ⊢ρ (⊢suc ⊢M) = ⊢suc (⊢subst ⊢ρ ⊢M)
⊢subst ⊢ρ (⊢pred ⊢M) = ⊢pred (⊢subst ⊢ρ ⊢M)
⊢subst ⊢ρ (⊢if0 ⊢L ⊢M ⊢N)
= ⊢if0 (⊢subst ⊢ρ ⊢L) (⊢subst ⊢ρ ⊢M) (⊢subst ⊢ρ ⊢N)
⊢subst ⊢ρ (⊢Y ⊢M) = ⊢Y (⊢subst ⊢ρ ⊢M)
\end{code}
Let's look at examples. Assume `M` is closed. Example 1.
subst (∅ , "x" ↦ M) (`λ "y" `→ ` "x") ≡ `λ "y" `→ M
Example 2.
subst (∅ , "y" ↦ N , "x" ↦ M) (`λ "y" `→ ` "x" · ` "y")
`λ "y" `→ subst (∅ , "y" ↦ ` N , "x" ↦ M , "y" ↦ ` "y") (` "x" · ` "y")
`λ "y" `→ (M · ` "y")
Before I wrote: "The hypotheses of the theorem appear to be violated. Drat!"
But let's assume that ``M `: A``, ``N `: B``, and the lambda bound `y` has type `C`.
Then ``Γ ∋ y `: B`` will not hold for the extended `ρ` because of interference
by the earlier `y`. So I'm not sure the hypothesis is violated.
\begin{code}
⊢substitution : ∀ {Γ x A N B M}
→ Γ , x `: A ⊢ N `: B
→ Γ ⊢ M `: A
----------------------
→ Γ ⊢ N [ x := M ] `: B
⊢substitution {Γ} {x} {A} {N} {B} {M} ⊢N ⊢M =
⊢subst {Γ′} {Γ} {ρ} ⊢ρ {N} {B} ⊢N
where
Γ′ = Γ , x `: A
ρ = ∅ , x ↦ M
⊢ρ : ∀ {w B} → Γ′ ∋ w `: B → Γ ⊢ ρ w `: B
⊢ρ {w} Z with w ≟ x
... | yes _ = ⊢M
... | no w≢ = ⊥-elim (w≢ refl)
⊢ρ {w} (S w≢ ⊢w) with w ≟ x
... | yes refl = ⊥-elim (w≢ refl)
... | no _ = Ax ⊢w
\end{code}
### Preservation
\begin{code}
preservation : ∀ {Γ M N A}
→ Γ ⊢ M `: A
→ M ⟶ N
---------
→ Γ ⊢ N `: A
preservation (Ax ⊢x) ()
preservation (⊢λ ⊢N) ()
preservation (⊢L · ⊢M) (ξ-·₁ L⟶) = preservation ⊢L L⟶ · ⊢M
preservation (⊢V · ⊢M) (ξ-·₂ _ M⟶) = ⊢V · preservation ⊢M M⟶
preservation ((⊢λ ⊢N) · ⊢W) (β-→ _) = ⊢substitution ⊢N ⊢W
preservation (⊢zero) ()
preservation (⊢suc ⊢M) (ξ-suc M⟶) = ⊢suc (preservation ⊢M M⟶)
preservation (⊢pred ⊢M) (ξ-pred M⟶) = ⊢pred (preservation ⊢M M⟶)
preservation (⊢pred ⊢zero) (β-pred-zero) = ⊢zero
preservation (⊢pred (⊢suc ⊢M)) (β-pred-suc _) = ⊢M
preservation (⊢if0 ⊢L ⊢M ⊢N) (ξ-if0 L⟶) = ⊢if0 (preservation ⊢L L⟶) ⊢M ⊢N
preservation (⊢if0 ⊢zero ⊢M ⊢N) β-if0-zero = ⊢M
preservation (⊢if0 (⊢suc ⊢V) ⊢M ⊢N) (β-if0-suc _) = ⊢N
preservation (⊢Y ⊢M) (ξ-Y M⟶) = ⊢Y (preservation ⊢M M⟶)
preservation (⊢Y (⊢λ ⊢N)) (β-Y refl) = ⊢substitution ⊢N (⊢Y (⊢λ ⊢N))
\end{code}
## Normalise
\begin{code}
data Normalise {M A} (⊢M : ε ⊢ M `: A) : Set where
out-of-gas : ∀ {N} → M ⟶* N → ε ⊢ N `: A → Normalise ⊢M
normal : ∀ {V} → → Canonical V A → M ⟶* V → Normalise ⊢M
normalise : ∀ {L A} → → (⊢L : ε ⊢ L `: A) → Normalise ⊢L
normalise {L} zero ⊢L = out-of-gas (L ∎) ⊢L
normalise {L} (suc m) ⊢L with progress ⊢L
... | done CL = normal (suc m) CL (L ∎)
... | step L⟶M with preservation ⊢L L⟶M
... | ⊢M with normalise m ⊢M
... | out-of-gas M⟶*N ⊢N = out-of-gas (L ⟶⟨ L⟶M ⟩ M⟶*N) ⊢N
... | normal n CV M⟶*V = normal n CV (L ⟶⟨ L⟶M ⟩ M⟶*V)
\end{code}

View file

@ -1,843 +0,0 @@
---
title : "Typed: Raw terms with types (broken)"
layout : page
permalink : /Typed
---
This version uses raw terms. Substitution presumes that no
generation of fresh names is required.
The substitution algorithm is based on one by McBride.
It is given a map from names to terms. Say the mapping of a
name is trivial if it takes a name to a term consisting of
just the variable with that name. No fresh names are required
if the mapping on each variable is either trivial or to a
closed term. However, the proof of correctness currently
contains a hole, and may be difficult to repair.
## Imports
\begin{code}
module Typed where
\end{code}
\begin{code}
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong; cong₂; _≢_)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.List using (List; []; _∷_; _++_; map; foldr; filter)
open import Data.Nat using (; zero; suc; _+_)
open import Data.String using (String; _≟_)
open import Data.Product using (_×_; proj₁; proj₂) renaming (_,_ to ⟨_,_⟩)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Function using (_∘_)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Negation using (¬?)
import fresh.Collections
pattern [_] x = x ∷ []
pattern [_,_] x y = x ∷ y ∷ []
pattern [_,_,_] x y z = x ∷ y ∷ z ∷ []
\end{code}
## Syntax
\begin{code}
infix 4 _∋_`:_
infix 4 _⊢_`:_
infixl 5 _,_`:_
infixr 6 _`→_
infix 6 `λ_`→_
infixl 7 `if0_then_else_
infix 8 `suc_ `pred_ `Y_
infixl 9 _·_
Id : Set
Id = String
data Type : Set where
` : Type
_`→_ : Type → Type → Type
data Env : Set where
ε : Env
_,_`:_ : Env → Id → Type → Env
data Term : Set where
`_ : Id → Term
`λ_`→_ : Id → Term → Term
_·_ : Term → Term → Term
`zero : Term
`suc_ : Term → Term
`pred_ : Term → Term
`if0_then_else_ : Term → Term → Term → Term
`Y_ : Term → Term
data _∋_`:_ : Env → Id → Type → Set where
Z : ∀ {Γ A x}
--------------------
→ Γ , x `: A ∋ x `: A
S : ∀ {Γ A B x w}
→ w ≢ x
→ Γ ∋ w `: B
--------------------
→ Γ , x `: A ∋ w `: B
data _⊢_`:_ : Env → Term → Type → Set where
Ax : ∀ {Γ A x}
→ Γ ∋ x `: A
--------------
→ Γ ⊢ ` x `: A
⊢λ : ∀ {Γ x N A B}
→ Γ , x `: A ⊢ N `: B
--------------------------
→ Γ ⊢ (`λ x `→ N) `: A `→ B
_·_ : ∀ {Γ L M A B}
→ Γ ⊢ L `: A `→ B
→ Γ ⊢ M `: A
----------------
→ Γ ⊢ L · M `: B
⊢zero : ∀ {Γ}
----------------
→ Γ ⊢ `zero `: `
⊢suc : ∀ {Γ M}
→ Γ ⊢ M `: `
-----------------
→ Γ ⊢ `suc M `: `
⊢pred : ∀ {Γ M}
→ Γ ⊢ M `: `
------------------
→ Γ ⊢ `pred M `: `
⊢if0 : ∀ {Γ L M N A}
→ Γ ⊢ L `: `
→ Γ ⊢ M `: A
→ Γ ⊢ N `: A
------------------------------
→ Γ ⊢ `if0 L then M else N `: A
⊢Y : ∀ {Γ M A}
→ Γ ⊢ M `: A `→ A
----------------
→ Γ ⊢ `Y M `: A
\end{code}
## Test examples
\begin{code}
s≢z : "s" ≢ "z"
s≢z ()
n≢z : "n" ≢ "z"
n≢z ()
n≢s : "n" ≢ "s"
n≢s ()
m≢z : "m" ≢ "z"
m≢z ()
m≢s : "m" ≢ "s"
m≢s ()
m≢n : "m" ≢ "n"
m≢n ()
p≢n : "p" ≢ "n"
p≢n ()
p≢m : "p" ≢ "m"
p≢m ()
two : Term
two = `suc `suc `zero
⊢two : ε ⊢ two `: `
⊢two = ⊢suc (⊢suc ⊢zero)
plus : Term
plus = `Y (`λ "p" `→ `λ "m" `→ `λ "n" `→
`if0 ` "m" then ` "n" else `suc (` "p" · (`pred (` "m")) · ` "n"))
⊢plus : ε ⊢ plus `: ` `→ ` `→ `
⊢plus = (⊢Y (⊢λ (⊢λ (⊢λ (⊢if0 (Ax ⊢m) (Ax ⊢n) (⊢suc (Ax ⊢p · (⊢pred (Ax ⊢m)) · Ax ⊢n)))))))
where
⊢p = S p≢n (S p≢m Z)
⊢m = S m≢n Z
⊢n = Z
four : Term
four = plus · two · two
⊢four : ε ⊢ four `: `
⊢four = ⊢plus · ⊢two · ⊢two
Ch : Type
Ch = (` `→ `) `→ ` `→ `
twoCh : Term
twoCh = `λ "s" `→ `λ "z" `→ (` "s" · (` "s" · ` "z"))
⊢twoCh : ε ⊢ twoCh `: Ch
⊢twoCh = (⊢λ (⊢λ (Ax ⊢s · (Ax ⊢s · Ax ⊢z))))
where
⊢s = S s≢z Z
⊢z = Z
plusCh : Term
plusCh = `λ "m" `→ `λ "n" `→ `λ "s" `→ `λ "z" `→
` "m" · ` "s" · (` "n" · ` "s" · ` "z")
⊢plusCh : ε ⊢ plusCh `: Ch `→ Ch `→ Ch
⊢plusCh = (⊢λ (⊢λ (⊢λ (⊢λ (Ax ⊢m · Ax ⊢s · (Ax ⊢n · Ax ⊢s · Ax ⊢z))))))
where
⊢m = S m≢z (S m≢s (S m≢n Z))
⊢n = S n≢z (S n≢s Z)
⊢s = S s≢z Z
⊢z = Z
fromCh : Term
fromCh = `λ "m" `→ ` "m" · (`λ "s" `→ `suc ` "s") · `zero
⊢fromCh : ε ⊢ fromCh `: Ch `→ `
⊢fromCh = (⊢λ (Ax ⊢m · (⊢λ (⊢suc (Ax ⊢s))) · ⊢zero))
where
⊢m = Z
⊢s = Z
fourCh : Term
fourCh = fromCh · (plusCh · twoCh · twoCh)
⊢fourCh : ε ⊢ fourCh `: `
⊢fourCh = ⊢fromCh · (⊢plusCh · ⊢twoCh · ⊢twoCh)
\end{code}
## Erasure
\begin{code}
lookup : ∀ {Γ x A} → Γ ∋ x `: A → Id
lookup {Γ , x `: A} Z = x
lookup {Γ , x `: A} (S w≢ ⊢w) = lookup {Γ} ⊢w
erase : ∀ {Γ M A} → Γ ⊢ M `: A → Term
erase (Ax ⊢w) = ` lookup ⊢w
erase (⊢λ {x = x} ⊢N) = `λ x `→ erase ⊢N
erase (⊢L · ⊢M) = erase ⊢L · erase ⊢M
erase (⊢zero) = `zero
erase (⊢suc ⊢M) = `suc (erase ⊢M)
erase (⊢pred ⊢M) = `pred (erase ⊢M)
erase (⊢if0 ⊢L ⊢M ⊢N) = `if0 (erase ⊢L) then (erase ⊢M) else (erase ⊢N)
erase (⊢Y ⊢M) = `Y (erase ⊢M)
\end{code}
### Properties of erasure
\begin{code}
cong₃ : ∀ {A B C D : Set} (f : A → B → C → D) {s t u v x y} →
s ≡ t → u ≡ v → x ≡ y → f s u x ≡ f t v y
cong₃ f refl refl refl = refl
lookup-lemma : ∀ {Γ x A} → (⊢x : Γ ∋ x `: A) → lookup ⊢x ≡ x
lookup-lemma Z = refl
lookup-lemma (S w≢ ⊢w) = lookup-lemma ⊢w
erase-lemma : ∀ {Γ M A} → (⊢M : Γ ⊢ M `: A) → erase ⊢M ≡ M
erase-lemma (Ax ⊢x) = cong `_ (lookup-lemma ⊢x)
erase-lemma (⊢λ {x = x} ⊢N) = cong (`λ x `→_) (erase-lemma ⊢N)
erase-lemma (⊢L · ⊢M) = cong₂ _·_ (erase-lemma ⊢L) (erase-lemma ⊢M)
erase-lemma (⊢zero) = refl
erase-lemma (⊢suc ⊢M) = cong `suc_ (erase-lemma ⊢M)
erase-lemma (⊢pred ⊢M) = cong `pred_ (erase-lemma ⊢M)
erase-lemma (⊢if0 ⊢L ⊢M ⊢N) = cong₃ `if0_then_else_
(erase-lemma ⊢L) (erase-lemma ⊢M) (erase-lemma ⊢N)
erase-lemma (⊢Y ⊢M) = cong `Y_ (erase-lemma ⊢M)
\end{code}
## Substitution
### Lists as sets
\begin{code}
open Collections (Id) (_≟_)
\end{code}
### Free variables
\begin{code}
free : Term → List Id
free (` x) = [ x ]
free (`λ x `→ N) = free N \\ x
free (L · M) = free L ++ free M
free (`zero) = []
free (`suc M) = free M
free (`pred M) = free M
free (`if0 L then M else N) = free L ++ free M ++ free N
free (`Y M) = free M
\end{code}
### Identifier maps
\begin{code}
∅ : Id → Term
∅ x = ` x
infixl 5 _,_↦_
_,_↦_ : (Id → Term) → Id → Term → (Id → Term)
(ρ , x ↦ M) w with w ≟ x
... | yes _ = M
... | no _ = ρ w
\end{code}
### Substitution
\begin{code}
subst : (Id → Term) → Term → Term
subst ρ (` x) = ρ x
subst ρ (`λ x `→ N) = `λ x `→ subst (ρ , x ↦ ` x) N
subst ρ (L · M) = subst ρ L · subst ρ M
subst ρ (`zero) = `zero
subst ρ (`suc M) = `suc (subst ρ M)
subst ρ (`pred M) = `pred (subst ρ M)
subst ρ (`if0 L then M else N)
= `if0 (subst ρ L) then (subst ρ M) else (subst ρ N)
subst ρ (`Y M) = `Y (subst ρ M)
_[_:=_] : Term → Id → Term → Term
N [ x := M ] = subst (∅ , x ↦ M) N
\end{code}
### Testing substitution
\begin{code}
_ : (` "s" · ` "s" · ` "z") [ "z" := `zero ] ≡ (` "s" · ` "s" · `zero)
_ = refl
_ : (` "s" · ` "s" · ` "z") [ "s" := (`λ "m" `→ `suc ` "m") ] [ "z" := `zero ]
≡ (`λ "m" `→ `suc ` "m") · (`λ "m" `→ `suc ` "m") · `zero
_ = refl
_ : (`λ "m" `→ ` "m" · ` "n") [ "n" := ` "p" · ` "q" ]
≡ `λ "m" `→ ` "m" · (` "p" · ` "q")
_ = refl
_ : subst (∅ , "m" ↦ two , "n" ↦ four) (` "m" · ` "n") ≡ (two · four)
_ = refl
\end{code}
## Values
\begin{code}
data Value : Term → Set where
Zero :
----------
Value `zero
Suc : ∀ {V}
→ Value V
--------------
→ Value (`suc V)
Fun : ∀ {x N}
---------------
→ Value (`λ x `→ N)
\end{code}
## Reduction
\begin{code}
infix 4 _⟶_
data _⟶_ : Term → Term → Set where
ξ-·₁ : ∀ {L L M}
→ L ⟶ L
-----------------
→ L · M ⟶ L · M
ξ-·₂ : ∀ {V M M}
→ Value V
→ M ⟶ M
-----------------
→ V · M ⟶ V · M
β-→ : ∀ {x N V}
→ Value V
---------------------------------
→ (`λ x `→ N) · V ⟶ N [ x := V ]
ξ-suc : ∀ {M M}
→ M ⟶ M
-------------------
→ `suc M ⟶ `suc M
ξ-pred : ∀ {M M}
→ M ⟶ M
---------------------
→ `pred M ⟶ `pred M
β-pred-zero :
----------------------
`pred `zero ⟶ `zero
β-pred-suc : ∀ {V}
→ Value V
---------------------
→ `pred (`suc V) ⟶ V
ξ-if0 : ∀ {L L M N}
→ L ⟶ L
-----------------------------------------------
→ `if0 L then M else N ⟶ `if0 L then M else N
β-if0-zero : ∀ {M N}
-------------------------------
→ `if0 `zero then M else N ⟶ M
β-if0-suc : ∀ {V M N}
→ Value V
----------------------------------
→ `if0 (`suc V) then M else N ⟶ N
ξ-Y : ∀ {M M}
→ M ⟶ M
---------------
→ `Y M ⟶ `Y M
β-Y : ∀ {F x N}
→ F ≡ `λ x `→ N
-------------------------
→ `Y F ⟶ N [ x := `Y F ]
\end{code}
## Reflexive and transitive closure
\begin{code}
infix 2 _⟶*_
infix 1 begin_
infixr 2 _⟶⟨_⟩_
infix 3 _∎
data _⟶*_ : Term → Term → Set where
_∎ : ∀ (M : Term)
-------------
→ M ⟶* M
_⟶⟨_⟩_ : ∀ (L : Term) {M N}
→ L ⟶ M
→ M ⟶* N
---------
→ L ⟶* N
begin_ : ∀ {M N} → (M ⟶* N) → (M ⟶* N)
begin M⟶*N = M⟶*N
\end{code}
## Sample execution
\begin{code}
_ : plus · two · two ⟶* (`suc (`suc (`suc (`suc `zero))))
_ =
begin
plus · two · two
⟶⟨ ξ-·₁ (ξ-·₁ (β-Y refl)) ⟩
(`λ "m" `→ (`λ "n" `→ `if0 ` "m" then ` "n" else
`suc (plus · (`pred (` "m")) · (` "n")))) · two · two
⟶⟨ ξ-·₁ (β-→ (Suc (Suc Zero))) ⟩
(`λ "n" `→ `if0 two then ` "n" else
`suc (plus · (`pred two) · (` "n"))) · two
⟶⟨ β-→ (Suc (Suc Zero)) ⟩
`if0 two then two else
`suc (plus · (`pred two) · two)
⟶⟨ β-if0-suc (Suc Zero) ⟩
`suc (plus · (`pred two) · two)
⟶⟨ ξ-suc (ξ-·₁ (ξ-·₁ (β-Y refl))) ⟩
`suc ((`λ "m" `→ (`λ "n" `→ `if0 ` "m" then ` "n" else
`suc (plus · (`pred (` "m")) · (` "n")))) · (`pred two) · two)
⟶⟨ ξ-suc (ξ-·₁ (ξ-·₂ Fun (β-pred-suc (Suc Zero)))) ⟩
`suc ((`λ "m" `→ (`λ "n" `→ `if0 ` "m" then ` "n" else
`suc (plus · (`pred (` "m")) · (` "n")))) · (`suc `zero) · two)
⟶⟨ ξ-suc (ξ-·₁ (β-→ (Suc Zero))) ⟩
`suc ((`λ "n" `→ `if0 `suc `zero then ` "n" else
`suc (plus · (`pred (`suc `zero)) · (` "n")))) · two
⟶⟨ ξ-suc (β-→ (Suc (Suc Zero))) ⟩
`suc (`if0 `suc `zero then two else
`suc (plus · (`pred (`suc `zero)) · two))
⟶⟨ ξ-suc (β-if0-suc Zero) ⟩
`suc (`suc (plus · (`pred (`suc `zero)) · two))
⟶⟨ ξ-suc (ξ-suc (ξ-·₁ (ξ-·₁ (β-Y refl)))) ⟩
`suc (`suc ((`λ "m" `→ (`λ "n" `→ `if0 ` "m" then ` "n" else
`suc (plus · (`pred (` "m")) · (` "n")))) · (`pred (`suc `zero)) · two))
⟶⟨ ξ-suc (ξ-suc (ξ-·₁ (ξ-·₂ Fun (β-pred-suc Zero)))) ⟩
`suc (`suc ((`λ "m" `→ (`λ "n" `→ `if0 ` "m" then ` "n" else
`suc (plus · (`pred (` "m")) · (` "n")))) · `zero · two))
⟶⟨ ξ-suc (ξ-suc (ξ-·₁ (β-→ Zero))) ⟩
`suc (`suc ((`λ "n" `→ `if0 `zero then ` "n" else
`suc (plus · (`pred `zero) · (` "n"))) · two))
⟶⟨ ξ-suc (ξ-suc (β-→ (Suc (Suc Zero)))) ⟩
`suc (`suc (`if0 `zero then two else
`suc (plus · (`pred `zero) · two)))
⟶⟨ ξ-suc (ξ-suc β-if0-zero) ⟩
`suc (`suc (`suc (`suc `zero)))
\end{code}
## Values do not reduce
Values do not reduce.
\begin{code}
Val-⟶ : ∀ {M N} → Value M → ¬ (M ⟶ N)
Val-⟶ Fun ()
Val-⟶ Zero ()
Val-⟶ (Suc VM) (ξ-suc M⟶N) = Val-⟶ VM M⟶N
\end{code}
As a corollary, terms that reduce are not values.
\begin{code}
⟶-Val : ∀ {M N} → (M ⟶ N) → ¬ Value M
⟶-Val M⟶N VM = Val-⟶ VM M⟶N
\end{code}
## Reduction is deterministic
\begin{code}
det : ∀ {M M M″}
→ (M ⟶ M)
→ (M ⟶ M″)
----------
→ M ≡ M″
det (ξ-·₁ L⟶L) (ξ-·₁ L⟶L″) = cong₂ _·_ (det L⟶L L⟶L″) refl
det (ξ-·₁ L⟶L) (ξ-·₂ VL _) = ⊥-elim (Val-⟶ VL L⟶L)
det (ξ-·₁ L⟶L) (β-→ _) = ⊥-elim (Val-⟶ Fun L⟶L)
det (ξ-·₂ VL _) (ξ-·₁ L⟶L″) = ⊥-elim (Val-⟶ VL L⟶L″)
det (ξ-·₂ _ M⟶M) (ξ-·₂ _ M⟶M″) = cong₂ _·_ refl (det M⟶M M⟶M″)
det (ξ-·₂ _ M⟶M) (β-→ VM) = ⊥-elim (Val-⟶ VM M⟶M)
det (β-→ VM) (ξ-·₁ L⟶L″) = ⊥-elim (Val-⟶ Fun L⟶L″)
det (β-→ VM) (ξ-·₂ _ M⟶M″) = ⊥-elim (Val-⟶ VM M⟶M″)
det (β-→ _) (β-→ _) = refl
det (ξ-suc M⟶M) (ξ-suc M⟶M″) = cong `suc_ (det M⟶M M⟶M″)
det (ξ-pred M⟶M) (ξ-pred M⟶M″) = cong `pred_ (det M⟶M M⟶M″)
det (ξ-pred M⟶M) β-pred-zero = ⊥-elim (Val-⟶ Zero M⟶M)
det (ξ-pred M⟶M) (β-pred-suc VM) = ⊥-elim (Val-⟶ (Suc VM) M⟶M)
det β-pred-zero (ξ-pred M⟶M) = ⊥-elim (Val-⟶ Zero M⟶M)
det β-pred-zero β-pred-zero = refl
det (β-pred-suc VM) (ξ-pred M⟶M) = ⊥-elim (Val-⟶ (Suc VM) M⟶M)
det (β-pred-suc _) (β-pred-suc _) = refl
det (ξ-if0 L⟶L) (ξ-if0 L⟶L″) = cong₃ `if0_then_else_ (det L⟶L L⟶L″) refl refl
det (ξ-if0 L⟶L) β-if0-zero = ⊥-elim (Val-⟶ Zero L⟶L)
det (ξ-if0 L⟶L) (β-if0-suc VL) = ⊥-elim (Val-⟶ (Suc VL) L⟶L)
det β-if0-zero (ξ-if0 L⟶L″) = ⊥-elim (Val-⟶ Zero L⟶L″)
det β-if0-zero β-if0-zero = refl
det (β-if0-suc VL) (ξ-if0 L⟶L″) = ⊥-elim (Val-⟶ (Suc VL) L⟶L″)
det (β-if0-suc _) (β-if0-suc _) = refl
det (ξ-Y M⟶M) (ξ-Y M⟶M″) = cong `Y_ (det M⟶M M⟶M″)
det (ξ-Y M⟶M) (β-Y refl) = ⊥-elim (Val-⟶ Fun M⟶M)
det (β-Y refl) (ξ-Y M⟶M″) = ⊥-elim (Val-⟶ Fun M⟶M″)
det (β-Y refl) (β-Y refl) = refl
\end{code}
Almost half the lines in the above proof are redundant, for example
det (ξ-·₁ L⟶L) (ξ-·₂ VL _) = ⊥-elim (Val-⟶ VL L⟶L)
det (ξ-·₂ VL _) (ξ-·₁ L⟶L″) = ⊥-elim (Val-⟶ VL L⟶L″)
are essentially identical. What we might like to do is delete the
redundant lines and add
det M⟶M M⟶M″ = sym (det M⟶M″ M⟶M)
to the bottom of the proof. But this does not work. The termination
checker complains, because the arguments have merely switched order
and neither is smaller.
## Canonical forms
\begin{code}
data Canonical : Term → Type → Set where
Zero :
-------------------
Canonical `zero `
Suc : ∀ {V}
→ Canonical V `
----------------------
→ Canonical (`suc V) `
Fun : ∀ {x N A B}
→ ε , x `: A ⊢ N `: B
-------------------------------
→ Canonical (`λ x `→ N) (A `→ B)
\end{code}
## Canonical forms lemma
Every typed value is canonical.
\begin{code}
canonical : ∀ {V A}
→ ε ⊢ V `: A
→ Value V
-------------
→ Canonical V A
canonical ⊢zero Zero = Zero
canonical (⊢suc ⊢V) (Suc VV) = Suc (canonical ⊢V VV)
canonical (⊢λ ⊢N) Fun = Fun ⊢N
\end{code}
Every canonical form has a type and a value.
\begin{code}
type : ∀ {V A}
→ Canonical V A
--------------
→ ε ⊢ V `: A
type Zero = ⊢zero
type (Suc CV) = ⊢suc (type CV)
type (Fun {x = x} ⊢N) = ⊢λ ⊢N
value : ∀ {V A}
→ Canonical V A
-------------
→ Value V
value Zero = Zero
value (Suc CV) = Suc (value CV)
value (Fun ⊢N) = Fun
\end{code}
## Progress
\begin{code}
data Progress (M : Term) (A : Type) : Set where
step : ∀ {N}
→ M ⟶ N
----------
→ Progress M A
done :
Canonical M A
-------------
→ Progress M A
progress : ∀ {M A} → ε ⊢ M `: A → Progress M A
progress (Ax ())
progress (⊢λ ⊢N) = done (Fun ⊢N)
progress (⊢L · ⊢M) with progress ⊢L
... | step L⟶L = step (ξ-·₁ L⟶L)
... | done (Fun _) with progress ⊢M
... | step M⟶M = step (ξ-·₂ Fun M⟶M)
... | done CM = step (β-→ (value CM))
progress ⊢zero = done Zero
progress (⊢suc ⊢M) with progress ⊢M
... | step M⟶M = step (ξ-suc M⟶M)
... | done CM = done (Suc CM)
progress (⊢pred ⊢M) with progress ⊢M
... | step M⟶M = step (ξ-pred M⟶M)
... | done Zero = step β-pred-zero
... | done (Suc CM) = step (β-pred-suc (value CM))
progress (⊢if0 ⊢L ⊢M ⊢N) with progress ⊢L
... | step L⟶L = step (ξ-if0 L⟶L)
... | done Zero = step β-if0-zero
... | done (Suc CM) = step (β-if0-suc (value CM))
progress (⊢Y ⊢M) with progress ⊢M
... | step M⟶M = step (ξ-Y M⟶M)
... | done (Fun _) = step (β-Y refl)
\end{code}
## Preservation
### Domain of an environment
\begin{code}
{-
dom : Env → List Id
dom ε = []
dom (Γ , x `: A) = x ∷ dom Γ
dom-lemma : ∀ {Γ y B} → Γ ∋ y `: B → y ∈ dom Γ
dom-lemma Z = here
dom-lemma (S x≢y ⊢y) = there (dom-lemma ⊢y)
free-lemma : ∀ {Γ M A} → Γ ⊢ M `: A → free M ⊆ dom Γ
free-lemma (Ax ⊢x) w∈ with w∈
... | here = dom-lemma ⊢x
... | there ()
free-lemma {Γ} (⊢λ {N = N} ⊢N) = ∷-to-\\ (free-lemma ⊢N)
free-lemma (⊢L · ⊢M) w∈ with ++-to-⊎ w∈
... | inj₁ ∈L = free-lemma ⊢L ∈L
... | inj₂ ∈M = free-lemma ⊢M ∈M
free-lemma ⊢zero ()
free-lemma (⊢suc ⊢M) w∈ = free-lemma ⊢M w∈
free-lemma (⊢pred ⊢M) w∈ = free-lemma ⊢M w∈
free-lemma (⊢if0 ⊢L ⊢M ⊢N) w∈
with ++-to-⊎ w∈
... | inj₁ ∈L = free-lemma ⊢L ∈L
... | inj₂ ∈MN with ++-to-⊎ ∈MN
... | inj₁ ∈M = free-lemma ⊢M ∈M
... | inj₂ ∈N = free-lemma ⊢N ∈N
free-lemma (⊢Y ⊢M) w∈ = free-lemma ⊢M w∈
-}
\end{code}
### Renaming
\begin{code}
⊢rename : ∀ {Γ Δ}
→ (∀ {x A} → Γ ∋ x `: A → Δ ∋ x `: A)
--------------------------------------------------
→ (∀ {M A} → Γ ⊢ M `: A → Δ ⊢ M `: A)
⊢rename ⊢σ (Ax ⊢x) = Ax (⊢σ ⊢x)
⊢rename {Γ} {Δ} ⊢σ (⊢λ {x = x} {N = N} {A = A} ⊢N)
= ⊢λ (⊢rename {Γ′} {Δ′} ⊢σ′ ⊢N)
where
Γ′ = Γ , x `: A
Δ′ = Δ , x `: A
⊢σ′ : ∀ {w B} → Γ′ ∋ w `: B → Δ′ ∋ w `: B
⊢σ′ Z = Z
⊢σ′ (S w≢ ⊢w) = S w≢ (⊢σ ⊢w)
⊢rename ⊢σ (⊢L · ⊢M) = ⊢rename ⊢σ ⊢L · ⊢rename ⊢σ ⊢M
⊢rename ⊢σ (⊢zero) = ⊢zero
⊢rename ⊢σ (⊢suc ⊢M) = ⊢suc (⊢rename ⊢σ ⊢M)
⊢rename ⊢σ (⊢pred ⊢M) = ⊢pred (⊢rename ⊢σ ⊢M)
⊢rename ⊢σ (⊢if0 ⊢L ⊢M ⊢N)
= ⊢if0 (⊢rename ⊢σ ⊢L) (⊢rename ⊢σ ⊢M) (⊢rename ⊢σ ⊢N)
⊢rename ⊢σ (⊢Y ⊢M) = ⊢Y (⊢rename ⊢σ ⊢M)
\end{code}
### Substitution preserves types
\begin{code}
-- trivial : Set
-- trivial = ∀ ρ x → ρ x ≡ ` x ⊎ closed (ρ x)
⊢subst : ∀ {Γ Δ ρ}
-- → (∀ {x A} → Γ ∋ x `: A → trivial ρ x)
→ (∀ {x A} → Γ ∋ x `: A → Δ ⊢ ρ x `: A)
-------------------------------------------------
→ (∀ {M A} → Γ ⊢ M `: A → Δ ⊢ subst ρ M `: A)
⊢subst ⊢ρ (Ax ⊢x) = ⊢ρ ⊢x
⊢subst {Γ} {Δ} {ρ} ⊢ρ (⊢λ {x = x} {N = N} {A = A} ⊢N)
= ⊢λ {x = x} {A = A} (⊢subst {Γ′} {Δ′} {ρ} ⊢ρ′ ⊢N)
where
Γ′ = Γ , x `: A
Δ′ = Δ , x `: A
ρ = ρ , x ↦ ` x
⊢σ : ∀ {w C} → Δ ∋ w `: C → Δ′ ∋ w `: C
⊢σ ⊢w = S {!!} ⊢w
⊢ρ′ : ∀ {w C} → Γ′ ∋ w `: C → Δ′ ⊢ ρ w `: C
⊢ρ′ {w} Z with w ≟ x
... | yes _ = Ax Z
... | no w≢ = ⊥-elim (w≢ refl)
⊢ρ′ {w} (S w≢ ⊢w) with w ≟ x
... | yes refl = ⊥-elim (w≢ refl)
... | no _ = ⊢rename {Δ} {Δ′} ⊢σ (⊢ρ ⊢w)
⊢subst ⊢ρ (⊢L · ⊢M) = ⊢subst ⊢ρ ⊢L · ⊢subst ⊢ρ ⊢M
⊢subst ⊢ρ ⊢zero = ⊢zero
⊢subst ⊢ρ (⊢suc ⊢M) = ⊢suc (⊢subst ⊢ρ ⊢M)
⊢subst ⊢ρ (⊢pred ⊢M) = ⊢pred (⊢subst ⊢ρ ⊢M)
⊢subst ⊢ρ (⊢if0 ⊢L ⊢M ⊢N)
= ⊢if0 (⊢subst ⊢ρ ⊢L) (⊢subst ⊢ρ ⊢M) (⊢subst ⊢ρ ⊢N)
⊢subst ⊢ρ (⊢Y ⊢M) = ⊢Y (⊢subst ⊢ρ ⊢M)
\end{code}
Let's look at examples. Assume `M` is closed. Example 1.
subst (∅ , "x" ↦ M) (`λ "y" `→ ` "x") ≡ `λ "y" `→ M
Example 2.
subst (∅ , "y" ↦ N , "x" ↦ M) (`λ "y" `→ ` "x" · ` "y")
`λ "y" `→ subst (∅ , "y" ↦ ` N , "x" ↦ M , "y" ↦ ` "y") (` "x" · ` "y")
`λ "y" `→ (M · ` "y")
Before I wrote: "The hypotheses of the theorem appear to be violated. Drat!"
But let's assume that ``M `: A``, ``N `: B``, and the lambda bound `y` has type `C`.
Then ``Γ ∋ y `: B`` will not hold for the extended `ρ` because of interference
by the earlier `y`. So I'm not sure the hypothesis is violated.
\begin{code}
⊢substitution : ∀ {Γ x A N B M}
→ Γ , x `: A ⊢ N `: B
→ Γ ⊢ M `: A
----------------------
→ Γ ⊢ N [ x := M ] `: B
⊢substitution {Γ} {x} {A} {N} {B} {M} ⊢N ⊢M =
⊢subst {Γ′} {Γ} {ρ} ⊢ρ {N} {B} ⊢N
where
Γ′ = Γ , x `: A
ρ = ∅ , x ↦ M
⊢ρ : ∀ {w B} → Γ′ ∋ w `: B → Γ ⊢ ρ w `: B
⊢ρ {w} Z with w ≟ x
... | yes _ = ⊢M
... | no w≢ = ⊥-elim (w≢ refl)
⊢ρ {w} (S w≢ ⊢w) with w ≟ x
... | yes refl = ⊥-elim (w≢ refl)
... | no _ = Ax ⊢w
\end{code}
### Preservation
\begin{code}
preservation : ∀ {Γ M N A}
→ Γ ⊢ M `: A
→ M ⟶ N
---------
→ Γ ⊢ N `: A
preservation (Ax ⊢x) ()
preservation (⊢λ ⊢N) ()
preservation (⊢L · ⊢M) (ξ-·₁ L⟶) = preservation ⊢L L⟶ · ⊢M
preservation (⊢V · ⊢M) (ξ-·₂ _ M⟶) = ⊢V · preservation ⊢M M⟶
preservation ((⊢λ ⊢N) · ⊢W) (β-→ _) = ⊢substitution ⊢N ⊢W
preservation (⊢zero) ()
preservation (⊢suc ⊢M) (ξ-suc M⟶) = ⊢suc (preservation ⊢M M⟶)
preservation (⊢pred ⊢M) (ξ-pred M⟶) = ⊢pred (preservation ⊢M M⟶)
preservation (⊢pred ⊢zero) (β-pred-zero) = ⊢zero
preservation (⊢pred (⊢suc ⊢M)) (β-pred-suc _) = ⊢M
preservation (⊢if0 ⊢L ⊢M ⊢N) (ξ-if0 L⟶) = ⊢if0 (preservation ⊢L L⟶) ⊢M ⊢N
preservation (⊢if0 ⊢zero ⊢M ⊢N) β-if0-zero = ⊢M
preservation (⊢if0 (⊢suc ⊢V) ⊢M ⊢N) (β-if0-suc _) = ⊢N
preservation (⊢Y ⊢M) (ξ-Y M⟶) = ⊢Y (preservation ⊢M M⟶)
preservation (⊢Y (⊢λ ⊢N)) (β-Y refl) = ⊢substitution ⊢N (⊢Y (⊢λ ⊢N))
\end{code}
## Normalise
\begin{code}
data Normalise {M A} (⊢M : ε ⊢ M `: A) : Set where
out-of-gas : ∀ {N} → M ⟶* N → ε ⊢ N `: A → Normalise ⊢M
normal : ∀ {V} → → Canonical V A → M ⟶* V → Normalise ⊢M
normalise : ∀ {L A} → → (⊢L : ε ⊢ L `: A) → Normalise ⊢L
normalise {L} zero ⊢L = out-of-gas (L ∎) ⊢L
normalise {L} (suc m) ⊢L with progress ⊢L
... | done CL = normal (suc m) CL (L ∎)
... | step L⟶M with preservation ⊢L L⟶M
... | ⊢M with normalise m ⊢M
... | out-of-gas M⟶*N ⊢N = out-of-gas (L ⟶⟨ L⟶M ⟩ M⟶*N) ⊢N
... | normal n CV M⟶*V = normal n CV (L ⟶⟨ L⟶M ⟩ M⟶*V)
\end{code}

View file

@ -1,408 +0,0 @@
---
title : "TypedDB: Typed DeBruijn representation"
layout : page
permalink : /TypedDB
---
## Imports
\begin{code}
module TypedDB where
\end{code}
\begin{code}
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.Nat using (; zero; suc; _+_; _∸_)
open import Data.Product using (_×_) renaming (_,_ to ⟨_,_⟩)
open import Data.Unit using (; tt)
open import Function using (_∘_)
open import Function.Equivalence using (_⇔_; equivalence)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Decidable using (map)
open import Relation.Nullary.Negation using (contraposition)
open import Relation.Nullary.Product using (_×-dec_)
\end{code}
## Syntax
\begin{code}
infixl 6 _,_
infix 4 _⊢_
infix 4 _∋_
infixr 5 _⇒_
infixl 5 _·_
infix 6 S_
infix 4 ƛ_
infix 4 μ_
data Type : Set where
` : Type
_⇒_ : Type → Type → Type
data Env : Set where
ε : Env
_,_ : Env → Type → Env
data _∋_ : Env → Type → Set where
Z : ∀ {Γ} {A}
----------
→ Γ , A ∋ A
S_ : ∀ {Γ} {A B}
→ Γ ∋ B
---------
→ Γ , A ∋ B
data _⊢_ : Env → Type → Set where
⌊_⌋ : ∀ {Γ} {A}
→ Γ ∋ A
------
→ Γ ⊢ A
ƛ_ : ∀ {Γ} {A B}
→ Γ , A ⊢ B
----------
→ Γ ⊢ A ⇒ B
_·_ : ∀ {Γ} {A B}
→ Γ ⊢ A ⇒ B
→ Γ ⊢ A
----------
→ Γ ⊢ B
`zero : ∀ {Γ}
----------
→ Γ ⊢ `
`suc : ∀ {Γ}
→ Γ ⊢ `
-------
→ Γ ⊢ `
`case : ∀ {Γ A}
→ Γ ⊢ `
→ Γ ⊢ A
→ Γ , ` ⊢ A
-----------
→ Γ ⊢ A
μ_ : ∀ {Γ A}
→ Γ , A ⊢ A
----------
→ Γ ⊢ A
\end{code}
Should modify the above to ensure that body of μ is a function.
## Test examples
\begin{code}
two : ∀ {Γ} → Γ ⊢ `
two = `suc (`suc `zero)
four : ∀ {Γ} → Γ ⊢ `
four = `suc (`suc (`suc (`suc `zero)))
plus : ∀ {Γ} → Γ ⊢ ` ⇒ ` ⇒ `
plus = μ ƛ ƛ `case ⌊ S Z ⌋ ⌊ Z ⌋ (`suc (⌊ S S S Z ⌋ · ⌊ Z ⌋ · ⌊ S Z ⌋))
Ch : Type → Type
Ch A = (A ⇒ A) ⇒ A ⇒ A
plusCh : ∀ {Γ A} → Γ ⊢ Ch A ⇒ Ch A ⇒ Ch A
plusCh = ƛ ƛ ƛ ƛ ⌊ S S S Z ⌋ · ⌊ S Z ⌋ · (⌊ S S Z ⌋ · ⌊ S Z ⌋ · ⌊ Z ⌋)
twoCh : ∀ {Γ A} → Γ ⊢ Ch A
twoCh = ƛ ƛ ⌊ S Z ⌋ · (⌊ S Z ⌋ · ⌊ Z ⌋)
fourCh : ∀ {Γ A} → Γ ⊢ Ch A
fourCh = ƛ ƛ ⌊ S Z ⌋ · (⌊ S Z ⌋ · (⌊ S Z ⌋ · (⌊ S Z ⌋ · ⌊ Z ⌋)))
fourCh : ∀ {Γ A} → Γ ⊢ Ch A
fourCh = plusCh · twoCh · twoCh
inc : ∀ {Γ} → Γ ⊢ ` ⇒ `
inc = ƛ `suc ⌊ Z ⌋
fromCh : ε ⊢ Ch ` ⇒ `
fromCh = ƛ ⌊ Z ⌋ · inc · `zero
\end{code}
## Operational semantics
Simultaneous substitution, a la McBride
## Renaming
\begin{code}
ext : ∀ {Γ Δ} → (∀ {A} → Γ ∋ A → Δ ∋ A) → (∀ {A B} → Γ , A ∋ B → Δ , A ∋ B)
ext σ Z = Z
ext σ (S x) = S (σ x)
rename : ∀ {Γ Δ} → (∀ {A} → Γ ∋ A → Δ ∋ A) → (∀ {A} → Γ ⊢ A → Δ ⊢ A)
rename σ (⌊ n ⌋) = ⌊ σ n ⌋
rename σ (ƛ N) = ƛ (rename (ext σ) N)
rename σ (L · M) = (rename σ L) · (rename σ M)
rename σ (`zero) = `zero
rename σ (`suc M) = `suc (rename σ M)
rename σ (`case L M N) = `case (rename σ L) (rename σ M) (rename (ext σ) N)
rename σ (μ N) = μ (rename (ext σ) N)
\end{code}
## Substitution
\begin{code}
exts : ∀ {Γ Δ} → (∀ {A} → Γ ∋ A → Δ ⊢ A) → (∀ {A B} → Γ , A ∋ B → Δ , A ⊢ B)
exts ρ Z = ⌊ Z ⌋
exts ρ (S x) = rename S_ (ρ x)
subst : ∀ {Γ Δ} → (∀ {C} → Γ ∋ C → Δ ⊢ C) → (∀ {C} → Γ ⊢ C → Δ ⊢ C)
subst ρ (⌊ k ⌋) = ρ k
subst ρ (ƛ N) = ƛ (subst (exts ρ) N)
subst ρ (L · M) = (subst ρ L) · (subst ρ M)
subst ρ (`zero) = `zero
subst ρ (`suc M) = `suc (subst ρ M)
subst ρ (`case L M N) = `case (subst ρ L) (subst ρ M) (subst (exts ρ) N)
subst ρ (μ N) = μ (subst (exts ρ) N)
_[_] : ∀ {Γ A B} → Γ , A ⊢ B → Γ ⊢ A → Γ ⊢ B
_[_] {Γ} {A} N M = subst {Γ , A} {Γ} ρ N
where
ρ : ∀ {B} → Γ , A ∋ B → Γ ⊢ B
ρ Z = M
ρ (S x) = ⌊ x ⌋
\end{code}
## Value
\begin{code}
data Value : ∀ {Γ A} → Γ ⊢ A → Set where
Zero : ∀ {Γ} →
-----------------
Value (`zero {Γ})
Suc : ∀ {Γ} {V : Γ ⊢ `}
→ Value V
--------------
→ Value (`suc V)
Fun : ∀ {Γ A B} {N : Γ , A ⊢ B}
---------------------------
→ Value (ƛ N)
\end{code}
Here `` `zero `` requires an implicit parameter to aid inference
(much in the same way that `[]` did in [Lists](Lists)).
## Reduction step
\begin{code}
infix 2 _⟶_
data _⟶_ : ∀ {Γ A} → (Γ ⊢ A) → (Γ ⊢ A) → Set where
ξ-⇒₁ : ∀ {Γ 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} {W : Γ ⊢ A}
→ Value W
---------------------
→ (ƛ N) · W ⟶ N [ W ]
ξ- : ∀ {Γ} {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
β-ℕ₁ : ∀ {Γ A} {M : Γ ⊢ A} {N : Γ , ` ⊢ A}
-----------------------
→ `case `zero M N ⟶ M
β-ℕ₂ : ∀ {Γ A} {V : Γ ⊢ `} {M : Γ ⊢ A} {N : Γ , ` ⊢ A}
→ Value V
--------------------------------
→ `case (`suc V) M N ⟶ N [ V ]
β-μ : ∀ {Γ A} {N : Γ , A ⊢ A}
------------------
→ μ N ⟶ N [ μ N ]
\end{code}
## Reflexive and transitive closure
\begin{code}
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 ⟶* N
begin_ : ∀ {Γ} {A} {M N : Γ ⊢ A} → (M ⟶* N) → (M ⟶* N)
begin M⟶*N = M⟶*N
\end{code}
## Example reduction sequences
\begin{code}
id : ∀ (A : Type) → ε ⊢ A ⇒ A
id A = ƛ ⌊ Z ⌋
_ : ∀ {A} → id (A ⇒ A) · id A ⟶* id A
_ =
begin
(ƛ ⌊ Z ⌋) · (ƛ ⌊ Z ⌋)
⟶⟨ β-⇒ Fun ⟩
ƛ ⌊ Z ⌋
_ : plus {ε} · two · two ⟶* four
_ =
plus · two · two
⟶⟨ ξ-⇒₁ (ξ-⇒₁ β-μ) ⟩
(ƛ ƛ `case ⌊ S Z ⌋ ⌊ Z ⌋ (`suc (plus · ⌊ Z ⌋ · ⌊ S Z ⌋))) · two · two
⟶⟨ ξ-⇒₁ (β-⇒ (Suc (Suc Zero))) ⟩
(ƛ `case two ⌊ Z ⌋ (`suc (plus · ⌊ Z ⌋ · ⌊ S Z ⌋))) · two
⟶⟨ β-⇒ (Suc (Suc Zero)) ⟩
`case two two (`suc (plus · ⌊ Z ⌋ · two))
⟶⟨ β-ℕ₂ (Suc Zero) ⟩
`suc (plus · `suc `zero · two)
⟶⟨ ξ- (ξ-⇒₁ (ξ-⇒₁ β-μ)) ⟩
`suc ((ƛ ƛ `case ⌊ S Z ⌋ ⌊ Z ⌋ (`suc (plus · ⌊ Z ⌋ · ⌊ S Z ⌋)))
· `suc `zero · two)
⟶⟨ ξ- (ξ-⇒₁ (β-⇒ (Suc Zero))) ⟩
`suc ((ƛ `case (`suc `zero) ⌊ Z ⌋ (`suc (plus · ⌊ Z ⌋ · ⌊ S Z ⌋))) · two)
⟶⟨ ξ- (β-⇒ (Suc (Suc Zero))) ⟩
`suc (`case (`suc `zero) (two) (`suc (plus · ⌊ Z ⌋ · two)))
⟶⟨ ξ- (β-ℕ₂ Zero) ⟩
`suc (`suc (plus · `zero · two))
⟶⟨ ξ- (ξ- (ξ-⇒₁ (ξ-⇒₁ β-μ))) ⟩
`suc (`suc ((ƛ ƛ `case ⌊ S Z ⌋ ⌊ Z ⌋ (`suc (plus · ⌊ Z ⌋ · ⌊ S Z ⌋)))
· `zero · two))
⟶⟨ ξ- (ξ- (ξ-⇒₁ (β-⇒ Zero))) ⟩
`suc (`suc ((ƛ `case `zero ⌊ Z ⌋ (`suc (plus · ⌊ Z ⌋ · ⌊ S Z ⌋))) · two))
⟶⟨ ξ- (ξ- (β-⇒ (Suc (Suc Zero)))) ⟩
`suc (`suc (`case `zero (two) (`suc (plus · ⌊ Z ⌋ · two))))
⟶⟨ ξ- (ξ- β-ℕ₁) ⟩
`suc (`suc (`suc (`suc `zero)))
_ : fromCh · (plusCh · twoCh · twoCh) ⟶* four
_ =
begin
fromCh · (plusCh · twoCh · twoCh)
⟶⟨ ξ-⇒₂ Fun (ξ-⇒₁ (β-⇒ Fun)) ⟩
fromCh · ((ƛ ƛ ƛ twoCh · ⌊ S Z ⌋ · (⌊ S (S Z) ⌋ · ⌊ S Z ⌋ · ⌊ Z ⌋)) · twoCh)
⟶⟨ ξ-⇒₂ Fun (β-⇒ Fun) ⟩
fromCh · (ƛ ƛ twoCh · ⌊ S Z ⌋ · (twoCh · ⌊ S Z ⌋ · ⌊ Z ⌋))
⟶⟨ β-⇒ Fun ⟩
(ƛ ƛ twoCh · ⌊ S Z ⌋ · (twoCh · ⌊ S Z ⌋ · ⌊ Z ⌋)) · inc · `zero
⟶⟨ ξ-⇒₁ (β-⇒ Fun) ⟩
(ƛ twoCh · inc · (twoCh · inc · ⌊ Z ⌋)) · `zero
⟶⟨ β-⇒ Zero ⟩
twoCh · inc · (twoCh · inc · `zero)
⟶⟨ ξ-⇒₁ (β-⇒ Fun) ⟩
(ƛ inc · (inc · ⌊ Z ⌋)) · (twoCh · inc · `zero)
⟶⟨ ξ-⇒₂ Fun (ξ-⇒₁ (β-⇒ Fun)) ⟩
(ƛ inc · (inc · ⌊ Z ⌋)) · ((ƛ inc · (inc · ⌊ Z ⌋)) · `zero)
⟶⟨ ξ-⇒₂ Fun (β-⇒ Zero) ⟩
(ƛ inc · (inc · ⌊ Z ⌋)) · (inc · (inc · `zero))
⟶⟨ ξ-⇒₂ Fun (ξ-⇒₂ Fun (β-⇒ Zero)) ⟩
(ƛ inc · (inc · ⌊ Z ⌋)) · (inc · `suc `zero)
⟶⟨ ξ-⇒₂ Fun (β-⇒ (Suc Zero)) ⟩
(ƛ inc · (inc · ⌊ Z ⌋)) · `suc (`suc `zero)
⟶⟨ β-⇒ (Suc (Suc Zero)) ⟩
inc · (inc · `suc (`suc `zero))
⟶⟨ ξ-⇒₂ Fun (β-⇒ (Suc (Suc Zero))) ⟩
inc · `suc (`suc (`suc `zero))
⟶⟨ β-⇒ (Suc (Suc (Suc Zero))) ⟩
`suc (`suc (`suc (`suc `zero)))
\end{code}
## Progress
\begin{code}
data Progress {A} (M : ε ⊢ A) : Set where
step : ∀ {N : ε ⊢ A}
→ M ⟶ N
-------------
→ Progress M
done :
Value M
----------
→ Progress M
progress : ∀ {A} → (M : ε ⊢ A) → Progress M
progress ⌊ () ⌋
progress (ƛ N) = done Fun
progress (L · M) with progress L
... | step L⟶L = step (ξ-⇒₁ L⟶L)
... | done Fun with progress M
... | step M⟶M = step (ξ-⇒₂ Fun M⟶M)
... | done VM = step (β-⇒ VM)
progress (`zero) = done Zero
progress (`suc M) with progress M
... | step M⟶M = step (ξ- M⟶M)
... | done VM = done (Suc VM)
progress (`case L M N) with progress L
... | step L⟶L = step (ξ-case L⟶L)
... | done Zero = step (β-ℕ₁)
... | done (Suc VL) = step (β-ℕ₂ VL)
progress (μ N) = step (β-μ)
\end{code}
## Normalise
\begin{code}
Gas : Set
Gas =
data Normalise {A} (M : ε ⊢ A) : Set where
normal : ∀ {N : ε ⊢ A}
→ Gas
→ M ⟶* N
-----------
→ Normalise M
normalise : ∀ {A} → → (L : ε ⊢ A) → Normalise L
normalise zero L = normal zero (L ∎)
normalise (suc g) L with progress L
... | done VL = normal (suc zero) (L ∎)
... | step {M} L⟶M with normalise g M
... | normal h M⟶*N = normal (suc h) (L ⟶⟨ L⟶M ⟩ M⟶*N)
\end{code}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,64 +0,0 @@
module _ where
-- Ulf's example of why removing abstract may
-- cause a proof that used to work to now fail
-- Agda mailing list, 16 May 2018
open import Agda.Builtin.Nat
open import Agda.Builtin.Bool
open import Agda.Builtin.Equality
module WithAbstract where
abstract
f : Nat Nat
f zero = zero
f (suc n) = suc (f n)
lem : n f n n
lem zero = refl
lem (suc n) rewrite lem n = refl
thm : m n f (suc m) + n suc (m + n)
thm m n rewrite lem (suc m) = refl
-- Works.
thm : m n f (suc m) + n suc (m + n)
thm m n = {!!}
{- Hole 0
Goal: f (suc m) + n suc (m + n)
————————————————————————————————————————————————————————————
n : Nat
m : Nat
-}
module WithoutAbstract where
f : Nat Nat
f zero = zero
f (suc n) = suc (f n)
lem : n f n n
lem zero = refl
lem (suc n) rewrite lem n = refl
thm : m n f (suc m) + n suc (m + n)
thm m n rewrite lem (suc m) = {! refl!}
-- Fails since rewrite doesn't trigger:
-- lem (suc m) : suc (f m) ≡ suc m
-- goal : suc (f m + n) ≡ suc (m + n)
-- NB: The problem is with the expansion of `f`,
-- not with the expansion of the lemma
thm : m n f (suc m) + n suc (m + n)
thm m n = {!!}
{- Holes 1 and 2
Goal: suc (f m + n) suc (m + n)
————————————————————————————————————————————————————————————
n : Nat
m : Nat
-}

View file

@ -1,334 +0,0 @@
---
title : "Untyped: Untyped lambda calculus with full normalisation"
layout : page
permalink : /Untyped
---
This chapter considers a system that varies, in interesting ways,
what has gone earlier. The lambda calculus in this section is
untyped rather than simply-typed; uses terms that are inherently-scoped
(as opposed to inherently-typed); reduces terms to full normal form
rather than weak head-normal form; and uses call-by-name rather than
call-by-value order of reduction.
*(((Need to update from call-by-value to call-by-name)))*
## Imports
\begin{code}
module Untyped where
\end{code}
\begin{code}
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.Nat using (; zero; suc; _+_; _∸_)
open import Data.Product using (_×_) renaming (_,_ to ⟨_,_⟩)
open import Data.Unit using (; tt)
open import Function using (_∘_)
open import Function.Equivalence using (_⇔_; equivalence)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Decidable using (map)
open import Relation.Nullary.Negation using (contraposition)
open import Relation.Nullary.Product using (_×-dec_)
\end{code}
## Syntax
\begin{code}
infix 6 ƛ_
infixl 7 _·_
data Var : → Set where
Z : ∀ {n}
-----------
→ Var (suc n)
S_ : ∀ {n}
→ Var n
-----------
→ Var (suc n)
data Term : → Set where
⌊_⌋ : ∀ {n}
→ Var n
------
→ Term n
ƛ_ : ∀ {n}
→ Term (suc n)
------------
→ Term n
_·_ : ∀ {n}
→ Term n
→ Term n
------
→ Term n
\end{code}
## Writing variables as numerals
\begin{code}
#_ : ∀ {n} → → Term n
#_ {n} m = ⌊ h n m ⌋
where
h : ∀ n → → Var n
h zero _ = ⊥-elim impossible
where postulate impossible : ⊥
h (suc n) 0 = Z
h (suc n) (suc m) = S (h n m)
\end{code}
## Test examples
\begin{code}
plus : ∀ {n} → Term n
plus = ƛ ƛ ƛ ƛ ⌊ S S S Z ⌋ · ⌊ S Z ⌋ · (⌊ S S Z ⌋ · ⌊ S Z ⌋ · ⌊ Z ⌋)
two : ∀ {n} → Term n
two = ƛ ƛ ⌊ S Z ⌋ · (⌊ S Z ⌋ · ⌊ Z ⌋)
four : ∀ {n} → Term n
four = ƛ ƛ ⌊ S Z ⌋ · (⌊ S Z ⌋ · (⌊ S Z ⌋ · (⌊ S Z ⌋ · ⌊ Z ⌋)))
\end{code}
## Renaming
\begin{code}
rename : ∀ {m n} → (Var m → Var n) → (Term m → Term n)
rename ρ ⌊ k ⌋ = ⌊ ρ k ⌋
rename {m} {n} ρ (ƛ N) = ƛ (rename {suc m} {suc n} ρ N)
where
ρ : Var (suc m) → Var (suc n)
ρ Z = Z
ρ (S k) = S (ρ k)
rename ρ (L · M) = (rename ρ L) · (rename ρ M)
\end{code}
## Substitution
\begin{code}
subst : ∀ {m n} → (Var m → Term n) → (Term m → Term n)
subst ρ ⌊ k ⌋ = ρ k
subst {m} {n} ρ (ƛ N) = ƛ (subst {suc m} {suc n} ρ N)
where
ρ : Var (suc m) → Term (suc n)
ρ Z = ⌊ Z ⌋
ρ (S k) = rename {n} {suc n} S_ (ρ k)
subst ρ (L · M) = (subst ρ L) · (subst ρ M)
substitute : ∀ {n} → Term (suc n) → Term n → Term n
substitute {n} N M = subst {suc n} {n} ρ N
where
ρ : Var (suc n) → Term n
ρ Z = M
ρ (S k) = ⌊ k ⌋
\end{code}
## Normal
\begin{code}
data Normal : ∀ {n} → Term n → Set
data Neutral : ∀ {n} → Term n → Set
data Normal where
ƛ_ : ∀ {n} {N : Term (suc n)} → Normal N → Normal (ƛ N)
⌈_⌉ : ∀ {n} {M : Term n} → Neutral M → Normal M
data Neutral where
⌊_⌋ : ∀ {n} → (k : Var n) → Neutral ⌊ k ⌋
_·_ : ∀ {n} → {L : Term n} {M : Term n} → Neutral L → Normal M → Neutral (L · M)
\end{code}
## Reduction step
\begin{code}
infix 2 _⟶_
data _⟶_ : ∀ {n} → Term n → Term n → Set where
ξ₁ : ∀ {n} {L L M : Term n}
→ L ⟶ L
-----------------
→ L · M ⟶ L · M
ξ₂ : ∀ {n} {V M M : Term n}
→ Normal V
→ M ⟶ M
----------------
→ V · M ⟶ V · M
ζ : ∀ {n} {N N : Term (suc n)}
→ N ⟶ N
-----------
→ ƛ N ⟶ ƛ N
β : ∀ {n} {N : Term (suc n)} {V : Term n}
→ Normal V
----------------------------
→ (ƛ N) · V ⟶ substitute N V
\end{code}
## Reflexive and transitive closure
\begin{code}
infix 2 _⟶*_
infix 1 begin_
infixr 2 _⟶⟨_⟩_
infix 3 _∎
data _⟶*_ : ∀ {n} → Term n → Term n → Set where
_∎ : ∀ {n} (M : Term n)
---------------------
→ M ⟶* M
_⟶⟨_⟩_ : ∀ {n} (L : Term n) {M N : Term n}
→ L ⟶ M
→ M ⟶* N
---------
→ L ⟶* N
begin_ : ∀ {n} {M N : Term n} → (M ⟶* N) → (M ⟶* N)
begin M⟶*N = M⟶*N
\end{code}
## Example reduction sequences
\begin{code}
id : Term zero
id = ƛ ⌊ Z ⌋
_ : id · id ⟶* id
_ =
begin
(ƛ ⌊ Z ⌋) · (ƛ ⌊ Z ⌋)
⟶⟨ β (ƛ ⌈ ⌊ Z ⌋ ⌉) ⟩
(ƛ ⌊ Z ⌋)
_ : plus {zero} · two · two ⟶* four
_ =
begin
plus · two · two
⟶⟨ ξ₁ (β (ƛ ƛ ⌈ ⌊ S Z ⌋ · ⌈ ⌊ S Z ⌋ · ⌈ ⌊ Z ⌋ ⌉ ⌉ ⌉)) ⟩
(ƛ ƛ ƛ two · ⌊ S Z ⌋ · (⌊ S (S Z) ⌋ · ⌊ S Z ⌋ · ⌊ Z ⌋)) · two
⟶⟨ ξ₁ (ζ (ζ (ζ (ξ₁ (β ⌈ ⌊ S Z ⌋ ⌉))))) ⟩
(ƛ ƛ ƛ (ƛ ⌊ S (S Z) ⌋ · (⌊ S (S Z) ⌋ · ⌊ Z ⌋)) ·
(⌊ S (S Z) ⌋ · ⌊ S Z ⌋ · ⌊ Z ⌋)) · two
⟶⟨ ξ₁ (ζ (ζ (ζ (β ⌈ (⌊ S (S Z) ⌋ · ⌈ ⌊ S Z ⌋ ⌉) · ⌈ ⌊ Z ⌋ ⌉ ⌉)))) ⟩
(ƛ ƛ ƛ ⌊ S Z ⌋ · (⌊ S Z ⌋ · (⌊ S (S Z) ⌋ · ⌊ S Z ⌋ · ⌊ Z ⌋))) · two
⟶⟨ β (ƛ (ƛ ⌈ ⌊ S Z ⌋ · ⌈ ⌊ S Z ⌋ · ⌈ ⌊ Z ⌋ ⌉ ⌉ ⌉)) ⟩
ƛ ƛ ⌊ S Z ⌋ · (⌊ S Z ⌋ · ((ƛ (ƛ ⌊ S Z ⌋ · (⌊ S Z ⌋ · ⌊ Z ⌋))) · ⌊ S Z ⌋ · ⌊ Z ⌋))
⟶⟨ ζ (ζ (ξ₂ ⌈ ⌊ S Z ⌋ ⌉ (ξ₂ ⌈ ⌊ S Z ⌋ ⌉ (ξ₁ (β ⌈ ⌊ S Z ⌋ ⌉))))) ⟩
ƛ ƛ ⌊ S Z ⌋ · (⌊ S Z ⌋ · ((ƛ ⌊ S (S Z) ⌋ · (⌊ S (S Z) ⌋ · ⌊ Z ⌋)) · ⌊ Z ⌋))
⟶⟨ ζ (ζ (ξ₂ ⌈ ⌊ S Z ⌋ ⌉ (ξ₂ ⌈ ⌊ S Z ⌋ ⌉ (β ⌈ ⌊ Z ⌋ ⌉)))) ⟩
ƛ ƛ ⌊ S Z ⌋ · (⌊ S Z ⌋ · (⌊ S Z ⌋ · (⌊ S Z ⌋ · ⌊ Z ⌋)))
\end{code}
## Progress
\begin{code}
data Progress {n} (M : Term n) : Set where
step : ∀ (N : Term n) → M ⟶ N → Progress M
done : Normal M → Progress M
progress : ∀ {n} → (M : Term n) → Progress M
progress ⌊ x ⌋ = done ⌈ ⌊ x ⌋ ⌉
progress (ƛ N) with progress N
progress (ƛ N) | step N r = step (ƛ N) (ζ r)
progress (ƛ V) | done NmV = done (ƛ NmV)
progress (L · M) with progress L
progress (L · M) | step L r = step (L · M) (ξ₁ r)
progress (V · M) | done NmV with progress M
progress (V · M) | done NmV | step M r = step (V · M) (ξ₂ NmV r)
progress (V · W) | done ⌈ NeV ⌉ | done NmW = done ⌈ NeV · NmW ⌉
progress ((ƛ V) · W) | done (ƛ NmV) | done NmW = step (substitute V W) (β NmW)
\end{code}
## Normalise
\begin{code}
Gas : Set
Gas =
data Normalise {n} (M : Term n) : Set where
out-of-gas : ∀ {N : Term n}
→ M ⟶* N
-------------
→ Normalise M
normal : ∀ {N : Term n}
→ Gas
→ M ⟶* N
→ Normal N
--------------
→ Normalise M
normalise : ∀ {n}
→ Gas
→ ∀ (M : Term n)
-------------
→ Normalise M
normalise zero L = out-of-gas (L ∎)
normalise (suc g) L with progress L
... | done VL = normal (suc g) (L ∎) VL
... | step M L⟶M with normalise g M
... | out-of-gas M⟶*N = out-of-gas (L ⟶⟨ L⟶M ⟩ M⟶*N)
... | normal h M⟶*N VN = normal h (L ⟶⟨ L⟶M ⟩ M⟶*N) VN
\end{code}
\begin{code}
_ : normalise 100 (plus {zero} · two · two) ≡
normal 94
((ƛ
(ƛ ⌊ S (S (S Z)) ⌋ · ⌊ S Z ⌋ · (⌊ S (S Z) ⌋ · ⌊ S Z ⌋ · ⌊ Z ⌋)))))
· (ƛ (ƛ ⌊ S Z ⌋ · (⌊ S Z ⌋ · ⌊ Z ⌋)))
· (ƛ (ƛ ⌊ S Z ⌋ · (⌊ S Z ⌋ · ⌊ Z ⌋)))
⟶⟨ ξ₁ (β (ƛ (ƛ ⌈ ⌊ S Z ⌋ · ⌈ ⌊ S Z ⌋ · ⌈ ⌊ Z ⌋ ⌉ ⌉ ⌉))) ⟩
(ƛ (ƛ ⌊ S Z ⌋ · (⌊ S Z ⌋ · ⌊ Z ⌋))) · ⌊ S Z ⌋ ·
(⌊ S (S Z) ⌋ · ⌊ S Z ⌋ · ⌊ Z ⌋))))
· (ƛ (ƛ ⌊ S Z ⌋ · (⌊ S Z ⌋ · ⌊ Z ⌋)))
⟶⟨ ξ₁ (ζ (ζ (ζ (ξ₁ (β ⌈ ⌊ S Z ⌋ ⌉))))) ⟩
(ƛ ⌊ S (S Z) ⌋ · (⌊ S (S Z) ⌋ · ⌊ Z ⌋)) ·
(⌊ S (S Z) ⌋ · ⌊ S Z ⌋ · ⌊ Z ⌋))))
· (ƛ (ƛ ⌊ S Z ⌋ · (⌊ S Z ⌋ · ⌊ Z ⌋)))
⟶⟨ ξ₁ (ζ (ζ (ζ (β ⌈ ⌊ S (S Z) ⌋ · ⌈ ⌊ S Z ⌋ ⌉ · ⌈ ⌊ Z ⌋ ⌉ ⌉)))) ⟩
(ƛ (ƛ (ƛ ⌊ S Z ⌋ · (⌊ S Z ⌋ · (⌊ S (S Z) ⌋ · ⌊ S Z ⌋ · ⌊ Z ⌋))))) ·
(ƛ (ƛ ⌊ S Z ⌋ · (⌊ S Z ⌋ · ⌊ Z ⌋)))
⟶⟨ β (ƛ (ƛ ⌈ ⌊ S Z ⌋ · ⌈ ⌊ S Z ⌋ · ⌈ ⌊ Z ⌋ ⌉ ⌉ ⌉)) ⟩
ƛ
⌊ S Z ⌋ ·
(⌊ S Z ⌋ ·
((ƛ (ƛ ⌊ S Z ⌋ · (⌊ S Z ⌋ · ⌊ Z ⌋))) · ⌊ S Z ⌋ · ⌊ Z ⌋)))
⟶⟨ ζ (ζ (ξ₂ ⌈ ⌊ S Z ⌋ ⌉ (ξ₂ ⌈ ⌊ S Z ⌋ ⌉ (ξ₁ (β ⌈ ⌊ S Z ⌋ ⌉))))) ⟩
ƛ
⌊ S Z ⌋ ·
(⌊ S Z ⌋ · ((ƛ ⌊ S (S Z) ⌋ · (⌊ S (S Z) ⌋ · ⌊ Z ⌋)) · ⌊ Z ⌋)))
⟶⟨ ζ (ζ (ξ₂ ⌈ ⌊ S Z ⌋ ⌉ (ξ₂ ⌈ ⌊ S Z ⌋ ⌉ (β ⌈ ⌊ Z ⌋ ⌉)))) ⟩
ƛ (ƛ ⌊ S Z ⌋ · (⌊ S Z ⌋ · (⌊ S Z ⌋ · (⌊ S Z ⌋ · ⌊ Z ⌋)))) ∎)
⌈ ⌊ S Z ⌋ · ⌈ ⌊ S Z ⌋ · ⌈ ⌊ S Z ⌋ · ⌈ ⌊ S Z ⌋ · ⌈ ⌊ Z ⌋ ⌉ ⌉ ⌉ ⌉ ⌉))
_ = refl
\end{code}

View file

@ -1,17 +0,0 @@
\begin{code}
open import Data.Nat (; zero; suc)
data Env : Set where
ε : Env
_,* : Env → Env
data _∋* : Env → Set where
Z : ∀ {Γ : Env} → Var (Γ ,*)
S : ∀ {Γ : Env} → Var Γ → Var (Γ ,*)
data _⊢* : Env → Set where
var : ∀ {Γ : Env} → Var Γ → Tm Γ
ƛ : Var (Γ ,*) → Var Γ
_·_ : Var Γ → Var Γ → Var Γ
\end{code}

View file

@ -1,142 +0,0 @@
Outline of
Programming Languages Theory in Agda (PLTA)
[can I think of a wadlerian name?]
Naturals
definition of naturals and why it makes sense
Nat; zero; suc
Recursion
recursive definitions and why they make sense
_+_; _*_; _∸_
Exercises
_^_; _⊔_; _⊓_
Induction
proof by induction and its relation to recursion
+-assoc; +-suc; +-identity; +-comm
*-distributes-+
classifying operations
associative; identity; commutative; distributive; idempotent
monoid; Abelian monoid; ring
Exercises
*-assoc; *-comm; ∸-+-assoc
^-distributes-*; +-distributes-⊔; +-distributes-⊓
counterexamples to show that _^_ is not associative or commutative
Relations
specifying relations by an inductive datatype
classifying relations
reflexive; symmetric; antisymmetric; transitive; total
preorder; partial order; total order
[do I also want irreflexive (requires negation)?]
[should I include a bit of lattice theory?]
proof by induction over evidence
≤-refl; ≤-trans; ≤-antisym; ≤-total
[define ≤-total using ⊎ or a custom datatype? Probably custom is better]
decidable relations
total order corresponds to a decidable relation
Lists
definition
data List : Set → Set where
[] : ∀ {A : Set} → List A
_::_ : ∀ {A : Set} → A → List A → List A
equivalent way to write:
data List (A : Set) : Set where
[] : List A
_::_ : A → List A → List A
length
append _++_
infixr 5 _++_
++-monoid
and or any all sum product
reverse
reverse and append
double reverse
fast and slow reverse and their equivalence
exercise : length xs ≡ length (reverse xs)
function composition
map
composition of two maps
foldr
composition of foldr with map
foldl
relation of foldr, foldl, and reverse
lexicographic order
define using a nested module
data Lex {a ℓ₁ ℓ₂} {A : Set a} (P : Set)
(_≈_ : Rel A ℓ₁) (_≺_ : Rel A ℓ₂) : Rel (List A) (ℓ₁ ⊔ ℓ₂) where
base : P → Lex P _≈_ _≺_ [] []
halt : ∀ {y ys} → Lex P _≈_ _≺_ [] (y ∷ ys)
this : ∀ {x xs y ys} (x≺y : x ≺ y) → Lex P _≈_ _≺_ (x ∷ xs) (y ∷ ys)
next : ∀ {x xs y ys} (x≈y : x ≈ y)
(xs<ys : Lex P _≈_ _≺_ xs ys) → Lex P _≈_ _≺_ (x ∷ xs) (y ∷ ys)
Logic
isomorphism
use two different definitions of ≤ as an example
projection
will get an example later, with ⊎-distributes-×
conjunction and top
×-assoc; ×-comm; ×-ident (as isomorphisms)
disjunction and bottom
⊥-elim
⊎-assoc; ⊎-comm; ⊎-ident (as isomorphisms)
distributive laws
×-distributes-⊎ (as isomorphism)
[The proof is straightforward but lengthy. Is there a way to shorten it?]
⊎-distributes-× (as projection)
implication
reflexive and transitive
negation
contrapositive: (A → B) → (¬ B → ¬ A)
double negation introduction: A → ¬ ¬ A
triple negation elimination: ¬ ¬ ¬ A → ¬ A
excluded middle irrefutable: ¬ ¬ (A ⊎ ¬ A)
for all
there exists
example: even n → ∃(λ m → n = 2 * m)
exercise: odd n → ∃(λ m → n = 2 * m + 1)
example:
∀ (A : Set) (B : A → Set) →
(∀ (x : A) → B x) → ¬ ∃ (λ (x : A) → ¬ B x)
exercise:
∀ (A : Set) (B : A → Set) →
∃ (λ (x : A) → B x) → ¬ (∀ (x : A) → ¬ B x)
intuitionistic and classical logic
following are all equivalent
excluded middle: A ⊎ ¬ A
double negation elimination: ¬ ¬ A → A
Peirce's law: ∀ (A B : Set) → ((A → B) → A) → A
de Morgan's law: ¬ (¬ A × ¬ B) → A ⊎ B
implication implies disjunction: (A → B) → ¬ A ⊎ B
show classical implies
∀ (A : Set) (B : A → Set) →
¬ (∃(λ (x : A) → ¬ B x) → ∀ (x : A) → B x
∀ (A : Set) (B : A → Set) →
¬ (∀ (x : A) → ¬ B x) → ∃(λ (x : A) → B x)
[demonstrate Kolmogorov's or Gödel's embedding]
equivalence
how it is defined
biimplication with Leibniz equality
Equivalence [not sure where this goes]
how it is defined
library for reasoning about it
Lambda notation [don't know where to put this]
[Best if it comes *before* existentials]
Currying [don't know where to put this]
Structures [not sure where this goes]
[distribute as they are introduced, or centralise in one chapter?]
mathematical structures as records
equivalence
monoid; Abelian monoid; ring
preorder; partial order; total order
lattice
isomorphism; projection;
relation inclusion; biinclusion
other properties of relations
irreflexive
complement of a relation

View file

@ -1,176 +0,0 @@
---
title : "Collections: Representing collections as lists"
layout : page
permalink : /Collections
---
This chapter presents operations on collections and a number of
useful operations on them.
## Imports
\begin{code}
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; _≢_; refl; sym; trans; cong)
open Eq.≡-Reasoning
open import Data.Nat using (; zero; suc; _+_; _*_; _∸_; _≤_; s≤s; z≤n)
-- open import Data.Nat.Properties using
-- (+-assoc; +-identityˡ; +-identityʳ; *-assoc; *-identityˡ; *-identityʳ)
open import Relation.Nullary using (¬_)
open import Data.Product using (_×_; proj₁; proj₂) renaming (_,_ to ⟨_,_⟩)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Data.Empty using (⊥; ⊥-elim)
open import Function using (_∘_)
open import Level using (Level)
open import Data.List using (List; []; _∷_; [_]; _++_; map; foldr; filter)
open import Data.List.All using (All; []; _∷_)
open import Data.List.Any using (Any; here; there)
open import Data.Maybe using (Maybe; just; nothing)
-- open import Data.List.Any.Membership.Propositional using (_∈_)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Negation using (contraposition; ¬?)
open import Relation.Nullary.Product using (_×-dec_)
-- open import Relation.Binary using (IsEquivalence)
\end{code}
## Collections
\begin{code}
module fresh.Collections (A : Set) (_≟_ : ∀ (x y : A) → Dec (x ≡ y)) where
Coll : Set → Set
Coll A = List A
infix 4 _∈_
infix 4 _⊆_
infixl 5 _\\_
data _∈_ : A → List A → Set where
here : ∀ {x xs} →
----------
x ∈ x ∷ xs
there : ∀ {w x xs} →
w ∈ xs →
----------
w ∈ x ∷ xs
_∉_ : A → List A → Set
x ∉ xs = ¬ (x ∈ xs)
_⊆_ : List A → List A → Set
xs ⊆ ys = ∀ {w} → w ∈ xs → w ∈ ys
_\\_ : List A → A → List A
xs \\ x = filter (¬? ∘ (_≟ x)) xs
refl-⊆ : ∀ {xs} → xs ⊆ xs
refl-⊆ ∈xs = ∈xs
trans-⊆ : ∀ {xs ys zs} → xs ⊆ ys → ys ⊆ zs → xs ⊆ zs
trans-⊆ xs⊆ ys⊆ = ys⊆ ∘ xs⊆
∈-[_] : ∀ {w x} → w ∈ [ x ] → w ≡ x
∈-[_] here = refl
∈-[_] (there ())
there⁻¹ : ∀ {w x xs} → w ∈ x ∷ xs → w ≢ x → w ∈ xs
there⁻¹ here w≢ = ⊥-elim (w≢ refl)
there⁻¹ (there w∈) w≢ = w∈
there⟨_⟩ : ∀ {w x y xs} → w ∈ xs × w ≢ x → w ∈ y ∷ xs × w ≢ x
there⟨ ⟨ w∈ , w≢ ⟩ ⟩ = ⟨ there w∈ , w≢ ⟩
\\-to-∈-≢ : ∀ {w x xs} → w ∈ xs \\ x → w ∈ xs × w ≢ x
\\-to-∈-≢ {_} {x} {[]} ()
\\-to-∈-≢ {_} {x} {y ∷ _} w∈ with y ≟ x
\\-to-∈-≢ {_} {x} {y ∷ _} w∈ | yes refl = there⟨ \\-to-∈-≢ w∈ ⟩
\\-to-∈-≢ {_} {x} {y ∷ _} here | no w≢ = ⟨ here , w≢ ⟩
\\-to-∈-≢ {_} {x} {y ∷ _} (there w∈) | no _ = there⟨ \\-to-∈-≢ w∈ ⟩
∈-≢-to-\\ : ∀ {w x xs} → w ∈ xs → w ≢ x → w ∈ xs \\ x
∈-≢-to-\\ {_} {x} {y ∷ _} here w≢ with y ≟ x
... | yes refl = ⊥-elim (w≢ refl)
... | no _ = here
∈-≢-to-\\ {_} {x} {y ∷ _} (there w∈) w≢ with y ≟ x
... | yes refl = ∈-≢-to-\\ w∈ w≢
... | no _ = there (∈-≢-to-\\ w∈ w≢)
\\-to-∷ : ∀ {x xs ys} → xs \\ x ⊆ ys → xs ⊆ x ∷ ys
\\-to-∷ {x} ⊆ys {w} ∈xs
with w ≟ x
... | yes refl = here
... | no ≢x = there (⊆ys (∈-≢-to-\\ ∈xs ≢x))
∷-to-\\ : ∀ {x xs ys} → xs ⊆ x ∷ ys → xs \\ x ⊆ ys
∷-to-\\ {x} xs⊆ {w} w∈
with \\-to-∈-≢ w∈
... | ⟨ ∈xs , ≢x ⟩ with w ≟ x
... | yes refl = ⊥-elim (≢x refl)
... | no w≢ with (xs⊆ ∈xs)
... | here = ⊥-elim (≢x refl)
... | there ∈ys = ∈ys
⊆-++₁ : ∀ {xs ys} → xs ⊆ xs ++ ys
⊆-++₁ here = here
⊆-++₁ (there ∈xs) = there (⊆-++₁ ∈xs)
⊆-++₂ : ∀ {xs ys} → ys ⊆ xs ++ ys
⊆-++₂ {[]} ∈ys = ∈ys
⊆-++₂ {x ∷ xs} ∈ys = there (⊆-++₂ {xs} ∈ys)
++-to-⊎ : ∀ {xs ys w} → w ∈ xs ++ ys → w ∈ xs ⊎ w ∈ ys
++-to-⊎ {[]} ∈ys = inj₂ ∈ys
++-to-⊎ {x ∷ xs} here = inj₁ here
++-to-⊎ {x ∷ xs} (there w∈) with ++-to-⊎ {xs} w∈
... | inj₁ ∈xs = inj₁ (there ∈xs)
... | inj₂ ∈ys = inj₂ ∈ys
\end{code}
Neither of the following are currently needed, but I put them here
in case they turn out to be useful later.
\begin{code}
_?∈_ : ∀ (x : A) (xs : List A) → Dec (x ∈ xs)
x ?∈ [] = no (λ())
x ?∈ (y ∷ ys) with x ≟ y
... | yes refl = yes here
... | no x≢ with x ?∈ ys
... | yes x∈ = yes (there x∈)
... | no x∉ = no (λ{ here → x≢ refl
; (there x∈) → x∉ x∈
})
distinct : List A → List A
distinct [] = []
distinct (x ∷ xs) with x ?∈ distinct xs
... | yes x∈ = distinct xs
... | no x∉ = x ∷ distinct xs
\end{code}
## Standard Library
Definitions similar to those in this chapter can be found in the standard library.
\begin{code}
-- EDIT
\end{code}
The standard library version of `IsMonoid` differs from the
one given here, in that it is also parameterised on an equivalence relation.
## Unicode
This chapter uses the following unicode.
EDIT
∷ U+2237 PROPORTION (\::)
⊗ U+2297 CIRCLED TIMES (\otimes)
∈ U+2208 ELEMENT OF (\in)
∉ U+2209 NOT AN ELEMENT OF (\inn)

View file

@ -1,80 +0,0 @@
---
title : "Fresh: Choose fresh variable name"
layout : page
permalink : /Fresh
---
## Imports
\begin{code}
module Fresh where
\end{code}
\begin{code}
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong; cong₂; _≢_)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.List using (List; []; _∷_; _++_; map; foldr; filter; concat; length)
open import Data.Nat using (; zero; suc; _+_; _∸_; _≤_; _⊔_)
open import Data.Nat.Properties using (≤-refl; ≤-trans; m≤m⊔n; n≤m⊔n; 1+n≰n)
open import Data.String using (String; _≟_)
open import Data.Product using (_×_; proj₁; proj₂; ∃; ∃-syntax)
renaming (_,_ to ⟨_,_⟩)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Function using (_∘_)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Negation using (¬?)
import Data.String as Str
import Collections
pattern [_] w = w ∷ []
pattern [_,_] w x = w ∷ x ∷ []
pattern [_,_,_] w x y = w ∷ x ∷ y ∷ []
pattern [_,_,_,_] w x y z = w ∷ x ∷ y ∷ z ∷ []
\end{code}
\begin{code}
Id : Set
Id = String
open Collections (Id) (_≟_)
prime : Id → Id
prime x = x Str.++ ""
++-identityʳ : ∀ (us : List Id) → us ++ [] ≡ us
++-identityʳ [] = refl
++-identityʳ (u ∷ us) = cong (u ∷_) (++-identityʳ us)
++-assoc : ∀ (us vs ws : List Id) →
(us ++ vs) ++ ws ≡ us ++ (vs ++ ws)
++-assoc [] vs ws = refl
++-assoc (u ∷ us) vs ws = cong (u ∷_) (++-assoc us vs ws)
lemma : ∀ (us : List Id) (v w : Id)
→ w ∉ us → w ≢ v → w ∉ (us ++ [ v ])
lemma [] v w w∉ w≢ = λ{ here → w≢ refl
; (there ())
}
lemma (u ∷ us) v w w∉ w≢ = λ{ here → w∉ here
; (there y∈) → (lemma us v w (w∉ ∘ there) w≢) y∈
}
helper : ∀ (n : ) (us vs xs : List Id) (w : Id)
→ w ∉ us → us ++ vs ≡ xs → ∃[ y ]( y ∉ xs)
helper n us [] xs w w∉ refl rewrite ++-identityʳ us = ⟨ w , w∉ ⟩
helper n us (v ∷ vs) xs w w∉ refl with w ≟ v
helper n us (v ∷ vs) xs w w∉ refl | no w≢
= helper n (us ++ [ v ]) vs xs w (lemma us v w w∉ w≢) (++-assoc us [ v ] vs)
helper (suc n) us (v ∷ vs) xs w w∉ refl | yes _
= helper n [] xs xs w (λ()) refl
helper zero us (v ∷ vs) xs w w∉ refl | yes _
= ⊥-elim impossible
where postulate impossible : ⊥
fresh : List Id → Id → Id
fresh xs y = proj₁ (helper (length xs) [] xs xs y (λ()) refl)
fresh-lemma : ∀ (xs : List Id) (x : Id) → fresh xs x ∉ xs
fresh-lemma xs y = proj₂ (helper (length xs) [] xs xs y (λ()) refl)
\end{code}

View file

@ -1,285 +0,0 @@
---
title : "FreshId: Generation of fresh names"
layout : page
permalink : /FreshId
---
Generation of fresh names, where names are strings.
Each name has a base (a string not ending in a prime)
and a suffix (a sequence of primes).
Based on an earlier version fixed by James McKinna.
\begin{code}
module FreshId where
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong; cong₂; _≢_)
open Eq.≡-Reasoning
open import Data.Empty using (⊥; ⊥-elim)
open import Data.List
using (List; []; _∷_; _++_; map; foldr; replicate; length; _∷ʳ_)
renaming (reverse to rev)
open import Data.List.Properties
using (++-assoc; ++-identityʳ)
renaming (unfold-reverse to revʳ;
reverse-++-commute to rev-++;
reverse-involutive to rev-inv)
open import Data.List.All using (All; []; _∷_)
open import Data.List.All.Properties
renaming (++⁺ to _++All_)
open import Data.Nat using (; zero; suc; _+_; _∸_; _≤_; _⊔_)
open import Data.Nat.Properties using (≤-refl; ≤-trans; m≤m⊔n; n≤m⊔n; 1+n≰n)
open import Data.Bool using (Bool; true; false; T)
open import Data.Char using (Char)
import Data.Char as Char using (_≟_)
open import Data.String using (String; toList; fromList; _≟_;
toList∘fromList; fromList∘toList)
open import Data.Product using (_×_; proj₁; proj₂; ∃; ∃-syntax)
renaming (_,_ to ⟨_,_⟩)
open import Data.Unit using (; tt)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Function using (_∘_)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Negation using (¬?)
-- open import Relation.Nullary.Decidable using (⌊_⌋)
open import Relation.Unary using (Decidable)
import Data.Nat as Nat
import Data.String as String
import Collections
pattern [_] x = x ∷ []
pattern [_,_] x y = x ∷ y ∷ []
pattern [_,_,_] x y z = x ∷ y ∷ z ∷ []
pattern [_,_,_,_] x y z w = x ∷ y ∷ z ∷ w ∷ []
\end{code}
## DropWhile and TakeWhile for decidable predicates
\begin{code}
module Break {A : Set} where
data Break (P : A → Set) : List A → Set where
none : ∀ {xs} → All P xs → Break P xs
some : ∀ {xs y zs} → All P xs → ¬ P y → Break P (xs ++ [ y ] ++ zs)
break : ∀ {P : A → Set} (P? : Decidable P) → (xs : List A) → Break P xs
break P? [] = none []
break P? (w ∷ ws) with P? w
... | no ¬Pw = some [] ¬Pw
... | yes Pw with break P? ws
... | none Pws = none (Pw ∷ Pws)
... | some Pws ¬Py = some (Pw ∷ Pws) ¬Py
takeWhile : ∀ {P : A → Set} (P? : Decidable P) → List A → List A
takeWhile P? ws with break P? ws
... | none {xs} Pxs = xs
... | some {xs} {y} {zs} Pxs ¬Py = xs
dropWhile : ∀ {P : A → Set} (P? : Decidable P) → List A → List A
dropWhile P? ws with break P? ws
... | none {xs} Pxs = []
... | some {xs} {y} {zs} Pxs ¬Py = y ∷ zs
module RevBreak {A : Set} where
open Break {A}
data RevBreak (P : A → Set) : List A → Set where
rnone : ∀ {xs} → All P (rev xs) → RevBreak P xs
rsome : ∀ {zs y xs} → ¬ P y → All P (rev xs) → RevBreak P (zs ++ [ y ] ++ xs)
{-
revBreak : ∀ {P : A → Set} (P? : Decidable P) → (xs : List A) → RevBreak P xs
revBreak P? ws with break P? (rev ws)
... | none {xs} Pxs = ?
-- rewrite rev-inv ws
-- = rnone {xs = rev xs} Pxs
... | some {xs} {y} {zs} Pxs ¬Py = ?
-- rewrite rev-inv xs | rev-inv zs
-- = rsome {zs = rev zs} {y = y} {xs = rev xs} ¬Py Pxs
-}
{-
_++All_ : ∀ {xs ys : List A} (P : A → Set) → All P xs → All P ys → All P (xs ++ ys)
revAll : ∀ {xs : List A} (P : A → Set) → All P xs → All P (rev xs)
data BBreak (P : A → Set) : List A → Set where
none : ∀ {xs} → All P xs → BBreak P xs
some : ∀ {xs y zs} → ¬ P y → All P zs → BBreak P (xs ++ [ y ] ++ zs)
bbreak : ∀ {P : A → Set} (P? : Decidable P) → (xs : List A) → Break P xs
bbreak P? ws with break P? (rev ws)
... | none {xs} Pxs = none {rev xs} (revAll Pws)
... | some {xs} {y} {zs} Pxs ¬Py = some ¬Py
-}
\end{code}
## Abstract operators prefix, suffix, and make
\begin{code}
{-
Id : Set
Id = String
open Collections (Id) (String._≟_)
module IdBase
(P : Char → Set)
(P? : ∀ (c : Char) → Dec (P c))
(to : List Char → )
(from : → List Char)
(to∘from : ∀ (n : ) → to (from n) ≡ n)
(from∘to : ∀ (s : List Char) → (All P s) → from (to s) ≡ s)
where
open Break
isPrefix : String → Set
isPrefix s = ¬ Head P (reverse (toList s))
Prefix : Set
Prefix = ∃[ s ] (isPrefix s)
body : Prefix → String
body = proj₁
prop : (p : Prefix) → isPrefix (body p)
prop = proj₂
make : Prefix → → Id
make p n = fromList (toList (body p) ++ from n)
prefixS : Id → String
prefixS = fromList ∘ reverse ∘ dropWhile P? ∘ reverse ∘ toList
prefixS-lemma : ∀ (x : Id) → isPrefix (prefixS x)
prefixS-lemma x
rewrite toList∘fromList ((reverse ∘ dropWhile P? ∘ reverse ∘ toList) x)
| reverse-involutive ((dropWhile P? ∘ reverse ∘ toList) x)
= dropWhile-lemma P? ((reverse ∘ toList) x)
prefix : Id → Prefix
prefix x = ⟨ prefixS x , prefixS-lemma x ⟩
suffix : Id →
suffix = length ∘ takeWhile P? ∘ reverse ∘ toList
_≟Pr_ : ∀ (p q : Prefix) → Dec (body p ≡ body q)
p ≟Pr q = (body p) String.≟ (body q)
prefix-lemma : ∀ (p : Prefix) (n : ) → prefix (make p n) ≡ p
prefix-lemma p n = ?
suffix-lemma : ∀ (p : Prefix) (n : ) → suffix (make p n) ≡ n
suffix-lemma = {!!}
make-lemma : ∀ (x : Id) → make (prefix x) (suffix x) ≡ x
make-lemma = {!!}
-}
\end{code}
## Main lemmas
\begin{code}
{-
module IdLemmas
(Prefix : Set)
(prefix : Id → Prefix)
(suffix : Id → )
(make : Prefix → → Id)
(body : Prefix → String)
(_≟Pr_ : ∀ (p q : Prefix) → Dec (body p ≡ body q))
(prefix-lemma : ∀ (p : Prefix) (n : ) → prefix (make p n) ≡ p)
(suffix-lemma : ∀ (p : Prefix) (n : ) → suffix (make p n) ≡ n)
(make-lemma : ∀ (x : Id) → make (prefix x) (suffix x) ≡ x)
where
bump : Prefix → Id →
bump p x with p ≟Pr prefix x
... | yes _ = suc (suffix x)
... | no _ = zero
next : Prefix → List Id →
next p = foldr _⊔_ 0 ∘ map (bump p)
fresh : Id → List Id → Id
fresh x xs = make p (next p xs)
where
p = prefix x
⊔-lemma : ∀ {p w xs} → w ∈ xs → bump p w ≤ next p xs
⊔-lemma {p} {_} {_ ∷ xs} here = m≤m⊔n _ (next p xs)
⊔-lemma {p} {w} {x ∷ xs} (there x∈) =
≤-trans (⊔-lemma {p} {w} x∈) (n≤m⊔n (bump p x) (next p xs))
bump-lemma : ∀ {p n} → bump p (make p n) ≡ suc n
bump-lemma {p} {n}
with p ≟Pr prefix (make p n)
... | yes eqn rewrite suffix-lemma p n = refl
... | no p≢ rewrite prefix-lemma p n = ⊥-elim (p≢ refl)
fresh-lemma : ∀ {w x xs} → w ∈ xs → w ≢ fresh x xs
fresh-lemma {w} {x} {xs} w∈ = h {prefix x}
where
h : ∀ {p} → w ≢ make p (next p xs)
h {p} refl
with ⊔-lemma {p} {make p (next p xs)} {xs} w∈
... | leq rewrite bump-lemma {p} {next p xs} = 1+n≰n leq
-}
\end{code}
## Test cases
\begin{code}
{-
prime : Char
prime = ''
isPrime : Char → Set
isPrime c = c ≡ prime
isPrime? : (c : Char) → Dec (isPrime c)
isPrime? c = c Char.≟ prime
to : List Char →
to s = length s
from : → List Char
from n = replicate n prime
to∘from : ∀ (n : ) → to (from n) ≡ n
to∘from = {!!}
from∘to : ∀ (s : List Char) → All isPrime s → from (to s) ≡ s
from∘to = {!!}
open IdBase (isPrime) (isPrime?) (to) (from) (to∘from) (from∘to)
open IdLemmas (Prefix) (prefix) (suffix) (make) (body) (_≟Pr_)
(prefix-lemma) (suffix-lemma) (make-lemma)
x0 = "x"
x1 = "x"
x2 = "x"
x3 = "x"
y0 = "y"
y1 = "y"
zs0 = "zs"
zs1 = "zs"
zs2 = "zs"
_ : fresh x0 [ x0 , x1 , x2 , zs2 ] ≡ x3
_ = refl
-- fresh "x" [ "x" , "x" , "x" , "y" ] ≡ "x"
_ : fresh zs0 [ x0 , x1 , x2 , zs1 ] ≡ zs2
_ = refl
-}
\end{code}

View file

@ -1,96 +0,0 @@
---
title : "FreshUnstuck: Generation of fresh names with strings"
layout : page
permalink : /FreshUnstuck
---
Generation of fresh names, where names are string-integer pairs.
Fixed by James McKinna.
\begin{code}
module FreshUnstuck where
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong; cong₂; _≢_)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.List using (List; []; _∷_; _++_; map; foldr; filter)
open import Data.Nat using (; zero; suc; _+_; _∸_; _≤_; _⊔_)
open import Data.Nat.Properties using (≤-refl; ≤-trans; m≤m⊔n; n≤m⊔n; 1+n≰n)
open import Data.String using (String)
open import Data.Product using (_×_; proj₁; proj₂) renaming (_,_ to ⟨_,_⟩)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Function using (_∘_)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Negation using (¬?)
import Data.Nat as Nat
import Data.String as String
pattern [_] w = w ∷ []
pattern [_,_] w x = w ∷ x ∷ []
pattern [_,_,_] w x y = w ∷ x ∷ y ∷ []
pattern [_,_,_,_] w x y z = w ∷ x ∷ y ∷ z ∷ []
data Id : Set where
id : String → → Id
_≟_ : ∀ (x y : Id) → Dec (x ≡ y)
id s m ≟ id t n with s String.≟ t | m Nat.≟ n
... | yes refl | yes refl = yes refl
... | yes refl | no m≢n = no (λ {refl → m≢n refl})
... | no s≢t | _ = no (λ {refl → s≢t refl})
infix 4 _∈_
data _∈_ : Id → List Id → Set where
here : ∀ {x xs} →
----------
x ∈ x ∷ xs
there : ∀ {w x xs} →
w ∈ xs →
----------
w ∈ x ∷ xs
bump : String → Id →
bump s (id t n) with s String.≟ t
... | yes refl = suc n
... | no _ = 0
next : String → List Id →
next s = foldr _⊔_ 0 ∘ map (bump s)
⊔-lemma : ∀ {s w xs} → w ∈ xs → bump s w ≤ next s xs
⊔-lemma {s} {_} {_ ∷ xs} here = m≤m⊔n _ (next s xs)
⊔-lemma {s} {w} {x ∷ xs} (there x∈) =
≤-trans (⊔-lemma {s} {w} x∈) (n≤m⊔n (bump s x) (next s xs))
fresh : Id → List Id → Id
fresh (id s _) xs = id s (next s xs)
id-invert-str : ∀ {s t m n} → (id s m) ≡ (id t n) → t ≡ s
id-invert-str refl = refl
id-invert-nat : ∀ {s t m n} → (id s m) ≡ (id t n) → n ≡ m
id-invert-nat refl = refl
fresh-lemma : ∀ {w x xs} → w ∈ xs → w ≢ fresh x xs
fresh-lemma {w @ (id t n)} {x @ (id s _)} {xs} w∈ w≡
with s String.≟ t | ⊔-lemma {s} {w} {xs} w∈
... | yes refl | prf rewrite id-invert-nat w≡ = 1+n≰n prf
... | no s≢t | _ = s≢t (id-invert-str w≡)
x0 = id "x" 0
x1 = id "x" 1
x2 = id "x" 2
x3 = id "x" 3
y0 = id "y" 0
y1 = id "y" 1
z4 = id "z" 4
_ : fresh x0 [ x0 , x1 , x2 , z4 ] ≡ x3
_ = refl
_ : fresh y1 [ x0 , x1 , x2 , z4 ] ≡ y0
_ = refl
\end{code}

View file

@ -1,687 +0,0 @@
---
title : "Raw: Raw, Scoped, Typed"
layout : page
permalink : /RawScopedTyped
---
This version uses raw, scoped, and typed terms.
The substitution algorithm is based on one by McBride.
## Imports
\begin{code}
module RawScopedTyped where
\end{code}
\begin{code}
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong; cong₂; _≢_)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.List using (List; []; _∷_; _++_; map; foldr; filter; length)
open import Data.Nat using (; zero; suc; _+_)
import Data.String as String
open import Data.String using (String; _≟_)
open import Data.Product using (_×_; proj₁; proj₂; ∃; ∃-syntax) renaming (_,_ to ⟨_,_⟩)
-- open import Data.Sum using (_⊎_; inj₁; inj₂)
-- open import Function using (_∘_)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Negation using (¬?)
import Collections
pattern [_] w = w ∷ []
pattern [_,_] w x = w ∷ x ∷ []
pattern [_,_,_] w x y = w ∷ x ∷ y ∷ []
pattern [_,_,_,_] w x y z = w ∷ x ∷ y ∷ z ∷ []
\end{code}
## Identifiers
\begin{code}
Id : Set
Id = String
\end{code}
### Fresh variables
\begin{code}
fresh : List Id → Id → Id
fresh xs₀ y = helper xs₀ (length xs₀) y
where
prime : Id → Id
prime x = x String.++ ""
helper : List Id → → Id → Id
helper [] _ w = w
helper (x ∷ xs) n w with w ≟ x
helper (x ∷ xs) n w | no _ = helper xs n w
helper (x ∷ xs) (suc n) w | yes refl = helper xs₀ n (prime w)
helper (x ∷ xs) zero w | yes refl = ⊥-elim impossible
where postulate impossible : ⊥
\end{code}
### Lists of identifiers
\begin{code}
open Collections (Id) (_≟_)
\end{code}
## First development: Raw
\begin{code}
module Raw where
\end{code}
### Syntax
\begin{code}
infix 6 `λ_`→_
infixl 9 _·_
data Type : Set where
` : Type
_`→_ : Type → Type → Type
data Ctx : Set where
ε : Ctx
_,_`:_ : Ctx → Id → Type → Ctx
data Term : Set where
⌊_⌋ : Id → Term
`λ_`→_ : Id → Term → Term
_·_ : Term → Term → Term
`zero : Term
`suc : Term → Term
\end{code}
### Example terms
\begin{code}
two : Term
two = `λ "s" `→ `λ "z" `→ ⌊ "s" ⌋ · (⌊ "s" ⌋ · ⌊ "z" ⌋)
plus : Term
plus = `λ "m" `→ `λ "n" `→ `λ "s" `→ `λ "z" `→
⌊ "m" ⌋ · ⌊ "s" ⌋ · (⌊ "n" ⌋ · ⌊ "s" ⌋ · ⌊ "z" ⌋)
norm : Term
norm = `λ "m" `→ ⌊ "m" ⌋ · (`λ "x" `→ `suc ⌊ "x" ⌋) · `zero
\end{code}
### Free variables
\begin{code}
free : Term → List Id
free (⌊ x ⌋) = [ x ]
free (`λ x `→ N) = free N \\ x
free (L · M) = free L ++ free M
free (`zero) = []
free (`suc M) = free M
\end{code}
### Identifier maps
\begin{code}
∅ : Id → Term
∅ x = ⌊ x ⌋
infixl 5 _,_↦_
_,_↦_ : (Id → Term) → Id → Term → (Id → Term)
(ρ , x ↦ M) w with w ≟ x
... | yes _ = M
... | no _ = ρ w
\end{code}
### Fresh variables
### Substitution
\begin{code}
subst : List Id → (Id → Term) → Term → Term
subst ys ρ ⌊ x ⌋ = ρ x
subst ys ρ (`λ x `→ N) = `λ y `→ subst (y ∷ ys) (ρ , x ↦ ⌊ y ⌋) N
where
y = fresh ys x
subst ys ρ (L · M) = subst ys ρ L · subst ys ρ M
subst ys ρ (`zero) = `zero
subst ys ρ (`suc M) = `suc (subst ys ρ M)
_[_:=_] : Term → Id → Term → Term
N [ x := M ] = subst (free M ++ (free N \\ x)) (∅ , x ↦ M) N
\end{code}
### Testing substitution
\begin{code}
_ : fresh [ "y" ] "y" ≡ "y"
_ = refl
_ : fresh [ "z" ] "y" ≡ "y"
_ = refl
_ : (⌊ "s" ⌋ · ⌊ "s" ⌋ · ⌊ "z" ⌋) [ "z" := `zero ] ≡ (⌊ "s" ⌋ · ⌊ "s" ⌋ · `zero)
_ = refl
_ : (`λ "y" `→ ⌊ "x" ⌋) [ "x" := ⌊ "z" ⌋ ] ≡ (`λ "y" `→ ⌊ "z" ⌋)
_ = refl
_ : (`λ "y" `→ ⌊ "x" ⌋) [ "x" := ⌊ "y" ⌋ ] ≡ (`λ "y" `→ ⌊ "y" ⌋)
_ = refl
_ : (⌊ "s" ⌋ · ⌊ "s" ⌋ · ⌊ "z" ⌋) [ "s" := (`λ "m" `→ `suc ⌊ "m" ⌋) ]
[ "z" := `zero ]
≡ (`λ "m" `→ `suc ⌊ "m" ⌋) · (`λ "m" `→ `suc ⌊ "m" ⌋) · `zero
_ = refl
_ : subst [] (∅ , "m" ↦ two , "n" ↦ `zero) (⌊ "m" ⌋ · ⌊ "n" ⌋) ≡ (two · `zero)
_ = refl
\end{code}
### Values
\begin{code}
data Natural : Term → Set where
Zero :
--------------
Natural `zero
Suc : ∀ {V}
→ Natural V
-----------------
→ Natural (`suc V)
data Value : Term → Set where
Nat : ∀ {V}
→ Natural V
----------
→ Value V
Fun : ∀ {x N}
-----------------
→ Value (`λ x `→ N)
\end{code}
### Decide whether a term is a value
Not needed, and no longer correct.
\begin{code}
{-
value : ∀ (M : Term) → Dec (Value M)
value ⌊ x ⌋ = no (λ())
value (`λ x `→ N) = yes Fun
value (L · M) = no (λ())
value `zero = yes Zero
value (`suc M) with value M
... | yes VM = yes (Suc VM)
... | no ¬VM = no (λ{(Suc VM) → (¬VM VM)})
-}
\end{code}
### Reduction
\begin{code}
infix 4 _⟶_
data _⟶_ : Term → Term → Set where
ξ-·₁ : ∀ {L L M}
→ L ⟶ L
----------------
→ L · M ⟶ L · M
ξ-·₂ : ∀ {V M M}
→ Value V
→ M ⟶ M
----------------
→ V · M ⟶ V · M
β-→ : ∀ {x N V}
→ Value V
--------------------------------
→ (`λ x `→ N) · V ⟶ N [ x := V ]
ξ-suc : ∀ {M M}
→ M ⟶ M
------------------
→ `suc M ⟶ `suc M
\end{code}
### Reflexive and transitive closure
\begin{code}
infix 2 _⟶*_
infix 1 begin_
infixr 2 _⟶⟨_⟩_
infix 3 _∎
data _⟶*_ : Term → Term → Set where
_∎ : ∀ (M : Term)
-------------
→ M ⟶* M
_⟶⟨_⟩_ : ∀ (L : Term) {M N}
→ L ⟶ M
→ M ⟶* N
---------
→ L ⟶* N
begin_ : ∀ {M N} → (M ⟶* N) → (M ⟶* N)
begin M⟶*N = M⟶*N
\end{code}
### Decide whether a term reduces
\begin{code}
{-
data Step (M : Term) : Set where
step : ∀ {N}
→ M ⟶ N
-------
→ Step M
reduce : ∀ (M : Term) → Dec (Step M)
reduce ⌊ x ⌋ = no (λ{(step ())})
reduce (`λ x `→ N) = no (λ{(step ())})
reduce (L · M) with reduce L
... | yes (step L⟶L) = yes (step (ξ-·₁ L⟶L))
... | no ¬L⟶L with value L
... | no ¬VL = no (λ{ (step (β-→ _)) → (¬VL Fun)
; (step (ξ-·₁ L⟶L)) → (¬L⟶L (step L⟶L))
; (step (ξ-·₂ VL _)) → (¬VL VL) })
... | yes VL with reduce M
... | yes (step M⟶M) = yes (step (ξ-·₂ VL M⟶M))
... | no ¬M⟶M = {!!}
reduce `zero = {!!}
reduce (`suc M) = {!!}
-}
\end{code}
### Stuck terms
\begin{code}
data Stuck : Term → Set where
st-·₁ : ∀ {L M}
→ Stuck L
--------------
→ Stuck (L · M)
st-·₂ : ∀ {V M}
→ Value V
→ Stuck M
--------------
→ Stuck (V · M)
st-·-nat : ∀ {V M}
→ Natural V
--------------
→ Stuck (V · M)
st-suc-λ : ∀ {x N}
-------------------------
→ Stuck (`suc (`λ x `→ N))
st-suc : ∀ {M}
→ Stuck M
--------------
→ Stuck (`suc M)
\end{code}
### Closed terms
\begin{code}
Closed : Term → Set
Closed M = free M ≡ []
Ax-lemma : ∀ {x} → ¬ (Closed ⌊ x ⌋)
Ax-lemma ()
closed-·₁ : ∀ {L M} → Closed (L · M) → Closed L
closed-·₁ r = lemma r
where
lemma : ∀ {A : Set} {xs ys : List A} → xs ++ ys ≡ [] → xs ≡ []
lemma {xs = []} _ = refl
lemma {xs = x ∷ xs} ()
closed-·₂ : ∀ {L M} → Closed (L · M) → Closed M
closed-·₂ r = lemma r
where
lemma : ∀ {A : Set} {xs ys : List A} → xs ++ ys ≡ [] → ys ≡ []
lemma {xs = []} refl = refl
lemma {xs = x ∷ xs} ()
·-closed : ∀ {L M} → Closed L → Closed M → Closed (L · M)
·-closed r s = lemma r s
where
lemma : ∀ {A : Set} {xs ys : List A} → xs ≡ [] → ys ≡ [] → xs ++ ys ≡ []
lemma refl refl = refl
closed-suc : ∀ {M} → Closed (`suc M) → Closed M
closed-suc r = r
suc-closed : ∀ {M} → Closed M → Closed (`suc M)
suc-closed r = r
\end{code}
### Progress
\begin{code}
data Progress (M : Term) : Set where
step : ∀ {N}
→ M ⟶ N
-----------
→ Progress M
stuck :
Stuck M
-----------
→ Progress M
done :
Value M
-----------
→ Progress M
\end{code}
### Progress
\begin{code}
progress : ∀ (M : Term) → Closed M → Progress M
progress ⌊ x ⌋ Cx = ⊥-elim (Ax-lemma Cx)
progress (L · M) CLM with progress L (closed-·₁ {L} {M} CLM)
... | step L⟶L = step (ξ-·₁ L⟶L)
... | stuck SL = stuck (st-·₁ SL)
... | done VL with progress M (closed-·₂ {L} {M} CLM)
... | step M⟶M = step (ξ-·₂ VL M⟶M)
... | stuck SM = stuck (st-·₂ VL SM)
... | done VM with VL
... | Nat NL = stuck (st-·-nat NL)
... | Fun = step (β-→ VM)
progress (`λ x `→ N) CxN = done Fun
progress `zero Cz = done (Nat Zero)
progress (`suc M) CsM with progress M (closed-suc {M} CsM)
... | step M⟶M = step (ξ-suc M⟶M)
... | stuck SM = stuck (st-suc SM)
... | done (Nat NL) = done (Nat (Suc NL))
... | done Fun = stuck st-suc-λ
\end{code}
### Preservation
Preservation of closed terms is not so easy.
\begin{code}
preservation : ∀ {M N : Term} → Closed M → M ⟶ N → Closed N
preservation = {!!}
{-
preservation CLM (ξ-·₁ L⟶L)
= ·-closed (preservation (closed-·₁ CLM) L⟶L) (closed-·₂ CLM)
preservation CLM (ξ-·₂ _ M⟶M)
= ·-closed (closed-·₁ CLM) (preservation (closed-·₂ CLM) M⟶M)
preservation CM (β-→ VM) = {!!} -- requires closure under substitution!
preservation CM (ξ-suc M⟶M)
= suc-closed (preservation (closed-suc CM) M⟶M)
-}
\end{code}
### Evaluation
\begin{code}
Gas : Set
Gas =
data Eval (M : Term) : Set where
out-of-gas : ∀ {N} → M ⟶* N → Eval M
stuck : ∀ {N} → M ⟶* N → Stuck N → Eval M
done : ∀ {V} → M ⟶* V → Value V → Eval M
eval : Gas → (L : Term) → Closed L → Eval L
eval zero L CL = out-of-gas (L ∎)
eval (suc n) L CL with progress L CL
... | stuck SL = stuck (L ∎) SL
... | done VL = done (L ∎) VL
... | step {M} L⟶M with eval n M (preservation CL L⟶M)
... | out-of-gas M⟶*N = out-of-gas (L ⟶⟨ L⟶M ⟩ M⟶*N)
... | stuck M⟶*N SN = stuck (L ⟶⟨ L⟶M ⟩ M⟶*N) SN
... | done M⟶*V VV = done (L ⟶⟨ L⟶M ⟩ M⟶*V) VV
\end{code}
## Second development: Scoped
\begin{code}
module Scoped where
\end{code}
### Syntax
\begin{code}
infix 4 _⊢*
infix 4 _∋*
infixl 5 _,*
infix 5 `λ_`→_
infixl 6 _·_
data Ctx : Set where
ε : Ctx
_,* : Ctx → Ctx
data _∋* : Ctx → Set where
Z : ∀ {Γ}
------------
→ Γ ,* ∋*
S : ∀ {Γ}
→ Γ ∋*
--------
→ Γ ,* ∋*
data _⊢* : Ctx → Set where
⌊_⌋ : ∀ {Γ}
→ Γ ∋*
-----
→ Γ ⊢*
`λ_`→_ : ∀ {Γ} (x : Id)
→ Γ ,* ⊢*
--------
→ Γ ⊢*
_·_ : ∀ {Γ}
→ Γ ⊢*
→ Γ ⊢*
-----
→ Γ ⊢*
`zero : ∀ {Γ}
-----
→ Γ ⊢*
`suc : ∀ {Γ}
→ Γ ⊢*
-----
→ Γ ⊢*
\end{code}
### Shorthand for variables
\begin{code}
short : ∀{Γ} → → Γ ∋*
short {ε} n = ⊥-elim impossible
where postulate impossible : ⊥
short {Γ ,*} zero = Z
short {Γ ,*} (suc n) = S (short {Γ} n)
⌈_⌉ : ∀{Γ} → → Γ ⊢*
⌈ n ⌉ = ⌊ short n ⌋
\end{code}
### Sample terms
\begin{code}
two : ∀{Γ} → Γ ⊢*
two = `λ "s" `→ `λ "z" `→ ⌈ 1 ⌉ · (⌈ 1 ⌉ · ⌈ 0 ⌉)
plus : ∀{Γ} → Γ ⊢*
plus = `λ "m" `→ `λ "n" `→ `λ "s" `→ `λ "z" `→
⌈ 3 ⌉ · ⌈ 1 ⌉ · (⌈ 2 ⌉ · ⌈ 1 ⌉ · ⌈ 0 ⌉)
norm : ∀{Γ} → Γ ⊢*
norm = `λ "m" `→ ⌈ 0 ⌉ · (`λ "x" `→ `suc ⌈ 0 ⌉) · `zero
\end{code}
### Conversion: Raw to Scoped
Doing the conversion from Raw to Scoped is hard.
The conversion takes a list of variables, with the invariant
is that every free variable in the term appears in this list.
But ensuring that the invariant holds is difficult.
One way around this may be *not* to ensure the invariant,
and to return `impossible` if it is violated. If the
conversion succeeds, it is guaranteed to return a term of
the correct type.
\begin{code}
raw→scoped : Raw.Term → ε ⊢*
raw→scoped M = helper [] M
where
lookup : List Id → Id →
lookup [] w = ⊥-elim impossible
where postulate impossible : ⊥
lookup (x ∷ xs) w with w ≟ x
... | yes _ = 0
... | no _ = suc (lookup xs w)
helper : ∀ {Γ} → List Id → Raw.Term → Γ ⊢*
helper xs Raw.⌊ x ⌋ = ⌈ lookup xs x ⌉
helper xs (Raw.`λ x `→ N) = `λ x `→ helper (x ∷ xs) N
helper xs (L Raw.· M) = helper xs L · helper xs M
helper xs Raw.`zero = `zero
helper xs (Raw.`suc M) = `suc (helper xs M)
\end{code}
### Test cases
\begin{code}
_ : raw→scoped Raw.two ≡ two
_ = refl
_ : raw→scoped Raw.plus ≡ plus
_ = refl
_ : raw→scoped Raw.norm ≡ norm
_ = refl
\end{code}
### Conversion: Scoped to Raw
\begin{code}
scoped→raw : ε ⊢* → Raw.Term
scoped→raw M = helper [] M
where
index : ∀ {Γ} → List Id → Γ ∋* → Id
index [] w = ⊥-elim impossible
where postulate impossible : ⊥
index (x ∷ xs) Z = x
index (x ∷ xs) (S w) = index xs w
helper : ∀ {Γ} → List Id → Γ ⊢* → Raw.Term
helper xs ⌊ x ⌋ = Raw.⌊ index xs x ⌋
helper xs (`λ x `→ N) = Raw.`λ y `→ helper (y ∷ xs) N
where y = fresh xs x
helper xs (L · M) = (helper xs L) Raw.· (helper xs M)
helper xs `zero = Raw.`zero
helper xs (`suc M) = Raw.`suc (helper xs M)
\end{code}
This is all straightforward. But what I would like to do is show that
meaning is preserved (or reductions are preserved) by the translations,
and that would be harder. I'm especially concerned by how one would
show the call to fresh is needed, or what goes wrong if it is omitted.
### Test cases
\begin{code}
_ : scoped→raw two ≡ Raw.two
_ = refl
_ : scoped→raw plus ≡ Raw.plus
_ = refl
_ : scoped→raw norm ≡ Raw.norm
_ = refl
_ : scoped→raw (`λ "x" `→ `λ "x" `→ ⌈ 1 ⌉ · ⌈ 0 ⌉) ≡
Raw.`λ "x" `→ Raw.`λ "x" `→ Raw.⌊ "x" ⌋ Raw.· Raw.⌊ "x" ⌋
_ = refl
\end{code}
## Third development: Typed
\begin{code}
module Typed where
infix 4 _⊢_
infix 4 _∋_
infixl 5 _,_
infixr 5 _`→_
infix 5 `λ_`→_
infixl 6 _·_
data Type : Set where
` : Type
_`→_ : Type → Type → Type
data Ctx : Set where
ε : Ctx
_,_ : Ctx → Type → Ctx
data _∋_ : Ctx → Type → Set where
Z : ∀ {Γ A}
----------
→ Γ , A ∋ A
S : ∀ {Γ A B}
→ Γ ∋ B
---------
→ Γ , A ∋ B
data _⊢_ : Ctx → Type → Set where
⌊_⌋ : ∀ {Γ} {A}
→ Γ ∋ A
------
→ Γ ⊢ A
`λ_`→_ : ∀ {Γ A B} (x : Id)
→ Γ , A ⊢ B
-----------
→ Γ ⊢ A `→ B
_·_ : ∀ {Γ} {A B}
→ Γ ⊢ A `→ B
→ Γ ⊢ A
-----------
→ Γ ⊢ B
`zero : ∀ {Γ}
----------
→ Γ ⊢ `
`suc : ∀ {Γ}
→ Γ ⊢ `
-------
→ Γ ⊢ `
\end{code}

View file

@ -1,409 +0,0 @@
---
title : "Scoped: Scoped and Typed DeBruijn representation"
layout : page
permalink : /Scoped
---
## Imports
\begin{code}
module Scoped where
\end{code}
\begin{code}
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong)
-- open Eq.≡-Reasoning
open import Data.Nat using (; zero; suc; _+_; _∸_)
open import Data.Product using (_×_; proj₁; proj₂; ∃; ∃-syntax) renaming (_,_ to ⟨_,_⟩)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Decidable using (map)
open import Relation.Nullary.Negation using (contraposition)
open import Relation.Nullary.Product using (_×-dec_)
open import Data.Unit using (; tt)
open import Data.Empty using (⊥; ⊥-elim)
open import Function using (_∘_)
open import Function.Equivalence using (_⇔_; equivalence)
\end{code}
## Syntax
\begin{code}
infixr 5 _⇒_
data Type : Set where
o : Type
_⇒_ : Type → Type → Type
data Env : Set where
ε : Env
_,_ : Env → Type → Env
data Var : Env → Type → Set where
Z : ∀ {Γ : Env} {A : Type} → Var (Γ , A) A
S : ∀ {Γ : Env} {A B : Type} → Var Γ B → Var (Γ , A) B
data Exp : Env → Type → Set where
var : ∀ {Γ : Env} {A : Type} → Var Γ A → Exp Γ A
abs : ∀ {Γ : Env} {A B : Type} → Exp (Γ , A) B → Exp Γ (A ⇒ B)
app : ∀ {Γ : Env} {A B : Type} → Exp Γ (A ⇒ B) → Exp Γ A → Exp Γ B
\end{code}
## Untyped DeBruijn
\begin{code}
data DB : Set where
var : → DB
abs : DB → DB
app : DB → DB → DB
\end{code}
# PH representation
\begin{code}
data PH (X : Type → Set) : Type → Set where
var : ∀ {A : Type} → X A → PH X A
abs : ∀ {A B : Type} → (X A → PH X B) → PH X (A ⇒ B)
app : ∀ {A B : Type} → PH X (A ⇒ B) → PH X A → PH X B
\end{code}
# Convert PHOAS to DB
\begin{code}
PH→DB : ∀ {A} → (∀ {X} → PH X A) → DB
PH→DB M = h M 0
where
K : Type → Set
K A =
h : ∀ {A} → PH K A → → DB
h (var k) j = var (j ∸ k)
h (abs N) j = abs (h (N (j + 1)) (j + 1))
h (app L M) j = app (h L j) (h M j)
\end{code}
# Test examples
\begin{code}
Church : Type
Church = (o ⇒ o) ⇒ o ⇒ o
twoExp : Exp ε Church
twoExp = (abs (abs (app (var (S Z)) (app (var (S Z)) (var Z)))))
twoPH : ∀ {X} → PH X Church
twoPH = (abs (λ f → (abs (λ x → (app (var f) (app (var f) (var x)))))))
twoDB : DB
twoDB = (abs (abs (app (var 1) (app (var 1) (var 0)))))
ex : PH→DB twoPH ≡ twoDB
ex = refl
\end{code}
## Decide whether environments and types are equal
\begin{code}
_≟T_ : ∀ (A B : Type) → Dec (A ≡ B)
o ≟T o = yes refl
o ≟T (A ⇒ B) = no (λ())
(A ⇒ B) ≟T o = no (λ())
(A ⇒ B) ≟T (A ⇒ B) = map (equivalence obv1 obv2) ((A ≟T A) ×-dec (B ≟T B))
where
obv1 : ∀ {A B A B : Type} → (A ≡ A) × (B ≡ B) → A ⇒ B ≡ A ⇒ B
obv1 ⟨ refl , refl ⟩ = refl
obv2 : ∀ {A B A B : Type} → A ⇒ B ≡ A ⇒ B → (A ≡ A) × (B ≡ B)
obv2 refl = ⟨ refl , refl ⟩
_≟_ : ∀ (Γ Δ : Env) → Dec (Γ ≡ Δ)
ε ≟ ε = yes refl
ε ≟ (Γ , A) = no (λ())
(Γ , A) ≟ ε = no (λ())
(Γ , A) ≟ (Δ , B) = map (equivalence obv1 obv2) ((Γ ≟ Δ) ×-dec (A ≟T B))
where
obv1 : ∀ {Γ Δ A B} → (Γ ≡ Δ) × (A ≡ B) → (Γ , A) ≡ (Δ , B)
obv1 ⟨ refl , refl ⟩ = refl
obv2 : ∀ {Γ Δ A B} → (Γ , A) ≡ (Δ , B) → (Γ ≡ Δ) × (A ≡ B)
obv2 refl = ⟨ refl , refl ⟩
\end{code}
## Convert Phoas to Exp
\begin{code}
postulate
impossible : ∀ {A : Set} → A
compare : ∀ (A : Type) (Γ Δ : Env) → Var Δ A -- Extends (Γ , A) Δ
compare A Γ Δ with (Γ , A) ≟ Δ
compare A Γ Δ | yes refl = Z
compare A Γ (Δ , B) | no ΓA≠ΔB = S (compare A Γ Δ)
compare A Γ ε | no ΓA≠ΔB = impossible
PH→Exp : ∀ {A : Type} → (∀ {X} → PH X A) → Exp ε A
PH→Exp M = h M ε
where
K : Type → Set
K A = Env
h : ∀ {A} → PH K A → (Δ : Env) → Exp Δ A
h {A} (var Γ) Δ = var (compare A Γ Δ)
h {A ⇒ B} (abs N) Δ = abs (h (N Δ) (Δ , A))
h (app L M) Δ = app (h L Δ) (h M Δ)
exPH : PH→Exp twoPH ≡ twoExp
exPH = refl
\end{code}
## When one environment extends another
We could get rid of the use of `impossible` above if we could prove
that `Extends (Γ , A) Δ` in the `(var Γ)` case of the definition of `h`.
\begin{code}
data Extends : (Γ : Env) → (Δ : Env) → Set where
Z : ∀ {Γ : Env} → Extends Γ Γ
S : ∀ {A : Type} {Γ Δ : Env} → Extends Γ Δ → Extends Γ (Δ , A)
extract : ∀ {A : Type} {Γ Δ : Env} → Extends (Γ , A) Δ → Var Δ A
extract Z = Z
extract (S k) = S (extract k)
\end{code}
# Test code for semantics
\begin{code}
plus : Exp ε (Church ⇒ Church ⇒ Church)
plus = PH→Exp (abs λ{m → (abs λ{n → (abs λ{s → (abs λ{z →
(app (app (var m) (var s)) (app (app (var n) (var s)) (var z)))})})})})
one : Exp ε Church
one = PH→Exp (abs λ{s → (abs λ{z → (app (var s) (var z))})})
two : Exp ε Church
two = (app (app plus one) one)
four : Exp ε Church
four = (app (app plus two) two)
\end{code}
# Denotational semantics
\begin{code}
type : Type → Set
type o =
type (A ⇒ B) = type A → type B
env : Env → Set
env ε =
env (Γ , A) = env Γ × type A
lookup : ∀ {Γ : Env} {A : Type} → Var Γ A → env Γ → type A
lookup Z ⟨ ρ , v ⟩ = v
lookup (S n) ⟨ ρ , v ⟩ = lookup n ρ
eval : ∀ {Γ : Env} {A : Type} → Exp Γ A → env Γ → type A
eval (var n) ρ = lookup n ρ
eval (abs N) ρ = λ{ v → eval N ⟨ ρ , v ⟩ }
eval (app L M) ρ = eval L ρ (eval M ρ)
ex₀ : eval four tt suc zero ≡ 4
ex₀ = refl
\end{code}
# Operational semantics - with substitution a la Darais (31 lines)
## Remove variable from environment (4 lines)
\begin{code}
infix 4 _⊝_
_⊝_ : ∀ {A : Type} (Γ : Env) → Var Γ A → Env
(Γ , B) ⊝ Z = Γ
(Γ , B) ⊝ S k = (Γ ⊝ k) , B
\end{code}
## Rebuild environment (6 lines)
\begin{code}
shunt : ∀ (Γ Δ : Env) → Env
shunt Γ ε = Γ
shunt Γ (Δ , A) = shunt (Γ , A) Δ
weaken : ∀ (Γ Δ : Env) {A : Type} (k : Var Γ A) → Var (shunt Γ Δ) A
weaken Γ ε k = k
weaken Γ (Δ , A) k = weaken (Γ , A) Δ (S k)
\end{code}
## Lift term to a larger environment (8 lines)
\begin{code}
liftvar : ∀ {Γ : Env} {A B : Type} (j : Var Γ B) (k : Var (Γ ⊝ j) A) → Var Γ A
liftvar Z k = S k
liftvar (S j) Z = Z
liftvar (S j) (S k) = S (liftvar j k)
lift : ∀ {Γ : Env} {A B : Type} (j : Var Γ B) (M : Exp (Γ ⊝ j) A) → Exp Γ A
lift j (var k) = var (liftvar j k)
lift j (abs N) = abs (lift (S j) N)
lift j (app L M) = app (lift j L) (lift j M)
\end{code}
## Substitution (13 lines)
\begin{code}
substvar : ∀ (Γ Δ : Env) {A B : Type} (j : Var Γ B) (k : Var Γ A) (P : Exp (shunt (Γ ⊝ k) Δ) A) → Exp (shunt (Γ ⊝ k) Δ) B
substvar Γ Δ Z Z P = P
substvar (Γ , A) Δ Z (S k) P = var (weaken ((Γ ⊝ k) , A) Δ Z)
substvar (Γ , A) Δ (S j) Z P = var (weaken Γ Δ j)
substvar (Γ , A) Δ (S j) (S k) P = substvar Γ (Δ , A) j k P
subst : ∀ {Γ : Env} {A B : Type} (N : Exp Γ B) (k : Var Γ A) (M : Exp (Γ ⊝ k) A) → Exp (Γ ⊝ k) B
subst {Γ} (var j) k P = substvar Γ ε j k P
subst (abs N) k P = abs (subst N (S k) (lift Z P))
subst (app L M) k P = app (subst L k P) (subst M k P)
\end{code}
# Operational semantics - with simultaneous substitution, a la McBride (18 lines)
## Renaming (7 lines)
\begin{code}
extend : ∀ {Γ Δ : Env} {B : Type} → (∀ {A : Type} → Var Γ A → Var Δ A) → Var Δ B → (∀ {A : Type} → Var (Γ , B) A → Var Δ A)
extend ρ j Z = j
extend ρ j (S k) = ρ k
rename : ∀ {Γ Δ : Env} → (∀ {A : Type} → Var Γ A → Var Δ A) → (∀ {A : Type} → Exp Γ A → Exp Δ A)
rename ρ (var n) = var (ρ n)
rename ρ (abs N) = abs (rename (extend (S ∘ ρ) Z) N)
rename ρ (app L M) = app (rename ρ L) (rename ρ M)
\end{code}
## Substitution (9 lines)
\begin{code}
ext : ∀ {Γ Δ : Env} {B : Type} → (∀ {A : Type} → Var Γ A → Exp Δ A) → Exp Δ B → (∀ {A : Type} → Var (Γ , B) A → Exp Δ A)
ext ρ j Z = j
ext ρ j (S k) = ρ k
sub : ∀ {Γ Δ : Env} → (∀ {A : Type} → Var Γ A → Exp Δ A) → (∀ {A : Type} → Exp Γ A → Exp Δ A)
sub ρ (var n) = ρ n
sub ρ (app L M) = app (sub ρ L) (sub ρ M)
sub ρ (abs N) = abs (sub (ext (rename S ∘ ρ) (var Z)) N)
substitute : ∀ {Γ : Env} {A B : Type} → Exp (Γ , A) B → Exp Γ A → Exp Γ B
substitute N M = sub (ext var M) N
\end{code}
## Value
\begin{code}
data Val : {Γ : Env} {A : Type} → Exp Γ A → Set where
Fun : ∀ {Γ : Env} {A B : Type} {N : Exp (Γ , A) B} →
Val (abs N)
\end{code}
## Reduction step
\begin{code}
data _⟶_ : {Γ : Env} {A : Type} → Exp Γ A → Exp Γ A → Set where
ξ₁ : ∀ {Γ : Env} {A B : Type} {L : Exp Γ (A ⇒ B)} {L : Exp Γ (A ⇒ B)} {M : Exp Γ A} →
L ⟶ L
app L M ⟶ app L M
ξ₂ : ∀ {Γ : Env} {A B : Type} {L : Exp Γ (A ⇒ B)} {M : Exp Γ A} {M : Exp Γ A} →
Val L →
M ⟶ M
app L M ⟶ app L M
β : ∀ {Γ : Env} {A B : Type} {N : Exp (Γ , A) B} {M : Exp Γ A} →
Val M →
app (abs N) M ⟶ substitute N M
\end{code}
## Reflexive and transitive closure
\begin{code}
data _⟶*_ : {Γ : Env} {A : Type} → Exp Γ A → Exp Γ A → Set where
reflexive : ∀ {Γ : Env} {A : Type} {M : Exp Γ A} →
M ⟶* M
inclusion : ∀ {Γ : Env} {A : Type} {L M : Exp Γ A} →
L ⟶ M →
L ⟶* M
transitive : ∀ {Γ : Env} {A : Type} {L M N : Exp Γ A} →
L ⟶* M →
M ⟶* N →
L ⟶* N
\end{code}
## Displaying reduction sequences
\begin{code}
infix 1 begin_
infixr 2 _⟶⟨_⟩_
infix 3 _∎
begin_ : {Γ : Env} {A : Type} {M N : Exp Γ A} → (M ⟶* N) → (M ⟶* N)
begin steps = steps
_⟶⟨_⟩_ : {Γ : Env} {A : Type} (L : Exp Γ A) {M N : Exp Γ A} → (L ⟶ M) → (M ⟶* N) → (L ⟶* N)
L ⟶⟨ L⟶M ⟩ M⟶*N = transitive (inclusion L⟶M) M⟶*N
_∎ : {Γ : Env} {A : Type} (M : Exp Γ A) → M ⟶* M
M ∎ = reflexive
\end{code}
## Example reduction sequence
\begin{code}
ex₁ : (app (abs (var Z)) (abs (var Z))) ⟶* (abs (var Z))
ex₁ =
begin
(app (abs {Γ = ε} {A = o ⇒ o} (var Z)) (abs (var Z)))
⟶⟨ β Fun ⟩
(abs (var Z))
\end{code}
\begin{code}
Γone : ∀ {Γ} → Exp Γ Church
Γone = (abs (abs (app (var (S Z)) (var Z))))
ex₂ : two ⟶* (abs (abs (app (app Γone (var (S Z))) (app (app Γone (var (S Z))) (var Z)))))
ex₂ =
begin
(app (app plus one) one)
⟶⟨ ξ₁ (β Fun) ⟩
(app (abs (abs (abs (app (app Γone (var (S Z))) (app (app (var (S (S Z))) (var (S Z))) (var Z)))))) Γone)
⟶⟨ β Fun ⟩
(abs (abs (app (app Γone (var (S Z))) (app (app Γone (var (S Z))) (var Z)))))
\end{code}
\begin{code}
progress : ∀ {A : Type} → (M : Exp ε A) → (∃[ N ] (M ⟶ N)) ⊎ Val M
progress (var ())
progress (abs N) = inj₂ Fun
progress (app L M) with progress L
progress (app L M) | inj₁ ⟨ L , r ⟩ = inj₁ ⟨ app L M , ξ₁ r ⟩
progress (app (abs N) M) | inj₂ Fun with progress M
progress (app (abs N) M) | inj₂ Fun | inj₁ ⟨ M , r ⟩ = inj₁ ⟨ app (abs N) M , ξ₂ Fun r ⟩
progress (app (abs N) M) | inj₂ Fun | inj₂ ValM = inj₁ ⟨ substitute N M , β ValM ⟩
\end{code}
\begin{code}
ex₃ : progress (app (app plus one) one) ≡
inj₁ ⟨ (app (abs (abs (abs (app (app Γone (var (S Z))) (app (app (var (S (S Z))) (var (S Z))) (var Z)))))) Γone) , ξ₁ (β Fun) ⟩
ex₃ = refl
ex₄ : progress (app (abs (abs (abs (app (app Γone (var (S Z))) (app (app (var (S (S Z))) (var (S Z))) (var Z)))))) Γone) ≡
inj₁ ⟨ (abs (abs (app (app Γone (var (S Z))) (app (app Γone (var (S Z))) (var Z))))) , β Fun ⟩
ex₄ = refl
ex₅ : progress (abs (abs (app (app Γone (var (S Z))) (app (app Γone (var (S Z))) (var Z))))) ≡ inj₂ Fun
ex₅ = refl
\end{code}

View file

@ -1,724 +0,0 @@
---
title : "TypedBadfix: Typed Lambda term representation (bad fix)"
layout : page
permalink : /TypedBadfix
---
## Imports
\begin{code}
module TypedBadfix where
\end{code}
\begin{code}
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong; cong₂; _≢_)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.List using (List; []; _∷_; [_]; _++_; map; foldr; filter)
open import Data.List.Any using (Any; here; there)
open import Data.Nat using (; zero; suc; _+_; _∸_; _≤_; _⊔_; _≟_)
open import Data.Nat.Properties using (≤-refl; ≤-trans; m≤m⊔n; n≤m⊔n; 1+n≰n)
open import Data.Product using (_×_; proj₁; proj₂; ∃; ∃-syntax)
renaming (_,_ to ⟨_,_⟩)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Data.Unit using (; tt)
open import Function using (_∘_)
open import Function.Equality using (≡-setoid)
open import Function.Equivalence using (_⇔_; equivalence)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Nullary.Negation using (contraposition; ¬?)
open import Relation.Nullary.Product using (_×-dec_)
import Collections
\end{code}
## Syntax
\begin{code}
infixr 5 _⟹_
infixl 5 _,_⦂_
infix 4 _∋_⦂_
infix 4 _⊢_⦂_
infix 5 `λ_⇒_
infix 5 `λ_
infixl 6 _·_
infix 7 `_
Id : Set
Id =
data Type : Set where
` : Type
_⟹_ : Type → Type → Type
data Env : Set where
ε : Env
_,_⦂_ : Env → Id → Type → Env
data Term : Set where
`_ : Id → Term
`λ_⇒_ : Id → Term → Term
_·_ : Term → Term → Term
data _∋_⦂_ : Env → Id → Type → Set where
Z : ∀ {Γ A x}
-----------------
→ Γ , x ⦂ A ∋ x ⦂ A
S : ∀ {Γ A B x w}
→ w ≢ x
→ Γ ∋ w ⦂ B
-----------------
→ Γ , x ⦂ A ∋ w ⦂ B
data _⊢_⦂_ : Env → Term → Type → Set where
`_ : ∀ {Γ A x}
→ Γ ∋ x ⦂ A
---------------------
→ Γ ⊢ ` x ⦂ A
`λ_ : ∀ {Γ x A N B}
→ Γ , x ⦂ A ⊢ N ⦂ B
------------------------
→ Γ ⊢ (`λ x ⇒ N) ⦂ A ⟹ B
_·_ : ∀ {Γ L M A B}
→ Γ ⊢ L ⦂ A ⟹ B
→ Γ ⊢ M ⦂ A
--------------
→ Γ ⊢ L · M ⦂ B
\end{code}
## Test examples
\begin{code}
m n s z : Id
m = 0
n = 1
s = 2
z = 3
s≢z : s ≢ z
s≢z ()
n≢z : n ≢ z
n≢z ()
n≢s : n ≢ s
n≢s ()
m≢z : m ≢ z
m≢z ()
m≢s : m ≢ s
m≢s ()
m≢n : m ≢ n
m≢n ()
Ch : Type
Ch = (` ⟹ `) ⟹ ` ⟹ `
two : Term
two = `λ s ⇒ `λ z ⇒ (` s · (` s · ` z))
⊢two : ε ⊢ two ⦂ Ch
⊢two = `λ `λ ` ⊢s · (` ⊢s · ` ⊢z)
where
⊢s = S s≢z Z
⊢z = Z
four : Term
four = `λ s ⇒ `λ z ⇒ ` s · (` s · (` s · (` s · ` z)))
⊢four : ε ⊢ four ⦂ Ch
⊢four = `λ `λ ` ⊢s · (` ⊢s · (` ⊢s · (` ⊢s · ` ⊢z)))
where
⊢s = S s≢z Z
⊢z = Z
plus : Term
plus = `λ m ⇒ `λ n ⇒ `λ s ⇒ `λ z ⇒ ` m · ` s · (` n · ` s · ` z)
⊢plus : ε ⊢ plus ⦂ Ch ⟹ Ch ⟹ Ch
⊢plus = `λ `λ `λ `λ ` ⊢m · ` ⊢s · (` ⊢n · ` ⊢s · ` ⊢z)
where
⊢z = Z
⊢s = S s≢z Z
⊢n = S n≢z (S n≢s Z)
⊢m = S m≢z (S m≢s (S m≢n Z))
four : Term
four = plus · two · two
⊢four : ε ⊢ four ⦂ Ch
⊢four = ⊢plus · ⊢two · ⊢two
\end{code}
# Denotational semantics
\begin{code}
⟦_⟧ᵀ : Type → Set
⟦ ` ⟧ᵀ =
⟦ A ⟹ B ⟧ᵀ = ⟦ A ⟧ᵀ → ⟦ B ⟧ᵀ
⟦_⟧ᴱ : Env → Set
⟦ ε ⟧ᴱ =
⟦ Γ , x ⦂ A ⟧ᴱ = ⟦ Γ ⟧ᴱ × ⟦ A ⟧ᵀ
⟦_⟧ⱽ : ∀ {Γ x A} → Γ ∋ x ⦂ A → ⟦ Γ ⟧ᴱ → ⟦ A ⟧ᵀ
⟦ Z ⟧ⱽ ⟨ ρ , v ⟩ = v
⟦ S _ x ⟧ⱽ ⟨ ρ , v ⟩ = ⟦ x ⟧ⱽ ρ
⟦_⟧ : ∀ {Γ M A} → Γ ⊢ M ⦂ A → ⟦ Γ ⟧ᴱ → ⟦ A ⟧ᵀ
⟦ ` x ⟧ ρ = ⟦ x ⟧ⱽ ρ
⟦ `λ ⊢N ⟧ ρ = λ{ v → ⟦ ⊢N ⟧ ⟨ ρ , v ⟩ }
⟦ ⊢L · ⊢M ⟧ ρ = (⟦ ⊢L ⟧ ρ) (⟦ ⊢M ⟧ ρ)
_ : ⟦ ⊢four ⟧ tt ≡ ⟦ ⊢four ⟧ tt
_ = refl
_ : ⟦ ⊢four ⟧ tt suc zero ≡ 4
_ = refl
\end{code}
## Erasure
\begin{code}
lookup : ∀ {Γ x A} → Γ ∋ x ⦂ A → Id
lookup {Γ , x ⦂ A} Z = x
lookup {Γ , x ⦂ A} (S _ k) = lookup {Γ} k
erase : ∀ {Γ M A} → Γ ⊢ M ⦂ A → Term
erase (` k) = ` lookup k
erase (`λ_ {x = x} ⊢N) = `λ x ⇒ erase ⊢N
erase (⊢L · ⊢M) = erase ⊢L · erase ⊢M
\end{code}
### Properties of erasure
\begin{code}
lookup-lemma : ∀ {Γ x A} → (⊢x : Γ ∋ x ⦂ A) → lookup ⊢x ≡ x
lookup-lemma Z = refl
lookup-lemma (S _ k) = lookup-lemma k
erase-lemma : ∀ {Γ M A} → (⊢M : Γ ⊢ M ⦂ A) → erase ⊢M ≡ M
erase-lemma (` ⊢x) = cong `_ (lookup-lemma ⊢x)
erase-lemma (`λ_ {x = x} ⊢N) = cong (`λ x ⇒_) (erase-lemma ⊢N)
erase-lemma (⊢L · ⊢M) = cong₂ _·_ (erase-lemma ⊢L) (erase-lemma ⊢M)
\end{code}
## Substitution
### Lists as sets
\begin{code}
open Collections (Id) (_≟_)
\end{code}
### Free variables
\begin{code}
free : Term → List Id
free (` x) = [ x ]
free (`λ x ⇒ N) = free N \\ x
free (L · M) = free L ++ free M
\end{code}
### Fresh identifier
\begin{code}
fresh : List Id → Id
fresh = foldr _⊔_ 0 ∘ map suc
⊔-lemma : ∀ {w xs} → w ∈ xs → suc w ≤ fresh xs
⊔-lemma {_} {_ ∷ xs} here = m≤m⊔n _ (fresh xs)
⊔-lemma {_} {_ ∷ xs} (there x∈) = ≤-trans (⊔-lemma x∈) (n≤m⊔n _ (fresh xs))
fresh-lemma : ∀ {x xs} → x ∈ xs → x ≢ fresh xs
fresh-lemma x∈ refl = 1+n≰n (⊔-lemma x∈)
\end{code}
### Identifier maps
\begin{code}
∅ : Id → Term
∅ x = ` x
infixl 5 _,_↦_
_,_↦_ : (Id → Term) → Id → Term → (Id → Term)
(ρ , x ↦ M) w with w ≟ x
... | yes _ = M
... | no _ = ρ w
\end{code}
### Substitution
\begin{code}
subst : List Id → (Id → Term) → Term → Term
subst ys ρ (` x) = ρ x
subst ys ρ (`λ x ⇒ N) = `λ y ⇒ subst (y ∷ ys) (ρ , x ↦ ` y) N
where
y = fresh ys
subst ys ρ (L · M) = subst ys ρ L · subst ys ρ M
_[_:=_] : Term → Id → Term → Term
N [ x := M ] = subst (free M ++ (free N \\ x)) (∅ , x ↦ M) N
\end{code}
## Values
\begin{code}
data Value : Term → Set where
Fun : ∀ {x N}
---------------
→ Value (`λ x ⇒ N)
\end{code}
## Reduction
\begin{code}
infix 4 _⟶_
data _⟶_ : Term → Term → Set where
β-⟹ : ∀ {x N V}
→ Value V
------------------------------
→ (`λ x ⇒ N) · V ⟶ N [ x := V ]
ξ-⟹₁ : ∀ {L L M}
→ L ⟶ L
----------------
→ L · M ⟶ L · M
ξ-⟹₂ : ∀ {V M M} →
Value V →
M ⟶ M
----------------
V · M ⟶ V · M
\end{code}
## Reflexive and transitive closure
\begin{code}
infix 2 _⟶*_
infix 1 begin_
infixr 2 _⟶⟨_⟩_
infix 3 _∎
data _⟶*_ : Term → Term → Set where
_∎ : ∀ {M}
-------------
→ M ⟶* M
_⟶⟨_⟩_ : ∀ (L : Term) {M N}
→ L ⟶ M
→ M ⟶* N
---------
→ L ⟶* N
begin_ : ∀ {M N} → (M ⟶* N) → (M ⟶* N)
begin M⟶*N = M⟶*N
\end{code}
## Progress
\begin{code}
data Progress (M : Term) : Set where
step : ∀ {N}
→ M ⟶ N
----------
→ Progress M
done :
Value M
----------
→ Progress M
progress : ∀ {M A} → ε ⊢ M ⦂ A → Progress M
progress (` ())
progress (`λ_ ⊢N) = done Fun
progress (⊢L · ⊢M) with progress ⊢L
... | step L⟶L = step (ξ-⟹₁ L⟶L)
... | done Fun with progress ⊢M
... | step M⟶M = step (ξ-⟹₂ Fun M⟶M)
... | done valM = step (β-⟹ valM)
\end{code}
## Preservation
### Domain of an environment
\begin{code}
dom : Env → List Id
dom ε = []
dom (Γ , x ⦂ A) = x ∷ dom Γ
dom-lemma : ∀ {Γ y B} → Γ ∋ y ⦂ B → y ∈ dom Γ
dom-lemma Z = here
dom-lemma (S x≢y ⊢y) = there (dom-lemma ⊢y)
free-lemma : ∀ {Γ M A} → Γ ⊢ M ⦂ A → free M ⊆ dom Γ
free-lemma (` ⊢x) w∈ with w∈
... | here = dom-lemma ⊢x
... | there ()
free-lemma {Γ} (`λ_ {x = x} {N = N} ⊢N) = ∷-to-\\ (free-lemma ⊢N)
free-lemma (⊢L · ⊢M) w∈ with ++-to-⊎ w∈
... | inj₁ ∈L = free-lemma ⊢L ∈L
... | inj₂ ∈M = free-lemma ⊢M ∈M
\end{code}
### Weakening
\begin{code}
⊢weaken : ∀ {Γ Δ}
→ (∀ {x A} → Γ ∋ x ⦂ A → Δ ∋ x ⦂ A)
--------------------------------------------------
→ (∀ {M A} → Γ ⊢ M ⦂ A → Δ ⊢ M ⦂ A)
⊢weaken ⊢σ (` ⊢x) = ` ⊢σ ⊢x
⊢weaken {Γ} {Δ} ⊢σ (`λ_ {x = x} {A = A} {N = N} ⊢N)
= `λ (⊢weaken {Γ′} {Δ′} ⊢σ′ ⊢N)
where
Γ′ = Γ , x ⦂ A
Δ′ = Δ , x ⦂ A
⊢σ′ : ∀ {w B} → Γ′ ∋ w ⦂ B → Δ′ ∋ w ⦂ B
⊢σ′ Z = Z
⊢σ′ (S w≢ ⊢w) = S w≢ (⊢σ ⊢w)
⊢weaken ⊢σ (⊢L · ⊢M) = ⊢weaken ⊢σ ⊢L · ⊢weaken ⊢σ ⊢M
\end{code}
### Strengthening is old renaming
### Renaming
\begin{code}
⊢rename : ∀ {Γ Δ xs}
→ (∀ {x A} → x ∈ xs → Γ ∋ x ⦂ A → Δ ∋ x ⦂ A)
--------------------------------------------------
→ (∀ {M A} → free M ⊆ xs → Γ ⊢ M ⦂ A → Δ ⊢ M ⦂ A)
⊢rename ⊢σ ⊆xs (` ⊢x) = ` ⊢σ ∈xs ⊢x
where
∈xs = ⊆xs here
⊢rename {Γ} {Δ} {xs} ⊢σ ⊆xs (`λ_ {x = x} {A = A} {N = N} ⊢N)
= `λ (⊢rename {Γ′} {Δ′} {xs} ⊢σ′ ⊆xs ⊢N)
where
Γ′ = Γ , x ⦂ A
Δ′ = Δ , x ⦂ A
xs = x ∷ xs
⊢σ′ : ∀ {w B} → w ∈ xs → Γ′ ∋ w ⦂ B → Δ′ ∋ w ⦂ B
⊢σ′ w∈ Z = Z
⊢σ′ w∈ (S w≢ ⊢w) = S w≢ (⊢σ ∈w ⊢w)
where
∈w = there⁻¹ w∈ w≢
⊆xs : free N ⊆ xs
⊆xs = \\-to-∷ ⊆xs
⊢rename ⊢σ ⊆xs (⊢L · ⊢M) = ⊢rename ⊢σ L⊆ ⊢L · ⊢rename ⊢σ M⊆ ⊢M
where
L⊆ = trans-⊆ ⊆-++₁ ⊆xs
M⊆ = trans-⊆ ⊆-++₂ ⊆xs
\end{code}
### Substitution preserves types, general case
\begin{code}
map-≡ : ∀ {ρ M w x} → w ≡ x → (ρ , x ↦ M) w ≡ M
map-≡ {_} {_} {w} {x} w≡ with w ≟ x
... | yes _ = refl
... | no w≢ = ⊥-elim (w≢ w≡)
map-≢ : ∀ {ρ M w x} → w ≢ x → (ρ , x ↦ M) w ≡ ρ w
map-≢ {_} {_} {w} {x} w≢ with w ≟ x
... | yes w≡ = ⊥-elim (w≢ w≡)
... | no _ = refl
\end{code}
\begin{code}
⊢subst : ∀ {Γ Δ ys ρ}
→ dom Δ ⊆ ys
→ (∀ {x A} → Γ ∋ x ⦂ A → Δ ⊢ ρ x ⦂ A)
--------------------------------------------------------------
→ (∀ {M A} → Γ ⊢ M ⦂ A → Δ ⊢ subst ys ρ M ⦂ A)
⊢subst ⊆ys ⊢ρ (` ⊢x)
= ⊢ρ ⊢x
⊢subst {Γ} {Δ} {ys} {ρ} ⊆ys ⊢ρ (`λ_ {x = x} {A = A} {N = N} ⊢N)
= `λ_ {x = y} {A = A} (⊢subst {Γ′} {Δ′} {ys} {ρ} ⊆ys ⊢ρ′ ⊢N)
where
y = fresh ys
Γ′ = Γ , x ⦂ A
Δ′ = Δ , y ⦂ A
ys = y ∷ ys
ρ = ρ , x ↦ ` y
⊆ys : dom Δ′ ⊆ ys
⊆ys {w} here = here
⊆ys {w} (there w∈) = there (⊆ys w∈)
⊢σ : ∀ {w C} → Δ ∋ w ⦂ C → Δ′ ∋ w ⦂ C
⊢σ {w} ⊢w = S w≢ ⊢w
where
w≢ : w ≢ y
w≢ = fresh-lemma (⊆ys (dom-lemma ⊢w))
⊢ρ′ : ∀ {w C} → Γ′ ∋ w ⦂ C → Δ′ ⊢ ρ w ⦂ C
⊢ρ′ {w} Z rewrite map-≡ {ρ} {` y} {w} {x} refl = ` Z
⊢ρ′ {w} (S w≢ ⊢w) rewrite map-≢ {ρ} {` y} {w} {x} w≢ = ⊢weaken {Δ} {Δ′} ⊢σ (⊢ρ ⊢w)
⊢subst Σ ⊢ρ (⊢L · ⊢M)
= ⊢subst Σ ⊢ρ ⊢L · ⊢subst Σ ⊢ρ ⊢M
{-
⊢subst : ∀ {Γ Δ xs ys ρ}
→ (∀ {x} → x ∈ xs → free (ρ x) ⊆ ys)
→ (∀ {x A} → x ∈ xs → Γ ∋ x ⦂ A → Δ ⊢ ρ x ⦂ A)
--------------------------------------------------------------
→ (∀ {M A} → free M ⊆ xs → Γ ⊢ M ⦂ A → Δ ⊢ subst ys ρ M ⦂ A)
⊢subst Σ ⊢ρ ⊆xs (` ⊢x)
= ⊢ρ (⊆xs here) ⊢x
⊢subst {Γ} {Δ} {xs} {ys} {ρ} Σ ⊢ρ ⊆xs (`λ_ {x = x} {A = A} {N = N} ⊢N)
= `λ_ {x = y} {A = A} (⊢subst {Γ′} {Δ′} {xs} {ys} {ρ} Σ′ ⊢ρ′ ⊆xs ⊢N)
where
y = fresh ys
Γ′ = Γ , x ⦂ A
Δ′ = Δ , y ⦂ A
xs = x ∷ xs
ys = y ∷ ys
ρ = ρ , x ↦ ` y
Σ′ : ∀ {w} → w ∈ xs → free (ρ w) ⊆ ys
Σ′ {w} w∈ with w ≟ x
... | yes refl = ⊆-++₁
... | no w≢ = ⊆-++₂ ∘ Σ (there⁻¹ w∈ w≢)
⊆xs : free N ⊆ xs
⊆xs = \\-to-∷ ⊆xs
⊢σ : ∀ {w C} → w ∈ ys → Δ ∋ w ⦂ C → Δ′ ∋ w ⦂ C
⊢σ w∈ ⊢w = S (fresh-lemma w∈) ⊢w
⊢ρ′ : ∀ {w C} → w ∈ xs → Γ′ ∋ w ⦂ C → Δ′ ⊢ ρ w ⦂ C
⊢ρ′ {w} _ Z with w ≟ x
... | yes _ = ` Z
... | no w≢ = ⊥-elim (w≢ refl)
⊢ρ′ {w} w∈ (S w≢ ⊢w) with w ≟ x
... | yes refl = ⊥-elim (w≢ refl)
... | no _ = ⊢rename {Δ} {Δ′} {ys} ⊢σ (Σ w∈) (⊢ρ w∈ ⊢w)
where
w∈ = there⁻¹ w∈ w≢
⊢subst Σ ⊢ρ ⊆xs (⊢L · ⊢M)
= ⊢subst Σ ⊢ρ L⊆ ⊢L · ⊢subst Σ ⊢ρ M⊆ ⊢M
where
L⊆ = trans-⊆ ⊆-++₁ ⊆xs
M⊆ = trans-⊆ ⊆-++₂ ⊆xs
-}
\end{code}
### Substitution preserves types, specific case
\begin{code}
infixl 5 _//_
_//_ : Env → List Id → Env
Γ // [] = Γ
ε // (y ∷ ys) = ε
(Γ , x ⦂ A) // (y ∷ ys) with x ≟ y
... | yes _ = Γ // ys , x ⦂ A
... | no _ = Γ // ys
//-lemma : ∀ {Γ xs} → dom (Γ // xs) ≡ xs
//-lemma = {!!}
⊢stronger : ∀ {Γ ys M A}
→ free M ⊆ ys
→ Γ ⊢ M ⦂ A
-------------------
→ Γ // ys ⊢ M ⦂ A
⊢stronger = {!!}
⊢weaker : ∀ {Γ ys M A}
→ free M ⊆ ys
→ Γ // ys ⊢ M ⦂ A
---------------
→ Γ ⊢ M ⦂ A
⊢weaker = {!!}
⊢substitution₀ : ∀ {Δ x A N B M}
→ dom Δ ⊆ free M ++ (free N \\ x)
→ Δ , x ⦂ A ⊢ N ⦂ B
→ Δ ⊢ M ⦂ A
---------------------
→ Δ ⊢ N [ x := M ] ⦂ B
⊢substitution₀ = {!!}
{-
⊢substitution : ∀ {Γ x A N B M}
→ Γ , x ⦂ A ⊢ N ⦂ B
→ Γ ⊢ M ⦂ A
--------------------
→ Γ ⊢ N [ x := M ] ⦂ B
⊢substitution {Γ} {x} {A} {N} {B} {M} ⊢N ⊢M =
⊢weaker {Γ} {ys} ⊆N[x:=M]
(⊢substitution₀
(refl-⊆ (//-lemma {Γ} {ys}))
(⊢stronger {Γ , x ⦂ A} {x ∷ ys} ⊆N ⊢N)
(⊢stronger {Γ} {ys} ⊆M ⊢M))
where
ys = free M ++ (free N \\ x)
⊆N : free N ⊆ x ∷ ys
⊆N = ?
⊆M : free M ⊆ ys
⊆M = ?
⊆N[x:=M] : free (N [ x := M ]) ⊆ ys
⊆N[x:=M] = ?
-}
{-
⊢substitution : ∀ {Γ x A N B M} →
Γ , x ⦂ A ⊢ N ⦂ B →
Γ ⊢ M ⦂ A →
--------------------
Γ ⊢ N [ x := M ] ⦂ B
⊢substitution {Γ} {x} {A} {N} {B} {M} ⊢N ⊢M =
subst {Γ′ , x ⦂ A} {Γ′} {ys} {ρ} Σ ⊢ρ ⊢N
where
ys = free M ++ (free N \\ x)
Δ = Γ // ys
⊢N = rename {Γ , x ⦂ A} {Δ , x ⦂ A} ? ⊢N
⊢M = rename {Γ} {Δ} ? ⊢M
-- rename is no longer sufficiently powerful
-- it can do weakening but not strengthening
-- not clear where and how def'n of ys gets used
⊢subst {Γ′} {Γ} {xs} {ys} {ρ} Σ ⊢ρ {N} {B} ⊆xs ⊢N
where
Γ′ = Γ , x ⦂ A
xs = free N
ρ = ∅ , x ↦ M
Σ : ∀ {w} → w ∈ xs → free (ρ w) ⊆ ys
Σ {w} w∈ y∈ with w ≟ x
... | yes _ = ⊆-++₁ y∈
... | no w≢ rewrite ∈-[_] y∈ = ⊆-++₂ (∈-≢-to-\\ w∈ w≢)
⊢ρ : ∀ {w B} → w ∈ xs → Γ′ ∋ w ⦂ B → Γ ⊢ ρ w ⦂ B
⊢ρ {w} w∈ Z with w ≟ x
... | yes _ = ⊢M
... | no w≢ = ⊥-elim (w≢ refl)
⊢ρ {w} w∈ (S w≢ ⊢w) with w ≟ x
... | yes refl = ⊥-elim (w≢ refl)
... | no _ = ` ⊢w
⊆xs : free N ⊆ xs
⊆xs x∈ = x∈
-}
{-
⊢substitution : ∀ {Γ x A N B M} →
Γ , x ⦂ A ⊢ N ⦂ B →
Γ ⊢ M ⦂ A →
--------------------
Γ ⊢ N [ x := M ] ⦂ B
⊢substitution {Γ} {x} {A} {N} {B} {M} ⊢N ⊢M =
subst {Γ′ , x ⦂ A} {Γ′} {ys} {ρ} Σ ⊢ρ ⊢N
where
ys = free M ++ (free N \\ x)
Γ′ = Γ // ys
⊢N = rename {Γ , x ⦂ A} {Γ′ , x ⦂ A} ? ⊢N
⊢M = rename {Γ} {Γ′} ? ⊢M
-- rename is no longer sufficiently powerful
-- it can do weakening but not strengthening
-- not clear where and how def'n of ys gets used
⊢subst {Γ′} {Γ} {xs} {ys} {ρ} Σ ⊢ρ {N} {B} ⊆xs ⊢N
where
Γ′ = Γ , x ⦂ A
xs = free N
ρ = ∅ , x ↦ M
Σ : ∀ {w} → w ∈ xs → free (ρ w) ⊆ ys
Σ {w} w∈ y∈ with w ≟ x
... | yes _ = ⊆-++₁ y∈
... | no w≢ rewrite ∈-[_] y∈ = ⊆-++₂ (∈-≢-to-\\ w∈ w≢)
⊢ρ : ∀ {w B} → w ∈ xs → Γ′ ∋ w ⦂ B → Γ ⊢ ρ w ⦂ B
⊢ρ {w} w∈ Z with w ≟ x
... | yes _ = ⊢M
... | no w≢ = ⊥-elim (w≢ refl)
⊢ρ {w} w∈ (S w≢ ⊢w) with w ≟ x
... | yes refl = ⊥-elim (w≢ refl)
... | no _ = ` ⊢w
⊆xs : free N ⊆ xs
⊆xs x∈ = x∈
-}
{-
⊢substitution : ∀ {Γ x A N B M} →
Γ , x ⦂ A ⊢ N ⦂ B →
Γ ⊢ M ⦂ A →
--------------------
Γ ⊢ N [ x := M ] ⦂ B
⊢substitution {Γ} {x} {A} {N} {B} {M} ⊢N ⊢M =
⊢subst {Γ′} {Γ} {xs} {ys} {ρ} Σ ⊢ρ {N} {B} ⊆xs ⊢N
where
Γ′ = Γ , x ⦂ A
xs = free N
ys = free M ++ (free N \\ x)
ρ = ∅ , x ↦ M
Σ : ∀ {w} → w ∈ xs → free (ρ w) ⊆ ys
Σ {w} w∈ y∈ with w ≟ x
... | yes _ = ⊆-++₁ y∈
... | no w≢ rewrite ∈-[_] y∈ = ⊆-++₂ (∈-≢-to-\\ w∈ w≢)
⊢ρ : ∀ {w B} → w ∈ xs → Γ′ ∋ w ⦂ B → Γ ⊢ ρ w ⦂ B
⊢ρ {w} w∈ Z with w ≟ x
... | yes _ = ⊢M
... | no w≢ = ⊥-elim (w≢ refl)
⊢ρ {w} w∈ (S w≢ ⊢w) with w ≟ x
... | yes refl = ⊥-elim (w≢ refl)
... | no _ = ` ⊢w
⊆xs : free N ⊆ xs
⊆xs x∈ = x∈
-}
\end{code}
### Preservation
\begin{code}
{-
preservation : ∀ {Γ M N A}
→ Γ ⊢ M ⦂ A
→ M ⟶ N
---------
→ Γ ⊢ N ⦂ A
preservation (` ⊢x) ()
preservation (`λ ⊢N) ()
preservation (⊢L · ⊢M) (ξ-⟹₁ L⟶L) = preservation ⊢L L⟶L · ⊢M
preservation (⊢V · ⊢M) (ξ-⟹₂ valV M⟶M) = ⊢V · preservation ⊢M M⟶M
preservation ((`λ ⊢N) · ⊢W) (β-⟹ valW) = ⊢substitution ⊢N ⊢W
-}
\end{code}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,387 +0,0 @@
---
title : "Maps: Total and Partial Maps"
layout : page
permalink : /Maps
---
Maps (or dictionaries) are ubiquitous data structures, both in software
construction generally and in the theory of programming languages in particular;
we're going to need them in many places in the coming chapters. They also make
a nice case study using ideas we've seen in previous chapters, including
building data structures out of higher-order functions (from [Basics]({{
"Basics" | relative_url }}) and [Poly]({{ "Poly" | relative_url }}) and the use
of reflection to streamline proofs (from [IndProp]({{ "IndProp" | relative_url
}})).
We'll define two flavors of maps: _total_ maps, which include a
"default" element to be returned when a key being looked up
doesn't exist, and _partial_ maps, which return an `Maybe` to
indicate success or failure. The latter is defined in terms of
the former, using `nothing` as the default element.
## The Agda Standard Library
One small digression before we start.
Unlike the chapters we have seen so far, this one does not
import the chapter before it (and, transitively, all the
earlier chapters). Instead, in this chapter and from now, on
we're going to import the definitions and theorems we need
directly from Agda's standard library. You should not notice
much difference, though, because we've been careful to name our
own definitions and theorems the same as their counterparts in the
standard library, wherever they overlap.
\begin{code}
open import Data.Nat using ()
open import Data.Empty using (⊥; ⊥-elim)
open import Data.Maybe using (Maybe; just; nothing)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Binary.PropositionalEquality
using (_≡_; refl; _≢_; trans; sym)
\end{code}
Documentation for the standard library can be found at
<https://agda.github.io/agda-stdlib/>.
## Identifiers
First, we need a type for the keys that we use to index into our
maps. For this purpose, we again use the type `Id` from the
[Lists](sf/Lists.html) chapter. To make this chapter self contained,
we repeat its definition here.
\begin{code}
data Id : Set where
id : → Id
\end{code}
We recall a standard fact of logic.
\begin{code}
contrapositive : ∀ {ℓ₁ ℓ₂} {P : Set ℓ₁} {Q : Set ℓ₂} → (P → Q) → (¬ Q → ¬ P)
contrapositive p→q ¬q p = ¬q (p→q p)
\end{code}
Using the above, we can decide equality of two identifiers
by deciding equality on the underlying strings.
\begin{code}
_≟_ : (x y : Id) → Dec (x ≡ y)
id x ≟ id y with x Data.Nat.≟ y
id x ≟ id y | yes refl = yes refl
id x ≟ id y | no x≢y = no (contrapositive id-inj x≢y)
where
id-inj : ∀ {x y} → id x ≡ id y → x ≡ y
id-inj refl = refl
\end{code}
## Total Maps
Our main job in this chapter will be to build a definition of
partial maps that is similar in behavior to the one we saw in the
[Lists](sf/Lists.html) chapter, plus accompanying lemmas about their
behavior.
This time around, though, we're going to use _functions_, rather
than lists of key-value pairs, to build maps. The advantage of
this representation is that it offers a more _extensional_ view of
maps, where two maps that respond to queries in the same way will
be represented as literally the same thing (the same function),
rather than just "equivalent" data structures. This, in turn,
simplifies proofs that use maps.
We build partial maps in two steps. First, we define a type of
_total maps_ that return a default value when we look up a key
that is not present in the map.
\begin{code}
TotalMap : Set → Set
TotalMap A = Id → A
\end{code}
Intuitively, a total map over anfi element type `A` _is_ just a
function that can be used to look up ids, yielding `A`s.
\begin{code}
module TotalMap where
\end{code}
The function `always` yields a total map given a
default element; this map always returns the default element when
applied to any id.
\begin{code}
always : ∀ {A} → A → TotalMap A
always v x = v
\end{code}
More interesting is the update function, which (as before) takes
a map `ρ`, a key `x`, and a value `v` and returns a new map that
takes `x` to `v` and takes every other key to whatever `ρ` does.
\begin{code}
infixl 15 _,_↦_
_,_↦_ : ∀ {A} → TotalMap A → Id → A → TotalMap A
(ρ , x ↦ v) y with x ≟ y
... | yes x≡y = v
... | no x≢y = ρ y
\end{code}
This definition is a nice example of higher-order programming.
The update function takes a _function_ `ρ` and yields a new
function that behaves like the desired map.
For example, we can build a map taking ids to naturals, where `x`
maps to 42, `y` maps to 69, and every other key maps to 0, as follows:
\begin{code}
module example where
x y z : Id
x = id 0
y = id 1
z = id 2
ρ₀ : TotalMap
ρ₀ = always 0 , x ↦ 42 , y ↦ 69
test₁ : ρ₀ x ≡ 42
test₁ = refl
test₂ : ρ₀ y ≡ 69
test₂ = refl
test₃ : ρ₀ z ≡ 0
test₃ = refl
\end{code}
This completes the definition of total maps. Note that we don't
need to define a `find` operation because it is just function
application!
To use maps in later chapters, we'll need several fundamental
facts about how they behave. Even if you don't work the following
exercises, make sure you understand the statements of
the lemmas!
#### Exercise: 1 star, optional (apply-always)
The `always` map returns its default element for all keys:
\begin{code}
postulate
apply-always : ∀ {A} (v : A) (x : Id) → always v x ≡ v
\end{code}
<div class="hidden">
\begin{code}
apply-always : ∀ {A} (v : A) (x : Id) → always v x ≡ v
apply-always v x = refl
\end{code}
</div>
#### Exercise: 2 stars, optional (update-eq)
Next, if we update a map `ρ` at a key `x` with a new value `v`
and then look up `x` in the map resulting from the update, we get
back `v`:
\begin{code}
postulate
update-eq : ∀ {A} (ρ : TotalMap A) (x : Id) (v : A)
→ (ρ , x ↦ v) x ≡ v
\end{code}
<div class="hidden">
\begin{code}
update-eq : ∀ {A} (ρ : TotalMap A) (x : Id) (v : A)
→ (ρ , x ↦ v) x ≡ v
update-eq ρ x v with x ≟ x
... | yes x≡x = refl
... | no x≢x = ⊥-elim (x≢x refl)
\end{code}
</div>
#### Exercise: 2 stars, optional (update-neq)
On the other hand, if we update a map `m` at a key `x` and
then look up a _different_ key `y` in the resulting map, we get
the same result that `m` would have given:
\begin{code}
update-neq : ∀ {A} (ρ : TotalMap A) (x : Id) (v : A) (y : Id)
→ x ≢ y → (ρ , x ↦ v) y ≡ ρ y
update-neq ρ x v y x≢y with x ≟ y
... | yes x≡y = ⊥-elim (x≢y x≡y)
... | no _ = refl
\end{code}
For the following lemmas, since maps are represented by functions, to
show two maps equal we will need to postulate extensionality.
\begin{code}
postulate
extensionality : ∀ {A : Set} {ρ ρ : TotalMap A} → (∀ x → ρ x ≡ ρ x) → ρρ
\end{code}
#### Exercise: 2 stars, optional (update-shadow)
If we update a map `ρ` at a key `x` with a value `v` and then
update again with the same key `x` and another value `w`, the
resulting map behaves the same (gives the same result when applied
to any key) as the simpler map obtained by performing just
the second update on `ρ`:
\begin{code}
postulate
update-shadow : ∀ {A} (ρ : TotalMap A) (x : Id) (v w : A)
→ (ρ , x ↦ v , x ↦ w) ≡ (ρ , x ↦ w)
\end{code}
<div class="hidden">
\begin{code}
update-shadow : ∀ {A} (ρ : TotalMap A) (x : Id) (v w : A)
→ ((ρ , x ↦ v) , x ↦ w) ≡ (ρ , x ↦ w)
update-shadow ρ x v w = extensionality lemma
where
lemma : ∀ y → ((ρ , x ↦ v) , x ↦ w) y ≡ (ρ , x ↦ w) y
lemma y with x ≟ y
... | yes refl = refl
... | no x≢y = update-neq ρ x v y x≢y
\end{code}
</div>
#### Exercise: 2 stars (update-same)
Prove the following theorem, which states that if we update a map `ρ` to
assign key `x` the same value as it already has in `ρ`, then the
result is equal to `ρ`:
\begin{code}
postulate
update-same : ∀ {A} (ρ : TotalMap A) (x : Id) → (ρ , x ↦ ρ x) ≡ ρ
\end{code}
<div class="hidden">
\begin{code}
update-same : ∀ {A} (ρ : TotalMap A) (x : Id) → (ρ , x ↦ ρ x) ≡ ρ
update-same ρ x = extensionality lemma
where
lemma : ∀ y → (ρ , x ↦ ρ x) y ≡ ρ y
lemma y with x ≟ y
... | yes refl = refl
... | no x≢y = refl
\end{code}
</div>
#### Exercise: 3 stars, recommended (update-permute)
Prove one final property of the `update` function: If we update a map
`m` at two distinct keys, it doesn't matter in which order we do the
updates.
\begin{code}
postulate
update-permute : ∀ {A} (ρ : TotalMap A) (x : Id) (v : A) (y : Id) (w : A)
→ x ≢ y → (ρ , x ↦ v , y ↦ w) ≡ (ρ , y ↦ w , x ↦ v)
\end{code}
<div class="hidden">
\begin{code}
update-permute : ∀ {A} (ρ : TotalMap A) (x : Id) (v : A) (y : Id) (w : A)
→ x ≢ y → (ρ , x ↦ v , y ↦ w) ≡ (ρ , y ↦ w , x ↦ v)
update-permute {A} ρ x v y w x≢y = extensionality lemma
where
lemma : ∀ z → (ρ , x ↦ v , y ↦ w) z ≡ (ρ , y ↦ w , x ↦ v) z
lemma z with x ≟ z | y ≟ z
... | yes refl | yes refl = ⊥-elim (x≢y refl)
... | no x≢z | yes refl = sym (update-eq ρ z w)
... | yes refl | no y≢z = update-eq ρ z v
... | no x≢z | no y≢z = trans (update-neq ρ x v z x≢z)
(sym (update-neq ρ y w z y≢z))
\end{code}
And a slightly different version of the same proof.
\begin{code}
update-permute : ∀ {A} (ρ : TotalMap A) (x : Id) (v : A) (y : Id) (w : A) (z : Id)
→ x ≢ y → (ρ , x ↦ v , y ↦ w) z ≡ (ρ , y ↦ w , x ↦ v) z
update-permute {A} ρ x v y w z x≢y with x ≟ z | y ≟ z
... | yes x≡z | yes y≡z = ⊥-elim (x≢y (trans x≡z (sym y≡z)))
... | no x≢z | yes y≡z rewrite y≡z = sym (update-eq ρ z w)
... | yes x≡z | no y≢z rewrite x≡z = update-eq ρ z v
... | no x≢z | no y≢z = trans (update-neq ρ x v z x≢z)
(sym (update-neq ρ y w z y≢z))
\end{code}
</div>
## Partial maps
Finally, we define _partial maps_ on top of total maps. A partial
map with elements of type `A` is simply a total map with elements
of type `Maybe A` and default element `nothing`.
\begin{code}
PartialMap : Set → Set
PartialMap A = TotalMap (Maybe A)
\end{code}
\begin{code}
module PartialMap where
\end{code}
\begin{code}
∅ : ∀ {A} → PartialMap A
∅ = TotalMap.always nothing
\end{code}
\begin{code}
infixl 15 _,_↦_
_,_↦_ : ∀ {A} (ρ : PartialMap A) (x : Id) (v : A) → PartialMap A
ρ , x ↦ v = TotalMap._,_↦_ ρ x (just v)
\end{code}
We now lift all of the basic lemmas about total maps to partial maps.
\begin{code}
apply-∅ : ∀ {A} → (x : Id) → (∅ {A} x) ≡ nothing
apply-∅ x = TotalMap.apply-always nothing x
\end{code}
\begin{code}
update-eq : ∀ {A} (ρ : PartialMap A) (x : Id) (v : A)
→ (ρ , x ↦ v) x ≡ just v
update-eq ρ x v = TotalMap.update-eq ρ x (just v)
\end{code}
\begin{code}
update-neq : ∀ {A} (ρ : PartialMap A) (x : Id) (v : A) (y : Id)
→ x ≢ y → (ρ , x ↦ v) y ≡ ρ y
update-neq ρ x v y x≢y = TotalMap.update-neq ρ x (just v) y x≢y
\end{code}
\begin{code}
update-shadow : ∀ {A} (ρ : PartialMap A) (x : Id) (v w : A)
→ (ρ , x ↦ v , x ↦ w) ≡ (ρ , x ↦ w)
update-shadow ρ x v w = TotalMap.update-shadow ρ x (just v) (just w)
\end{code}
\begin{code}
update-same : ∀ {A} (ρ : PartialMap A) (x : Id) (v : A)
ρ x ≡ just v
→ (ρ , x ↦ v) ≡ ρ
update-same ρ x v ρx≡v rewrite sym ρx≡v = TotalMap.update-same ρ x
\end{code}
\begin{code}
update-permute : ∀ {A} (ρ : PartialMap A) (x : Id) (v : A) (y : Id) (w : A)
→ x ≢ y → (ρ , x ↦ v , y ↦ w) ≡ (ρ , y ↦ w , x ↦ v)
update-permute ρ x v y w x≢y = TotalMap.update-permute ρ x (just v) y (just w) x≢y
\end{code}
We will also need the following basic facts about the `Maybe` type.
\begin{code}
just≢nothing : ∀ {X : Set} → ∀ {x : X} → ¬ (_≡_ {A = Maybe X} (just x) nothing)
just≢nothing ()
just-injective : ∀ {X : Set} {x y : X} → _≡_ {A = Maybe X} (just x) (just y) → x ≡ y
just-injective refl = refl
\end{code}

View file

@ -1,47 +0,0 @@
Three possible formulations of `μ`
μ N —→ N [ μ N ]
(μ N) · V —→ N [ μ N , V ]
(μ (ƛ N)) · V —→ N [ μ (ƛ N) , V ]
The first is odd in that we substitute for `f` a term that is not a value.
One advantage of the first is that it also works perfectly well on other types.
For instance,
case (μ x → suc x) [zero→ zero | suc x → x]
returns (μ x → suc x).
The second has two values of function type, both lambda abstractions and fixpoints.
What if the body of μ must first reduce to a value? Two cases.
Value is a lambda.
(μ f → N) · V
—→ (μ f → ƛ x → N) · V
—→ (ƛ x → N) [ f := μ f → ƛ x → N ] · V
—→ (ƛ x → N [ f := μ f → ƛ x → N ]) · V
—→ N [ f := μ f → ƛ x → N , x := V ]
Value is itself a mu.
(μ f → μ g → N) · V
—→ (μ f → μ g → N) · V
—→ (μ f → μ g → λ x → N″) · V
—→ (μ g → λ x → N″) [ f := μ f → μ g → λ x → N″ ] · V
—→ (μ g → λ x → N″ [ f := μ f → μ g → λ x → N″ ]) · V
—→ (λ x → N″ [ f := μ f → μ g → λ x → N″ ])
[ g := μ g → λ x → N″ [ f := μ f → μ g → λ x → N″ ] · V
—→ (λ x → N″ [ f := μ f → μ g → λ x → N″ ]
[ g := μ g → λ x → N″ [ f := μ f → μ g → λ x → N″ ]) · V
—→ N″ [ f := μ f → μ g → λ x → N″ ]
[ g := μ g → λ x → N″ [ f := μ f → μ g → λ x → N″ ]
[ x := V ]
This is something you would *never* want to do, because f and g are
bound to the same function. Better to avoid it by building functions
into the syntax, I expect.

Some files were not shown because too many files have changed in this diff Show more