diff --git a/TSPL/2024/Assignment3/index.html b/TSPL/2024/Assignment3/index.html index 83aa1db03..919fdc424 100644 --- a/TSPL/2024/Assignment3/index.html +++ b/TSPL/2024/Assignment3/index.html @@ -14,153 +14,152 @@ open import plfa.part1.Isomorphism using (_≃_; _⇔_)
open import plfa.part1.Lists hiding (downFrom; Tree; leaf; node; merge) -
reverse-++-distrib
(practice) (recommended)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
reverse-involutive
(practice) (recommended)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
map-compose
(practice)Prove that the map of a composition is equal to the composition of two maps:
map (g ∘ f) ≡ map g ∘ map f
The last step of the proof requires extensionality.
-- Your code goes here -
map-++-distribute
(practice)Prove the following relationship between map and append:
map f (xs ++ ys) ≡ map f xs ++ map f ys
-- Your code goes here -
map-Tree
(practice)A
and internal nodes of type B
:data Tree (A B : Set) : Set where - leaf : A → Tree A B - node : Tree A B → B → Tree A B → Tree A B -
Define a suitable map operator over trees:
map-Tree : ∀ {A B C D : Set} → (A → C) → (B → D) → Tree A B → Tree C D
-- Your code goes here -
product
(practice) (was recommended)Use fold to define a function to find the product of a list of numbers. For example:
product [ 1 , 2 , 3 , 4 ] ≡ 24
-- Your code goes here -
foldr-++
(practice) (was recommended)Show that fold and append are related as follows:
foldr _⊗_ e (xs ++ ys) ≡ foldr _⊗_ (foldr _⊗_ e ys) xs
-- Your code goes here -
foldr-∷
(practice)Show
foldr _∷_ [] xs ≡ xs
Show as a consequence of foldr-++
above that
xs ++ ys ≡ foldr _∷_ ys xs
-- Your code goes here -
map-is-foldr
(practice)Show that map can be defined using fold:
map f ≡ foldr (λ x xs → f x ∷ xs) []
The proof requires extensionality.
-- Your code goes here -
fold-Tree
(practice)Define a suitable fold function for the type of trees given earlier:
fold-Tree : ∀ {A B C : Set} → (A → C) → (C → B → C → C) → Tree A B → C
-- Your code goes here -
map-is-fold-Tree
(practice)Demonstrate an analogue of map-is-foldr
for the type of trees.
-- Your code goes here -
sum-downFrom
(practice) (was stretch)downFrom : ℕ → List ℕ - downFrom zero = [] - downFrom (suc n) = n ∷ downFrom n -For example:
_ : downFrom 3 ≡ [ 2 , 1 , 0 ] - _ = refl -
Prove that the sum of the numbers (n - 1) + ⋯ + 0
is equal to n * (n ∸ 1) / 2
:
sum (downFrom n) * 2 ≡ n * (n ∸ 1)
-- Your code goes here +
reverse-++-distrib
(recommended)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
reverse-involutive
(recommended)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
map-compose
(practice)Prove that the map of a composition is equal to the composition of two maps:
map (g ∘ f) ≡ map g ∘ map f
The last step of the proof requires extensionality.
-- Your code goes here +
map-++-distribute
(practice)Prove the following relationship between map and append:
map f (xs ++ ys) ≡ map f xs ++ map f ys
-- Your code goes here +
map-Tree
(practice)A
and internal nodes of type B
:data Tree (A B : Set) : Set where + leaf : A → Tree A B + node : Tree A B → B → Tree A B → Tree A B +
Define a suitable map operator over trees:
map-Tree : ∀ {A B C D : Set} → (A → C) → (B → D) → Tree A B → Tree C D
-- Your code goes here +
product
(recommended)Use fold to define a function to find the product of a list of numbers. For example:
product [ 1 , 2 , 3 , 4 ] ≡ 24
-- Your code goes here +
foldr-++
(recommended)Show that fold and append are related as follows:
foldr _⊗_ e (xs ++ ys) ≡ foldr _⊗_ (foldr _⊗_ e ys) xs
-- Your code goes here +
foldr-∷
(practice)Show
foldr _∷_ [] xs ≡ xs
Show as a consequence of foldr-++
above that
xs ++ ys ≡ foldr _∷_ ys xs
-- Your code goes here +
map-is-foldr
(practice)Show that map can be defined using fold:
map f ≡ foldr (λ x xs → f x ∷ xs) []
The proof requires extensionality.
-- Your code goes here +
fold-Tree
(practice)Define a suitable fold function for the type of trees given earlier:
fold-Tree : ∀ {A B C : Set} → (A → C) → (C → B → C → C) → Tree A B → C
-- Your code goes here +
map-is-fold-Tree
(practice)Demonstrate an analogue of map-is-foldr
for the type of trees.
-- Your code goes here +
sum-downFrom
(stretch)downFrom : ℕ → List ℕ + downFrom zero = [] + downFrom (suc n) = n ∷ downFrom n +For example:
_ : downFrom 3 ≡ [ 2 , 1 , 0 ] + _ = refl +
Prove that the sum of the numbers (n - 1) + ⋯ + 0
is equal to n * (n ∸ 1) / 2
:
sum (downFrom n) * 2 ≡ n * (n ∸ 1)
-- Your code goes here
foldl
(practice)Define a function foldl
which is analogous to foldr
, but where operations associate to the left rather than the right. For example:
foldr _⊗_ e [ x , y , z ] = x ⊗ (y ⊗ (z ⊗ e))
-foldl _⊗_ e [ x , y , z ] = ((e ⊗ x) ⊗ y) ⊗ z
-- Your code goes here -
foldr-monoid-foldl
(practice)Show that if _⊗_
and e
form a monoid, then foldr _⊗_ e
and foldl _⊗_ e
always compute the same result.
-- Your code goes here -
Any-++-⇔
(practice) (was recommended)Prove a result similar to All-++-⇔
, but with Any
in place of All
, and a suitable replacement for _×_
. As a consequence, demonstrate an equivalence relating _∈_
and _++_
.
-- Your code goes here -
All-++-≃
(practice) (was stretch)Show that the equivalence All-++-⇔
can be extended to an isomorphism.
-- Your code goes here -
¬Any⇔All¬
(practice) (was recommended)Show that Any
and All
satisfy a version of De Morgan’s Law:
(¬_ ∘ Any P) xs ⇔ All (¬_ ∘ P) xs
(Can you see why it is important that here _∘_
is generalised to arbitrary levels, as described in the section on universe polymorphism?)
Do we also have the following?
(¬_ ∘ All P) xs ⇔ Any (¬_ ∘ P) xs
If so, prove; if not, explain why.
-- Your code goes here -
¬Any≃All¬
(practice) (was stretch)Show that the equivalence ¬Any⇔All¬
can be extended to an isomorphism. You will need to use extensionality.
-- Your code goes here -
All-∀
(practice)Show that All P xs
is isomorphic to ∀ x → x ∈ xs → P x
.
-- You code goes here -
Any-∃
(practice)Show that Any P xs
is isomorphic to ∃[ x ] (x ∈ xs × P x)
.
-- You code goes here -
Any?
(practice) (was stretch)Just as All
has analogues all
and All?
which determine whether a predicate holds for every element of a list, so does Any
have analogues any
and Any?
which determine whether a predicate holds for some element of a list. Give their definitions.
-- Your code goes here -
split
(practice) (was stretch)merge
holds when two lists merge to give a third list.data merge {A : Set} : (xs ys zs : List A) → Set where +foldl _⊗_ e [ x , y , z ] = ((e ⊗ x) ⊗ y) ⊗ z
-- Your code goes here +
foldr-monoid-foldl
(practice)Show that if _⊗_
and e
form a monoid, then foldr _⊗_ e
and foldl _⊗_ e
always compute the same result.
-- Your code goes here +
Any-++-⇔
(recommended)Prove a result similar to All-++-⇔
, but with Any
in place of All
, and a suitable replacement for _×_
. As a consequence, demonstrate an equivalence relating _∈_
and _++_
.
-- Your code goes here +
All-++-≃
(stretch)Show that the equivalence All-++-⇔
can be extended to an isomorphism.
-- Your code goes here +
¬Any⇔All¬
(recommended)Show that Any
and All
satisfy a version of De Morgan’s Law:
(¬_ ∘ Any P) xs ⇔ All (¬_ ∘ P) xs
(Can you see why it is important that here _∘_
is generalised to arbitrary levels, as described in the section on universe polymorphism?)
Do we also have the following?
(¬_ ∘ All P) xs ⇔ Any (¬_ ∘ P) xs
If so, prove; if not, explain why.
-- Your code goes here +
¬Any≃All¬
(stretch)Show that the equivalence ¬Any⇔All¬
can be extended to an isomorphism. You will need to use extensionality.
-- Your code goes here +
All-∀
(practice)Show that All P xs
is isomorphic to ∀ x → x ∈ xs → P x
.
-- You code goes here +
Any-∃
(practice)Show that Any P xs
is isomorphic to ∃[ x ] (x ∈ xs × P x)
.
-- You code goes here +
Any?
(stretch)Just as All
has analogues all
and All?
which determine whether a predicate holds for every element of a list, so does Any
have analogues any
and Any?
which determine whether a predicate holds for some element of a list. Give their definitions.
-- Your code goes here +
split
(stretch)merge
holds when two lists merge to give a third list.data merge {A : Set} : (xs ys zs : List A) → Set where - [] : - -------------- - merge [] [] [] + [] : + -------------- + merge [] [] [] - left-∷ : ∀ {x xs ys zs} - → merge xs ys zs - -------------------------- - → merge (x ∷ xs) ys (x ∷ zs) + left-∷ : ∀ {x xs ys zs} + → merge xs ys zs + -------------------------- + → merge (x ∷ xs) ys (x ∷ zs) - right-∷ : ∀ {y xs ys zs} - → merge xs ys zs - -------------------------- - → merge xs (y ∷ ys) (y ∷ zs) -For example,
_ : merge [ 1 , 4 ] [ 2 , 3 ] [ 1 , 2 , 3 , 4 ] - _ = left-∷ (right-∷ (right-∷ (left-∷ []))) + right-∷ : ∀ {y xs ys zs} + → merge xs ys zs + -------------------------- + → merge xs (y ∷ ys) (y ∷ zs) +For example,
_ : merge [ 1 , 4 ] [ 2 , 3 ] [ 1 , 2 , 3 , 4 ] + _ = left-∷ (right-∷ (right-∷ (left-∷ [])))
Given a decidable predicate and a list, we can split the list into two lists that merge to give the original list, where all elements of one list satisfy the predicate, and all elements of the other do not satisfy the predicate.
Define the following variant of the traditional filter
function on lists, which given a decidable predicate and a list returns a list of elements that satisfy the predicate and a list of elements that don’t, with their corresponding proofs.
split : ∀ {A : Set} {P : A → Set} (P? : Decidable P) (zs : List A)
- → ∃[ xs ] ∃[ ys ] ( merge xs ys zs × All P xs × All (¬_ ∘ P) ys )
-- Your code goes here -
module Lambda where -
open import Data.Bool using (Bool; true; false; T; not) - open import Data.Empty using (⊥; ⊥-elim) - open import Data.List using (List; _∷_; []) - open import Data.Nat using (ℕ; zero; suc) - open import Data.Product using (∃-syntax; _×_) - open import Data.String using (String; _≟_) - open import Data.Unit using (tt) - open import Relation.Nullary using (Dec; yes; no; ¬_) - open import Relation.Nullary.Decidable using (False; toWitnessFalse) - open import Relation.Nullary.Negation using (¬?) - open import Relation.Binary.PropositionalEquality using (_≡_; _≢_; refl) -
open import plfa.part2.Lambda - hiding (var?; ƛ′_⇒_; case′_[zero⇒_|suc_⇒_]; μ′_⇒_; plus′) -
mul
(recommended)Write out the definition of a lambda term that multiplies two natural numbers. Your definition may use plus
as defined earlier.
-- Your code goes here -
mulᶜ
(practice)Write out the definition of a lambda term that multiplies two natural numbers represented as Church numerals. Your definition may use plusᶜ
as defined earlier (or may not — there are nice definitions both ways).
-- Your code goes here -
primed
(stretch)` "x"
instead of x
. We can make examples with lambda terms slightly easier to write by adding the following definitions:var? : (t : Term) → Bool - var? (` _) = true - var? _ = false + → ∃[ xs ] ∃[ ys ] ( merge xs ys zs × All P xs × All (¬_ ∘ P) ys )
-- Your code goes here +
module Lambda where +
open import Data.Bool using (Bool; true; false; T; not) + open import Data.Empty using (⊥; ⊥-elim) + open import Data.List using (List; _∷_; []) + open import Data.Nat using (ℕ; zero; suc) + open import Data.Product using (∃-syntax; _×_) + open import Data.String using (String; _≟_) + open import Data.Unit using (tt) + open import Relation.Nullary using (Dec; yes; no; ¬_) + open import Relation.Nullary.Decidable using (False; toWitnessFalse; ¬?) + open import Relation.Binary.PropositionalEquality using (_≡_; _≢_; refl) +
open import plfa.part2.Lambda + hiding (var?; ƛ′_⇒_; case′_[zero⇒_|suc_⇒_]; μ′_⇒_; plus′) +
mul
(recommended)Write out the definition of a lambda term that multiplies two natural numbers. Your definition may use plus
as defined earlier.
-- Your code goes here +
mulᶜ
(practice)Write out the definition of a lambda term that multiplies two natural numbers represented as Church numerals. Your definition may use plusᶜ
as defined earlier (or may not — there are nice definitions both ways).
-- Your code goes here +
primed
(stretch)` "x"
instead of x
. We can make examples with lambda terms slightly easier to write by adding the following definitions:var? : (t : Term) → Bool + var? (` _) = true + var? _ = false - ƛ′_⇒_ : (t : Term) → {_ : T (var? t)} → Term → Term - ƛ′_⇒_ (` x) N = ƛ x ⇒ N + ƛ′_⇒_ : (t : Term) → {_ : T (var? t)} → Term → Term + ƛ′_⇒_ (` x) N = ƛ x ⇒ N - case′_[zero⇒_|suc_⇒_] : Term → Term → (t : Term) → {_ : T (var? t)} → Term → Term - case′ L [zero⇒ M |suc (` x) ⇒ N ] = case L [zero⇒ M |suc x ⇒ N ] + case′_[zero⇒_|suc_⇒_] : Term → Term → (t : Term) → {_ : T (var? t)} → Term → Term + case′ L [zero⇒ M |suc (` x) ⇒ N ] = case L [zero⇒ M |suc x ⇒ N ] - μ′_⇒_ : (t : Term) → {_ : T (var? t)} → Term → Term - μ′ (` x) ⇒ N = μ x ⇒ N + μ′_⇒_ : (t : Term) → {_ : T (var? t)} → Term → Term + μ′ (` x) ⇒ N = μ x ⇒ N
Recall that T
is a function that maps from the computation world to the evidence world, as defined in Chapter Decidable. We ensure to use the primed functions only when the respective term argument is a variable, which we do by providing implicit evidence. For example, if we tried to define an abstraction term that binds anything but a variable:
_ : Term
-_ = ƛ′ two ⇒ two
Agda would complain it cannot find a value of the bottom type for the implicit argument. Note the implicit argument’s type reduces to ⊥
when term t
is anything but a variable.
plus
can now be written as follows:plus′ : Term - plus′ = μ′ + ⇒ ƛ′ m ⇒ ƛ′ n ⇒ - case′ m - [zero⇒ n - |suc m ⇒ `suc (+ · m · n) ] - where - + = ` "+" - m = ` "m" - n = ` "n" -
Write out the definition of multiplication in the same style.
_[_:=_]′
(stretch)The definition of substitution above has three clauses (ƛ
, case
, and μ
) that invoke a with
clause to deal with bound variables. Rewrite the definition to factor the common part of these three clauses into a single function, defined by mutual recursion with substitution.
-- Your code goes here -
—↠≲—↠′
(practice)Show that the first notion of reflexive and transitive closure above embeds into the second. Why are they not isomorphic?
-- Your code goes here -
plus-example
(practice)Write out the reduction sequence demonstrating that one plus one is two.
-- Your code goes here -
Context-≃
(practice)Show that Context
is isomorphic to List (Id × Type)
. For instance, the isomorphism relates the context
∅ , "s" ⦂ `ℕ ⇒ `ℕ , "z" ⦂ `ℕ
to the list
[ ⟨ "z" , `ℕ ⟩ , ⟨ "s" , `ℕ ⇒ `ℕ ⟩ ]
-- Your code goes here -
⊢mul
(recommended)Using the term mul
you defined earlier, write out the derivation showing that it is well typed.
-- Your code goes here -
⊢mulᶜ
(practice)Using the term mulᶜ
you defined earlier, write out the derivation showing that it is well typed.
-- Your code goes here -
module Properties where -
open import Relation.Binary.PropositionalEquality - using (_≡_; _≢_; refl; sym; cong; cong₂) - 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 plfa.part1.Isomorphism - open import plfa.part2.Lambda -
open import plfa.part2.Properties - hiding (value?; Canonical_⦂_; unstuck; preserves; wttdgs) - -- open Lambda using (mul; ⊢mul) -
Canonical-≃
(practice)Value
relation that relates values to their types. A lambda expression must have a function type, and a zero or successor expression must be a natural. Further, the body of a function must be well typed in a context containing only its bound variable, and the argument of successor must itself be canonical:infix 4 Canonical_⦂_ +_ = ƛ′ two ⇒ two
Agda would complain it cannot find a value of the bottom type for the implicit argument. Note the implicit argument’s type reduces to ⊥
when term t
is anything but a variable.
plus
can now be written as follows:plus′ : Term + plus′ = μ′ + ⇒ ƛ′ m ⇒ ƛ′ n ⇒ + case′ m + [zero⇒ n + |suc m ⇒ `suc (+ · m · n) ] + where + + = ` "+" + m = ` "m" + n = ` "n" +
Write out the definition of multiplication in the same style.
_[_:=_]′
(stretch)The definition of substitution above has three clauses (ƛ
, case
, and μ
) that invoke a with
clause to deal with bound variables. Rewrite the definition to factor the common part of these three clauses into a single function, defined by mutual recursion with substitution.
-- Your code goes here +
—↠≲—↠′
(practice)Show that the first notion of reflexive and transitive closure above embeds into the second. Why are they not isomorphic?
-- Your code goes here +
plus-example
(practice)Write out the reduction sequence demonstrating that one plus one is two.
-- Your code goes here +
Context-≃
(practice)Show that Context
is isomorphic to List (Id × Type)
. For instance, the isomorphism relates the context
∅ , "s" ⦂ `ℕ ⇒ `ℕ , "z" ⦂ `ℕ
to the list
[ ⟨ "z" , `ℕ ⟩ , ⟨ "s" , `ℕ ⇒ `ℕ ⟩ ]
-- Your code goes here +
⊢mul
(recommended)Using the term mul
you defined earlier, write out the derivation showing that it is well typed.
-- Your code goes here +
⊢mulᶜ
(practice)Using the term mulᶜ
you defined earlier, write out the derivation showing that it is well typed.
-- Your code goes here +
module Properties where +
open import Relation.Binary.PropositionalEquality + using (_≡_; _≢_; refl; sym; cong; cong₂) + 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 plfa.part1.Isomorphism + open import plfa.part2.Lambda +
open import plfa.part2.Properties + hiding (value?; Canonical_⦂_; unstuck; preserves; wttdgs) + -- open Lambda using (mul; ⊢mul) +
Canonical-≃
(practice)Value
relation that relates values to their types. A lambda expression must have a function type, and a zero or successor expression must be a natural. Further, the body of a function must be well typed in a context containing only its bound variable, and the argument of successor must itself be canonical:infix 4 Canonical_⦂_ - data Canonical_⦂_ : Term → Type → Set where + data Canonical_⦂_ : Term → Type → Set where - C-ƛ : ∀ {x A N B} - → ∅ , x ⦂ A ⊢ N ⦂ B - ----------------------------- - → Canonical (ƛ x ⇒ N) ⦂ (A ⇒ B) + C-ƛ : ∀ {x A N B} + → ∅ , x ⦂ A ⊢ N ⦂ B + ----------------------------- + → Canonical (ƛ x ⇒ N) ⦂ (A ⇒ B) - C-zero : - -------------------- - Canonical `zero ⦂ `ℕ + C-zero : + -------------------- + Canonical `zero ⦂ `ℕ - C-suc : ∀ {V} - → Canonical V ⦂ `ℕ - --------------------- - → Canonical `suc V ⦂ `ℕ -
Show that Canonical V ⦂ A
is isomorphic to (∅ ⊢ V ⦂ A) × (Value V)
, that is, the canonical forms are exactly the well-typed values.
-- Your code goes here -
Progress-≃
(practice)Show that Progress M
is isomorphic to Value M ⊎ ∃[ N ](M —→ N)
.
-- Your code goes here -
progress′
(practice)Write out the proof of progress′
in full, and compare it to the proof of progress
above.
-- Your code goes here -
value?
(practice)progress
and —→¬V
to write a program that decides whether a well-typed term is a value:postulate - value? : ∀ {A M} → ∅ ⊢ M ⦂ A → Dec (Value M) -
subst′
(stretch)Rewrite subst
to work with the modified definition _[_:=_]′
from the exercise in the previous chapter. As before, this should factor dealing with bound variables into a single function, defined by mutual recursion with the proof that substitution preserves types.
-- Your code goes here -
mul-eval
(recommended)Using the evaluator, confirm that two times two is four.
-- Your code goes here -
progress-preservation
(practice)Without peeking at their statements above, write down the progress and preservation theorems for the simply typed lambda-calculus.
-- Your code goes here -
subject_expansion
(practice)We say that M
reduces to N
if M —→ N
, but we can also describe the same situation by saying that N
expands to M
. The preservation property is sometimes called subject reduction. Its opposite is subject expansion, which holds if M —→ N
and ∅ ⊢ N ⦂ A
imply ∅ ⊢ M ⦂ A
. Find two counter-examples to subject expansion, one with case expressions and one not involving case expressions.
-- Your code goes here -
stuck
(practice)Give an example of an ill-typed term that does get stuck.
-- Your code goes here -
unstuck
(recommended)Provide proofs of the three postulates, unstuck
, preserves
, and wttdgs
above.
-- Your code goes here -
module DeBruijn where -
import Relation.Binary.PropositionalEquality as Eq - open Eq using (_≡_; refl) - open import Data.Empty using (⊥; ⊥-elim) - open import Data.Nat using (ℕ; zero; suc; _<_; _≤?_; z≤n; s≤s) - open import Relation.Nullary using (¬_) - open import Relation.Nullary.Decidable using (True; toWitness) -
open import plfa.part2.DeBruijn - hiding () -
mul
(recommended)Write out the definition of a lambda term that multiplies two natural numbers, now adapted to the intrinsically-typed de Bruijn representation.
-- Your code goes here -
V¬—→
(practice)Following the previous development, show values do not reduce, and its corollary, terms that reduce are not values.
-- Your code goes here -
mul-example
(recommended)Using the evaluator, confirm that two times two is four.
-- Your code goes here + C-suc : ∀ {V} + → Canonical V ⦂ `ℕ + --------------------- + → Canonical `suc V ⦂ `ℕ +
Show that Canonical V ⦂ A
is isomorphic to (∅ ⊢ V ⦂ A) × (Value V)
, that is, the canonical forms are exactly the well-typed values.
-- Your code goes here +
Progress-≃
(practice)Show that Progress M
is isomorphic to Value M ⊎ ∃[ N ](M —→ N)
.
-- Your code goes here +
progress′
(practice)Write out the proof of progress′
in full, and compare it to the proof of progress
above.
-- Your code goes here +
value?
(practice)progress
and —→¬V
to write a program that decides whether a well-typed term is a value:postulate + value? : ∀ {A M} → ∅ ⊢ M ⦂ A → Dec (Value M) +
subst′
(stretch)Rewrite subst
to work with the modified definition _[_:=_]′
from the exercise in the previous chapter. As before, this should factor dealing with bound variables into a single function, defined by mutual recursion with the proof that substitution preserves types.
-- Your code goes here +
mul-eval
(recommended)Using the evaluator, confirm that two times two is four.
-- Your code goes here +
progress-preservation
(practice)Without peeking at their statements above, write down the progress and preservation theorems for the simply typed lambda-calculus.
-- Your code goes here +
subject_expansion
(practice)We say that M
reduces to N
if M —→ N
, but we can also describe the same situation by saying that N
expands to M
. The preservation property is sometimes called subject reduction. Its opposite is subject expansion, which holds if M —→ N
and ∅ ⊢ N ⦂ A
imply ∅ ⊢ M ⦂ A
. Find two counter-examples to subject expansion, one with case expressions and one not involving case expressions.
-- Your code goes here +
stuck
(practice)Give an example of an ill-typed term that does get stuck.
-- Your code goes here +
unstuck
(recommended)Provide proofs of the three postulates, unstuck
, preserves
, and wttdgs
above.
-- Your code goes here +
module DeBruijn where +
import Relation.Binary.PropositionalEquality as Eq + open Eq using (_≡_; refl) + open import Data.Empty using (⊥; ⊥-elim) + open import Data.Nat using (ℕ; zero; suc; _<_; _≤?_; z≤n; s≤s) + open import Relation.Nullary using (¬_) + open import Relation.Nullary.Decidable using (True; toWitness) +
open import plfa.part2.DeBruijn + hiding () +
mul
(recommended)Write out the definition of a lambda term that multiplies two natural numbers, now adapted to the intrinsically-typed de Bruijn representation.
-- Your code goes here +
V¬—→
(practice)Following the previous development, show values do not reduce, and its corollary, terms that reduce are not values.
-- Your code goes here +
mul-example
(recommended)Using the evaluator, confirm that two times two is four.
-- Your code goes here