Assignment 3

This commit is contained in:
wadler 2018-10-15 00:20:19 +01:00
parent a934950066
commit cc62c156ce
4 changed files with 423 additions and 44 deletions

View file

@ -28,7 +28,7 @@ open import Relation.Nullary using (¬_; Dec; yes; no)
open import Data.Product using (_×_) renaming (_,_ to ⟨_,_⟩)
open import Function using (_∘_)
open import Level using (Level)
open import plfa.Isomorphism using (_≃_)
open import plfa.Isomorphism using (_≃_; _⇔_)
\end{code}
@ -344,7 +344,7 @@ 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`
#### Exercise `reverse-++-commute` (recommended)
Show that the reverse of one list appended to another is the
reverse of the second appended to the reverse of the first.
@ -354,7 +354,7 @@ postulate
→ reverse (xs ++ ys) ≡ reverse ys ++ reverse xs
\end{code}
#### Exercise `reverse-involutive`
#### Exercise `reverse-involutive` (recommended)
A function is an _involution_ if when applied twice it acts
as the identity function. Show that reverse is an involution.
@ -766,6 +766,21 @@ foldr-monoid-++ _⊗_ e monoid-⊗ xs ys =
\end{code}
#### Exercise `foldl`
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
#### Exercise `foldr-monoid-foldl`
Show that if `_⊕_` and `e` form a monoid, then `foldr _⊗_ e` and
`foldl _⊗_ e` always compute the same result.
## All {#All}
We can also define predicates over lists. Two of the most important
@ -843,19 +858,15 @@ possible evidence for `3 ≡ 0`, `3 ≡ 1`, `3 ≡ 0`, `3 ≡ 2`, and
## 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.
only if it holds for every element of each list.
\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 =
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) →
@ -868,24 +879,18 @@ All-++ xs ys =
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-++`
#### Exercise `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 isomorphism relating
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 `_++_`.
#### Exercise `All-++-≃` (stetch)
Show that the equivalence `All-++-⇔` can be extended to an isomorphism.
#### Exercise `¬Any≃All¬` (stretch)
First generalise composition to arbitrary levels, using

View file

@ -342,7 +342,7 @@ Show that `Progress M` is isomorphic to `Value M ⊎ ∃[ N ](M —→ N)`.
Write out the proof of `progress` in full, and compare it to the
proof of `progress` above.
#### Exercise `value?`
#### Exercise `value?` (recommended)
Combine `progress` and `—→¬V` to write a program that decides
whether a well-typed term is a value.
@ -1249,11 +1249,29 @@ _ = refl
And again, the example in the previous section was derived by editing the
above.
#### Exercise `mul-example`
#### Exercise `mul-example` (recommended)
Using the evaluator, confirm that two times two is four.
#### Exercise: `progress-preservation` (recommended)
Without peeking at their statements above, write down the progress
and preservation theorems for the simply typed lambda-calculus.
#### Exercise `subject_expansion`
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.
## Well-typed terms don't get stuck
A term is _normal_ if it cannot reduce.
@ -1398,23 +1416,6 @@ checker complains, because the arguments have merely switched order
and neither is smaller.
#### Exercise: `progress-preservation`
Without peeking at their statements above, write down the progress
and preservation theorems for the simply typed lambda-calculus.
#### Exercise `subject_expansion`
We say that `M` _reduces_ to `N` if `M —→ N`,
and conversely 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` imply `∅ ⊢ M ⦂ A`.
Find two counter-examples to subject expansion, one
with case expressions and one not involving case expressions.
#### Quiz
Suppose we add a new term `zap` with the following reduction rule

373
tspl/Assignment3.lagda Normal file
View file

@ -0,0 +1,373 @@
---
title : "Assignment3: TSPL Assignment 3"
layout : page
permalink : /Assignment3/
---
\begin{code}
module Assignment3 where
\end{code}
## YOUR NAME AND EMAIL GOES HERE
## Introduction
This assignment is due **4pm Thursday 1 November** (Week 7).
You must do _all_ the exercises labelled "(recommended)".
Exercises labelled "(stretch)" are there to provide an extra challenge.
You don't need to do all of these, but should attempt at least a few.
Exercises without a label are optional, and may be done if you want
some extra practice.
Submit your homework using the "submit" command.
Please ensure your files execute correctly under Agda!
## Imports
\begin{code}
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; cong; sym)
open Eq.≡-Reasoning using (begin_; _≡⟨⟩_; _≡⟨_⟩_; _∎)
open import Data.Bool.Base using (Bool; true; false; T; _∧_; __; not)
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 (¬_; Dec; yes; no)
open import Data.Product using (_×_) renaming (_,_ to ⟨_,_⟩)
open import Data.Empty using (⊥; ⊥-elim)
open import Function using (_∘_)
open import Level using (Level)
open import plfa.Relations using (_<_; z<s; s<s)
open import plfa.Isomorphism using (_≃_; ≃-sym; ≃-trans; _≲_; extensionality)
open plfa.Isomorphism.≃-Reasoning
open import plfa.Lists using (List; []; _∷_; [_]; [_,_]; [_,_,_]; [_,_,_,_];
_++_; reverse; map; foldr; sum; Any; All; _∈_)
open import plfa.Lambda hiding (ƛ_⇒_; case_[zero⇒_|suc_⇒_]; μ_⇒_; plus)
open import plfa.Properties hiding (value?)
\end{code}
#### Exercise `reverse-++-commute` (recommended)
Show that the reverse of one list appended to another is the
reverse of the second appended to the reverse of the first.
\begin{code}
postulate
reverse-++-commute : ∀ {A : Set} {xs ys : List A}
→ reverse (xs ++ ys) ≡ reverse ys ++ reverse xs
\end{code}
#### Exercise `reverse-involutive` (recommended)
A function is an _involution_ if when applied twice it acts
as the identity function. Show that reverse is an involution.
\begin{code}
postulate
reverse-involutive : ∀ {A : Set} {xs : List A}
→ reverse (reverse xs) ≡ xs
\end{code}
#### Exercise `map-compose`
Prove that the map of a composition is equal to the composition of two maps.
\begin{code}
postulate
map-compose : ∀ {A B C : Set} {f : A → B} {g : B → C}
→ map (g ∘ f) ≡ map g ∘ map f
\end{code}
The last step of the proof requires extensionality.
#### Exercise `map-++-commute`
Prove the following relationship between map and append.
\begin{code}
postulate
map-++-commute : ∀ {A B : Set} {f : A → B} {xs ys : List A}
→ map f (xs ++ ys) ≡ map f xs ++ map f ys
\end{code}
#### Exercise `map-Tree`
Define a type of trees with leaves of type `A` and internal
nodes of type `B`.
\begin{code}
data Tree (A B : Set) : Set where
leaf : A → Tree A B
node : Tree A B → B → Tree A B → Tree A B
\end{code}
Define a suitabve map operator over trees.
\begin{code}
postulate
map-Tree : ∀ {A B C D : Set}
→ (A → C) → (B → D) → Tree A B → Tree C D
\end{code}
#### Exercise `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
#### Exercise `foldr-++` (recommended)
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 `fold-Tree`
Define a suitable fold function for the type of trees given earlier.
\begin{code}
postulate
fold-Tree : ∀ {A B C : Set}
→ (A → C) → (C → B → C → C) → Tree A B → C
\end{code}
#### Exercise `map-is-fold-Tree`
Demonstrate an anologue of `map-is-foldr` for the type of trees.
#### Exercise `sum-downFrom` (stretch)
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}
#### Exercise `foldl`
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
#### Exercise `foldr-monoid-foldl`
Show that if `_⊕_` and `e` form a monoid, then `foldr _⊗_ e` and
`foldl _⊗_ e` always compute the same result.
#### Exercise `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 `_++_`.
#### Exercise `All-++-≃` (stetch)
Show that the equivalence `All-++-⇔` can be extended to an isomorphism.
#### Exercise `¬Any≃All¬` (stretch)
First generalise composition to arbitrary levels, using
[universe polymorphism][plfa.Equality#unipoly].
\begin{code}
_∘_ : ∀ {ℓ₁ ℓ₂ ℓ₃ : Level} {A : Set ℓ₁} {B : Set ℓ₂} {C : Set ℓ₃}
→ (B → C) → (A → B) → A → C
(g ∘′ f) x = g (f x)
\end{code}
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?
\begin{code}
postulate
¬All≃Any¬ : ∀ {A : Set} (P : A → Set) (xs : List A)
→ (¬_ ∘′ All P) xs ≃ Any (¬_ ∘′ P) xs
\end{code}
If so, prove; if not, explain why.
#### Exercise `any?`
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 predicates holds
for some element of a list. Give their definitions.
## Lambda
#### Exercise `mul` (recommended)
Write out the definition of a lambda term that multiplies
two natural numbers.
#### Exercise `primed` (stretch)
We can make examples with lambda terms slighly easier to write
by adding the following definitions.
\begin{code}
ƛ_⇒_ : Term → Term → Term
ƛ′ (` x) ⇒ N = ƛ x ⇒ N
ƛ′ _ ⇒ _ = ⊥-elim impossible
where postulate impossible : ⊥
case_[zero⇒_|suc_⇒_] : Term → Term → Term → Term → Term
case L [zero⇒ M |suc (` x) ⇒ N ] = case L [zero⇒ M |suc x ⇒ N ]
case _ [zero⇒ _ |suc _ ⇒ _ ] = ⊥-elim impossible
where postulate impossible : ⊥
μ_⇒_ : Term → Term → Term
μ′ (` x) ⇒ N = μ x ⇒ N
μ′ _ ⇒ _ = ⊥-elim impossible
where postulate impossible : ⊥
\end{code}
The definition of `plus` can now be written as follows.
\begin{code}
plus : Term
plus = μ′ + ⇒ ƛ′ m ⇒ ƛ′ n ⇒
case m
[zero⇒ n
|suc m ⇒ `suc (+ · m · n) ]
where
+ = ` "+"
m = ` "m"
n = ` "n"
\end{code}
Write out the definition of multiplication in the same style.
#### Exercise `_[_:=_]` (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.
#### Exercise `—↠≃—↠′`
Show that the two notions of reflexive and transitive closure
above are isomorphic.
#### Exercise `plus-example`
Write out the reduction sequence demonstrating that one plus one is two.
#### Exercise `mul-type`
Using the term `mul` you defined earlier, write out the derivation
showing that it is well-typed.
## Properties
#### Exercise `Progress-iso`
Show that `Progress M` is isomorphic to `Value M ⊎ ∃[ N ](M —→ N)`.
#### Exercise `progress`
Write out the proof of `progress` in full, and compare it to the
proof of `progress` above.
#### Exercise `value?`
Combine `progress` and `—→¬V` to write a program that decides
whether a well-typed term is a value.
\begin{code}
postulate
value? : ∀ {A M} → ∅ ⊢ M ⦂ A → Dec (Value M)
\end{code}
#### Exercise `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.
#### Exercise `mul-example` (recommended)
Using the evaluator, confirm that two times two is four.
#### Exercise: `progress-preservation` (recommended)
Without peeking at their statements above, write down the progress
and preservation theorems for the simply typed lambda-calculus.
#### Exercise `subject_expansion`
We say that `M` _reduces_ to `N` if `M —→ N`,
and conversely 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` imply `∅ ⊢ M ⦂ A`.
Find two counter-examples to subject expansion, one
with case expressions and one not involving case expressions.
#### Exercise `stuck` (recommended)
Give an example of an ill-typed term that does get stuck.
#### Exercise `unstuck` (recommended)
Provide proofs of the three postulates, `unstuck`, `preserves`, and `wttdgs` above.

View file

@ -99,7 +99,7 @@ For instructions on how to set up Agda for PLFA see [Getting Started](/GettingSt
* [Assignment 1][Assignment1] cw1 due 4pm Thursday 4 October (Week 3)
* [Assignment 2][Assignment2] cw2 due 4pm Thursday 18 October (Week 5)
* Assignment 3 cw3 due 4pm Thursday 1 November (Week 7)
* [Assignment 3][Assignment3] cw3 due 4pm Thursday 1 November (Week 7)
* Assignment 4 cw4 due 4pm Thursday 15 November (Week 9)
* Assignment 5 cw5 due 4pm Thursday 22 November (Week 10)