revised Lists
This commit is contained in:
parent
e188bedcc2
commit
b943785e6b
3 changed files with 112 additions and 106 deletions
2
index.md
2
index.md
|
@ -28,7 +28,7 @@ material in a different way; see the [Preface](Preface).
|
||||||
- [Connectives: Conjunction, Disjunction, and Implication](Connectives)
|
- [Connectives: Conjunction, Disjunction, and Implication](Connectives)
|
||||||
- [Negation: Negation, with Intuitionistic and Classical Logic](Negation)
|
- [Negation: Negation, with Intuitionistic and Classical Logic](Negation)
|
||||||
- [Quantiers: Universals and Existentials](Quantifiers)
|
- [Quantiers: Universals and Existentials](Quantifiers)
|
||||||
- [Lists: Lists and other data types](Lists)
|
- [Lists: Lists and higher-order functions](Lists)
|
||||||
- [Decidable: Booleans and decision procedures](Decidable)
|
- [Decidable: Booleans and decision procedures](Decidable)
|
||||||
|
|
||||||
- [PropertiesAns: Solutions to exercises](PropertiesAns)
|
- [PropertiesAns: Solutions to exercises](PropertiesAns)
|
||||||
|
|
215
src/Lists.lagda
215
src/Lists.lagda
|
@ -1,12 +1,12 @@
|
||||||
---
|
---
|
||||||
title : "Lists: Lists and other data types"
|
title : "Lists: Lists and higher-order functions"
|
||||||
layout : page
|
layout : page
|
||||||
permalink : /Lists
|
permalink : /Lists
|
||||||
---
|
---
|
||||||
|
|
||||||
This chapter discusses the list data type. It gives further examples
|
This chapter discusses the list data type. It gives further examples
|
||||||
of many of the techniques we have developed so far, and provides
|
of many of the techniques we have developed so far, and provides
|
||||||
examples of polymorphic types and functions.
|
examples of polymorphic types and higher-order functions.
|
||||||
|
|
||||||
## Imports
|
## Imports
|
||||||
|
|
||||||
|
@ -15,12 +15,23 @@ import Relation.Binary.PropositionalEquality as Eq
|
||||||
open Eq using (_≡_; refl; sym; trans; cong)
|
open Eq using (_≡_; refl; sym; trans; cong)
|
||||||
open Eq.≡-Reasoning
|
open Eq.≡-Reasoning
|
||||||
open import Data.Nat using (ℕ; zero; suc; _+_; _*_; _≤_; s≤s; z≤n)
|
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 Data.Nat.Properties using
|
||||||
|
(+-assoc; +-identityˡ; +-identityʳ; *-assoc; *-identityˡ; *-identityʳ)
|
||||||
open import Relation.Nullary using (¬_)
|
open import Relation.Nullary using (¬_)
|
||||||
open import Data.Product using (_×_) renaming (_,_ to ⟨_,_⟩)
|
open import Data.Product using (_×_) renaming (_,_ to ⟨_,_⟩)
|
||||||
open import Isomorphism using (_≃_)
|
open import Isomorphism using (_≃_)
|
||||||
|
open import Function using (_∘_)
|
||||||
\end{code}
|
\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
|
||||||
|
|
||||||
|
|
||||||
## Lists
|
## Lists
|
||||||
|
|
||||||
Lists are defined in Agda as follows.
|
Lists are defined in Agda as follows.
|
||||||
|
@ -90,8 +101,6 @@ the third line tells us that `[ x , y , z ]` is equivalent to
|
||||||
`x ∷ y ∷ z ∷ []`, and permits the former to appear either in
|
`x ∷ y ∷ z ∷ []`, and permits the former to appear either in
|
||||||
a pattern on the left-hand side of an equation, or a term
|
a pattern on the left-hand side of an equation, or a term
|
||||||
on the right-hand side of an equation.
|
on the right-hand side of an equation.
|
||||||
Agda recognises `[_,_,_]` as a bracketing notation, and hence `length
|
|
||||||
[ 0 , 1 , 2 ]` parses as `length ([ 0 , 1 , 2 ])`.
|
|
||||||
|
|
||||||
|
|
||||||
## Append
|
## Append
|
||||||
|
@ -102,8 +111,8 @@ Our first function on lists is written `_++_` and pronounced
|
||||||
infixr 5 _++_
|
infixr 5 _++_
|
||||||
|
|
||||||
_++_ : ∀ {A : Set} → List A → List A → List A
|
_++_ : ∀ {A : Set} → List A → List A → List A
|
||||||
[] ++ ys = ys
|
[] ++ ys = ys
|
||||||
(x ∷ xs) ++ ys = x ∷ (xs ++ ys)
|
(x ∷ xs) ++ ys = x ∷ (xs ++ ys)
|
||||||
\end{code}
|
\end{code}
|
||||||
The type `A` is an implicit argument to append, making it
|
The type `A` is an implicit argument to append, making it
|
||||||
a *polymorphic* function (one that can be used at many types).
|
a *polymorphic* function (one that can be used at many types).
|
||||||
|
@ -173,7 +182,7 @@ Applying the congruence `cong (x ∷_)` promotes the inductive hypothesis
|
||||||
|
|
||||||
xs ++ (ys ++ zs) ≡ (xs ++ ys) ++ zs
|
xs ++ (ys ++ zs) ≡ (xs ++ ys) ++ zs
|
||||||
|
|
||||||
to the equivalence
|
to the equality
|
||||||
|
|
||||||
x ∷ (xs ++ (ys ++ zs)) ≡ x ∷ ((xs ++ ys) ++ zs)
|
x ∷ (xs ++ (ys ++ zs)) ≡ x ∷ ((xs ++ ys) ++ zs)
|
||||||
|
|
||||||
|
@ -208,7 +217,8 @@ That it is a right identity follows by simple induction.
|
||||||
x ∷ xs
|
x ∷ xs
|
||||||
∎
|
∎
|
||||||
\end{code}
|
\end{code}
|
||||||
These three properties establish that `_++_` and `[]` form
|
As we will see later,
|
||||||
|
these three properties establish that `_++_` and `[]` form
|
||||||
a *monoid* over lists.
|
a *monoid* over lists.
|
||||||
|
|
||||||
## Length
|
## Length
|
||||||
|
@ -216,8 +226,8 @@ a *monoid* over lists.
|
||||||
Our next function finds the length of a list.
|
Our next function finds the length of a list.
|
||||||
\begin{code}
|
\begin{code}
|
||||||
length : ∀ {A : Set} → List A → ℕ
|
length : ∀ {A : Set} → List A → ℕ
|
||||||
length [] = zero
|
length [] = zero
|
||||||
length (x ∷ xs) = suc (length xs)
|
length (x ∷ xs) = suc (length xs)
|
||||||
\end{code}
|
\end{code}
|
||||||
Again, it takes an implicit parameter `A`.
|
Again, it takes an implicit parameter `A`.
|
||||||
The length of the empty list is zero.
|
The length of the empty list is zero.
|
||||||
|
@ -243,12 +253,9 @@ _ =
|
||||||
Computing the length of a list requires time
|
Computing the length of a list requires time
|
||||||
linear in the number of elements in the list.
|
linear in the number of elements in the list.
|
||||||
|
|
||||||
In the second-to-last line, we cannot write
|
In the second-to-last line, we cannot write simply `length []` but
|
||||||
simply `length []` but must instead write
|
must instead write `length {ℕ} []`. Since `[]` has no elements, Agda
|
||||||
`length {ℕ} []`. This is because Agda has
|
has insufficient information to infer the implicit parameter.
|
||||||
insufficient information to infer the implicit
|
|
||||||
parameter; after all, `[]` could just as well
|
|
||||||
be an empty list with elements of any type.
|
|
||||||
|
|
||||||
|
|
||||||
## Reasoning about length
|
## Reasoning about length
|
||||||
|
@ -339,16 +346,14 @@ reversed, append takes time linear in the length of the first
|
||||||
list, and the sum of the numbers up to `n` is `n * (n + 1) / 2`.
|
list, and the sum of the numbers up to `n` is `n * (n + 1) / 2`.
|
||||||
(We will validate that last fact later in this chapter.)
|
(We will validate that last fact later in this chapter.)
|
||||||
|
|
||||||
## Reasoning about reverse
|
### Exercise (`reverse-++-commute`)
|
||||||
|
|
||||||
*Exercise* `reverse-++-commute`
|
|
||||||
|
|
||||||
Show that the reverse of one list appended to another is the
|
Show that the reverse of one list appended to another is the
|
||||||
reverse of the second appended to the reverse of the first.
|
reverse of the second appended to the reverse of the first.
|
||||||
|
|
||||||
reverse (xs ++ ys) ≡ reverse ys ++ reverse xs
|
reverse (xs ++ ys) ≡ reverse ys ++ reverse xs
|
||||||
|
|
||||||
*Exercise* `reverse-involutive`
|
### Exercise (`reverse-involutive`)
|
||||||
|
|
||||||
A function is an *involution* if when applied twice it acts
|
A function is an *involution* if when applied twice it acts
|
||||||
as the identity function. Show that reverse is an involution.
|
as the identity function. Show that reverse is an involution.
|
||||||
|
@ -431,8 +436,8 @@ reverses xs =
|
||||||
|
|
||||||
Here is an example showing fast reverse of the list `[ 0 , 1 , 2 ]`.
|
Here is an example showing fast reverse of the list `[ 0 , 1 , 2 ]`.
|
||||||
\begin{code}
|
\begin{code}
|
||||||
ex₄ : reverse′ [ 0 , 1 , 2 ] ≡ [ 2 , 1 , 0 ]
|
_ : reverse′ [ 0 , 1 , 2 ] ≡ [ 2 , 1 , 0 ]
|
||||||
ex₄ =
|
_ =
|
||||||
begin
|
begin
|
||||||
reverse′ (0 ∷ 1 ∷ 2 ∷ [])
|
reverse′ (0 ∷ 1 ∷ 2 ∷ [])
|
||||||
≡⟨⟩
|
≡⟨⟩
|
||||||
|
@ -456,8 +461,8 @@ Map is an example of a *higher-order function*, one which takes a function as an
|
||||||
argument and returns a function as a result.
|
argument and returns a function as a result.
|
||||||
\begin{code}
|
\begin{code}
|
||||||
map : ∀ {A B : Set} → (A → B) → List A → List B
|
map : ∀ {A B : Set} → (A → B) → List A → List B
|
||||||
map f [] = []
|
map f [] = []
|
||||||
map f (x ∷ xs) = f x ∷ map f xs
|
map f (x ∷ xs) = f x ∷ map f xs
|
||||||
\end{code}
|
\end{code}
|
||||||
Map of the empty list is the empty list.
|
Map of the empty list is the empty list.
|
||||||
Map of a non-empty list yields a list
|
Map of a non-empty list yields a list
|
||||||
|
@ -466,8 +471,8 @@ 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.
|
Here is an example showing how to use map to increment every element of a list.
|
||||||
\begin{code}
|
\begin{code}
|
||||||
ex₅ : map suc [ 0 , 1 , 2 ] ≡ [ 1 , 2 , 3 ]
|
_ : map suc [ 0 , 1 , 2 ] ≡ [ 1 , 2 , 3 ]
|
||||||
ex₅ =
|
_ =
|
||||||
begin
|
begin
|
||||||
map suc (0 ∷ 1 ∷ 2 ∷ [])
|
map suc (0 ∷ 1 ∷ 2 ∷ [])
|
||||||
≡⟨⟩
|
≡⟨⟩
|
||||||
|
@ -489,8 +494,15 @@ point applying the resulting function.
|
||||||
sucs : List ℕ → List ℕ
|
sucs : List ℕ → List ℕ
|
||||||
sucs = map suc
|
sucs = map suc
|
||||||
|
|
||||||
ex₆ : sucs [ 0 , 1 , 2 ] ≡ [ 1 , 2 , 3 ]
|
_ : sucs [ 0 , 1 , 2 ] ≡ [ 1 , 2 , 3 ]
|
||||||
ex₆ = ex₅
|
_ =
|
||||||
|
begin
|
||||||
|
sucs [ 0 , 1 , 2 ]
|
||||||
|
≡⟨⟩
|
||||||
|
map suc [ 0 , 1 , 2 ]
|
||||||
|
≡⟨⟩
|
||||||
|
[ 1 , 2 , 3 ]
|
||||||
|
∎
|
||||||
\end{code}
|
\end{code}
|
||||||
|
|
||||||
Any type that is parameterised on another type, such as lists, has a
|
Any type that is parameterised on another type, such as lists, has a
|
||||||
|
@ -501,25 +513,13 @@ parameterised on *n* types will have a map that is parameterised on
|
||||||
*n* functions.
|
*n* functions.
|
||||||
|
|
||||||
|
|
||||||
*Exercise* `map-compose`
|
### Exercise (`map-compose`)
|
||||||
|
|
||||||
The composition of two functions applies one and then the other.
|
|
||||||
\begin{code}
|
|
||||||
_∘_ : ∀ {ℓ₁ ℓ₂ ℓ₃} {A : Set ℓ₁} {B : Set ℓ₂} {C : Set ℓ₃} → (B → C) → (A → B) → (A → C)
|
|
||||||
(f ∘ g) x = f (g x)
|
|
||||||
\end{code}
|
|
||||||
Unlike most of our definitions, this one is parameterised with respect to levels,
|
|
||||||
which will prove convenient later.
|
|
||||||
|
|
||||||
Prove that the map of a composition is equal to the composition of two maps.
|
Prove that the map of a composition is equal to the composition of two maps.
|
||||||
|
|
||||||
map (f ∘ g) ≡ map f ∘ map g
|
map (f ∘ g) ≡ map f ∘ map g
|
||||||
|
|
||||||
The last step of the proof requires extensionality.
|
The last step of the proof requires extensionality.
|
||||||
\begin{code}
|
|
||||||
postulate
|
|
||||||
extensionality : ∀ {A B : Set} → {f g : A → B} → (∀ (x : A) → f x ≡ g x) → f ≡ g
|
|
||||||
\end{code}
|
|
||||||
|
|
||||||
*Exercise* `map-++-commute`
|
*Exercise* `map-++-commute`
|
||||||
|
|
||||||
|
@ -535,8 +535,8 @@ each of the elements of the list, taking the given value as the result
|
||||||
for the empty list.
|
for the empty list.
|
||||||
\begin{code}
|
\begin{code}
|
||||||
foldr : ∀ {A B : Set} → (A → B → B) → B → List A → B
|
foldr : ∀ {A B : Set} → (A → B → B) → B → List A → B
|
||||||
foldr _⊗_ e [] = e
|
foldr _⊗_ e [] = e
|
||||||
foldr _⊗_ e (x ∷ xs) = x ⊗ foldr _⊗_ e xs
|
foldr _⊗_ e (x ∷ xs) = x ⊗ foldr _⊗_ e xs
|
||||||
\end{code}
|
\end{code}
|
||||||
Fold of the empty list is the given value.
|
Fold of the empty list is the given value.
|
||||||
Fold of a non-empty list uses the operator to combine
|
Fold of a non-empty list uses the operator to combine
|
||||||
|
@ -569,8 +569,8 @@ and at a later point applying the resulting function.
|
||||||
sum : List ℕ → ℕ
|
sum : List ℕ → ℕ
|
||||||
sum = foldr _+_ 0
|
sum = foldr _+_ 0
|
||||||
|
|
||||||
ex₈ : sum [ 1 , 2 , 3 , 4 ] ≡ 10
|
_ : sum [ 1 , 2 , 3 , 4 ] ≡ 10
|
||||||
ex₈ = ex₇
|
_ = ex₇
|
||||||
\end{code}
|
\end{code}
|
||||||
|
|
||||||
Just as the list type has two constructors, `[]` and `_∷_`,
|
Just as the list type has two constructors, `[]` and `_∷_`,
|
||||||
|
@ -588,7 +588,6 @@ Use fold to define a function to find the product of a list of numbers.
|
||||||
*Exercise* (`foldr-++`)
|
*Exercise* (`foldr-++`)
|
||||||
|
|
||||||
Show that fold and append are related as follows.
|
Show that fold and append are related as follows.
|
||||||
|
|
||||||
\begin{code}
|
\begin{code}
|
||||||
postulate
|
postulate
|
||||||
foldr-++ : ∀ {A B : Set} (_⊗_ : A → B → B) (e : B) (xs ys : List A) →
|
foldr-++ : ∀ {A B : Set} (_⊗_ : A → B → B) (e : B) (xs ys : List A) →
|
||||||
|
@ -599,9 +598,11 @@ postulate
|
||||||
*Exercise* (`map-is-foldr`) <!-- `mapIsFold` in Data.List.Properties -->
|
*Exercise* (`map-is-foldr`) <!-- `mapIsFold` in Data.List.Properties -->
|
||||||
|
|
||||||
Show that map can be defined using fold.
|
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) []
|
map f ≡ foldr (λ x xs → f x ∷ xs) []
|
||||||
|
\end{code}
|
||||||
This requires extensionality.
|
This requires extensionality.
|
||||||
|
|
||||||
|
|
||||||
|
@ -613,19 +614,19 @@ operator and the value form a *monoid*.
|
||||||
|
|
||||||
We can define a monoid as a suitable record type.
|
We can define a monoid as a suitable record type.
|
||||||
\begin{code}
|
\begin{code}
|
||||||
record Monoid {A : Set} (_⊗_ : A → A → A) (e : A) : Set where
|
record IsMonoid {A : Set} (_⊗_ : A → A → A) (e : A) : Set where
|
||||||
field
|
field
|
||||||
assoc : ∀ (x y z : A) → (x ⊗ y) ⊗ z ≡ x ⊗ (y ⊗ z)
|
assoc : ∀ (x y z : A) → (x ⊗ y) ⊗ z ≡ x ⊗ (y ⊗ z)
|
||||||
identityˡ : ∀ (x : A) → e ⊗ x ≡ x
|
identityˡ : ∀ (x : A) → e ⊗ x ≡ x
|
||||||
identityʳ : ∀ (x : A) → x ⊗ e ≡ x
|
identityʳ : ∀ (x : A) → x ⊗ e ≡ x
|
||||||
|
|
||||||
open Monoid
|
open IsMonoid
|
||||||
\end{code}
|
\end{code}
|
||||||
|
|
||||||
As examples, sum and zero, multiplication and one, and append and the empty
|
As examples, sum and zero, multiplication and one, and append and the empty
|
||||||
list, are all examples of monoids.
|
list, are all examples of monoids.
|
||||||
\begin{code}
|
\begin{code}
|
||||||
+-monoid : Monoid _+_ 0
|
+-monoid : IsMonoid _+_ 0
|
||||||
+-monoid =
|
+-monoid =
|
||||||
record
|
record
|
||||||
{ assoc = +-assoc
|
{ assoc = +-assoc
|
||||||
|
@ -633,7 +634,7 @@ list, are all examples of monoids.
|
||||||
; identityʳ = +-identityʳ
|
; identityʳ = +-identityʳ
|
||||||
}
|
}
|
||||||
|
|
||||||
*-monoid : Monoid _*_ 1
|
*-monoid : IsMonoid _*_ 1
|
||||||
*-monoid =
|
*-monoid =
|
||||||
record
|
record
|
||||||
{ assoc = *-assoc
|
{ assoc = *-assoc
|
||||||
|
@ -641,7 +642,7 @@ list, are all examples of monoids.
|
||||||
; identityʳ = *-identityʳ
|
; identityʳ = *-identityʳ
|
||||||
}
|
}
|
||||||
|
|
||||||
++-monoid : ∀ {A : Set} → Monoid {List A} _++_ []
|
++-monoid : ∀ {A : Set} → IsMonoid {List A} _++_ []
|
||||||
++-monoid =
|
++-monoid =
|
||||||
record
|
record
|
||||||
{ assoc = ++-assoc
|
{ assoc = ++-assoc
|
||||||
|
@ -653,42 +654,42 @@ list, are all examples of monoids.
|
||||||
If `_⊕_` and `e` form a monoid, then we can re-express fold on the
|
If `_⊕_` and `e` form a monoid, then we can re-express fold on the
|
||||||
same operator and an arbitrary value.
|
same operator and an arbitrary value.
|
||||||
\begin{code}
|
\begin{code}
|
||||||
foldr-monoid : ∀ {A : Set} (_⊗_ : A → A → A) (e : A) → Monoid _⊗_ e →
|
foldr-monoid : ∀ {A : Set} (_⊗_ : A → A → A) (e : A) → IsMonoid _⊗_ e →
|
||||||
∀ (xs : List A) (y : A) → foldr _⊗_ e xs ⊗ y ≡ foldr _⊗_ y xs
|
∀ (xs : List A) (y : A) → foldr _⊗_ y xs ≡ foldr _⊗_ e xs ⊗ y
|
||||||
foldr-monoid _⊗_ e ⊗-monoid [] y =
|
foldr-monoid _⊗_ e ⊗-monoid [] y =
|
||||||
begin
|
begin
|
||||||
foldr _⊗_ e [] ⊗ y
|
foldr _⊗_ y []
|
||||||
≡⟨⟩
|
≡⟨⟩
|
||||||
(e ⊗ y)
|
|
||||||
≡⟨ identityˡ ⊗-monoid y ⟩
|
|
||||||
y
|
y
|
||||||
|
≡⟨ sym (identityˡ ⊗-monoid y) ⟩
|
||||||
|
(e ⊗ y)
|
||||||
≡⟨⟩
|
≡⟨⟩
|
||||||
foldr _⊗_ y []
|
foldr _⊗_ e [] ⊗ y
|
||||||
∎
|
∎
|
||||||
foldr-monoid _⊗_ e ⊗-monoid (x ∷ xs) y =
|
foldr-monoid _⊗_ e ⊗-monoid (x ∷ xs) y =
|
||||||
begin
|
begin
|
||||||
foldr _⊗_ e (x ∷ xs) ⊗ y
|
|
||||||
≡⟨⟩
|
|
||||||
(x ⊗ foldr _⊗_ e xs) ⊗ y
|
|
||||||
≡⟨ assoc ⊗-monoid x (foldr _⊗_ e xs) y ⟩
|
|
||||||
x ⊗ (foldr _⊗_ e xs ⊗ y)
|
|
||||||
≡⟨ cong (x ⊗_) (foldr-monoid _⊗_ e ⊗-monoid xs y) ⟩
|
|
||||||
x ⊗ (foldr _⊗_ y xs)
|
|
||||||
≡⟨⟩
|
|
||||||
foldr _⊗_ y (x ∷ xs)
|
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}
|
\end{code}
|
||||||
|
|
||||||
As a consequence, using a previous exercise, we have the following.
|
As a consequence, using a previous exercise, we have the following.
|
||||||
\begin{code}
|
\begin{code}
|
||||||
foldr-monoid-++ : ∀ {A : Set} (_⊗_ : A → A → A) (e : A) → Monoid _⊗_ e →
|
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
|
∀ (xs ys : List A) → foldr _⊗_ e (xs ++ ys) ≡ foldr _⊗_ e xs ⊗ foldr _⊗_ e ys
|
||||||
foldr-monoid-++ _⊗_ e monoid-⊗ xs ys =
|
foldr-monoid-++ _⊗_ e monoid-⊗ xs ys =
|
||||||
begin
|
begin
|
||||||
foldr _⊗_ e (xs ++ ys)
|
foldr _⊗_ e (xs ++ ys)
|
||||||
≡⟨ foldr-++ _⊗_ e xs ys ⟩
|
≡⟨ foldr-++ _⊗_ e xs ys ⟩
|
||||||
foldr _⊗_ (foldr _⊗_ e ys) xs
|
foldr _⊗_ (foldr _⊗_ e ys) xs
|
||||||
≡⟨ sym (foldr-monoid _⊗_ e monoid-⊗ xs (foldr _⊗_ e ys)) ⟩
|
≡⟨ foldr-monoid _⊗_ e monoid-⊗ xs (foldr _⊗_ e ys) ⟩
|
||||||
foldr _⊗_ e xs ⊗ foldr _⊗_ e ys
|
foldr _⊗_ e xs ⊗ foldr _⊗_ e ys
|
||||||
∎
|
∎
|
||||||
\end{code}
|
\end{code}
|
||||||
|
@ -716,8 +717,8 @@ 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 ≤
|
`n`, and that if `m≤n` proves `m ≤ n` then `s≤s m≤n` proves `suc m ≤
|
||||||
suc n`, for any `m` and `n`.
|
suc n`, for any `m` and `n`.
|
||||||
\begin{code}
|
\begin{code}
|
||||||
ex₉ : All (_≤ 2) [ 0 , 1 , 2 ]
|
_ : All (_≤ 2) [ 0 , 1 , 2 ]
|
||||||
ex₉ = z≤n ∷ (s≤s z≤n) ∷ (s≤s (s≤s z≤n)) ∷ []
|
_ = z≤n ∷ (s≤s z≤n) ∷ (s≤s (s≤s z≤n)) ∷ []
|
||||||
\end{code}
|
\end{code}
|
||||||
Here `_∷_` and `[]` are the constructors of `All P` rather than of `List A`.
|
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.
|
The three items are proofs of `0 ≤ 2`, `1 ≤ 2`, and `2 ≤ 2`, respectively.
|
||||||
|
@ -747,19 +748,21 @@ For example, zero is an element of the list `[ 0 , 1 , 0 , 2 ]`. Indeed, we can
|
||||||
this fact in two different ways, corresponding to the two different
|
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.
|
occurrences of zero in the list, as the first element and as the third element.
|
||||||
\begin{code}
|
\begin{code}
|
||||||
ex₁₀ ex₁₁ : 0 ∈ [ 0 , 1 , 0 , 2 ]
|
_ : 0 ∈ [ 0 , 1 , 0 , 2 ]
|
||||||
ex₁₀ = here refl
|
_ = here refl
|
||||||
ex₁₁ = there (there (here refl))
|
|
||||||
|
_ : 0 ∈ [ 0 , 1 , 0 , 2 ]
|
||||||
|
_ = there (there (here refl))
|
||||||
\end{code}
|
\end{code}
|
||||||
Further, we can demonstrate that three is not in the list, because
|
Further, we can demonstrate that three is not in the list, because
|
||||||
any possible proof that it is in the list leads to contradiction.
|
any possible proof that it is in the list leads to contradiction.
|
||||||
\begin{code}
|
\begin{code}
|
||||||
ex₁₂ : 3 ∉ [ 0 , 1 , 0 , 2 ]
|
not-in : 3 ∉ [ 0 , 1 , 0 , 2 ]
|
||||||
ex₁₂ (here ())
|
not-in (here ())
|
||||||
ex₁₂ (there (here ()))
|
not-in (there (here ()))
|
||||||
ex₁₂ (there (there (here ())))
|
not-in (there (there (here ())))
|
||||||
ex₁₂ (there (there (there (here ()))))
|
not-in (there (there (there (here ()))))
|
||||||
ex₁₂ (there (there (there (there ()))))
|
not-in (there (there (there (there ()))))
|
||||||
\end{code}
|
\end{code}
|
||||||
The five occurrences of `()` attest to the fact that there is no
|
The five occurrences of `()` attest to the fact that there is no
|
||||||
possible evidence for `3 ≡ 0`, `3 ≡ 1`, `3 ≡ 0`, `3 ≡ 2`, and
|
possible evidence for `3 ≡ 0`, `3 ≡ 1`, `3 ≡ 0`, `3 ≡ 2`, and
|
||||||
|
@ -771,47 +774,49 @@ 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
|
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.
|
result is true, as we can show that the two types are isomorphic.
|
||||||
\begin{code}
|
\begin{code}
|
||||||
All-++ : ∀ {A : Set} {P : A → Set} (xs ys : List A) → All P (xs ++ ys) ≃ (All P xs × All P ys)
|
All-++ : ∀ {A : Set} {P : A → Set} (xs ys : List A) →
|
||||||
|
All P (xs ++ ys) ≃ (All P xs × All P ys)
|
||||||
All-++ xs ys =
|
All-++ xs ys =
|
||||||
record
|
record
|
||||||
{ to = to xs ys
|
{ to = to xs ys
|
||||||
; from = from xs ys
|
; from = from xs ys
|
||||||
; from∘to = from∘to xs ys
|
; from∘to = from∘to xs ys
|
||||||
; to∘from = to∘from xs ys
|
; to∘from = to∘from xs ys
|
||||||
}
|
}
|
||||||
|
|
||||||
where
|
where
|
||||||
|
|
||||||
to : ∀ {A : Set} {P : A → Set} (xs ys : List A) → All P (xs ++ ys) → (All P xs × All P ys)
|
to : ∀ {A : Set} {P : A → Set} (xs ys : List A) →
|
||||||
to [] ys AllPys = ⟨ [] , AllPys ⟩
|
All P (xs ++ ys) → (All P xs × All P ys)
|
||||||
to (x ∷ xs) ys (Px ∷ AllPxsys) with to xs ys AllPxsys
|
to [] ys ∀Pys = ⟨ [] , ∀Pys ⟩
|
||||||
... | ⟨ AllPxs , AllPys ⟩ = ⟨ Px ∷ AllPxs , AllPys ⟩
|
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 : ∀ { A : Set} {P : A → Set} (xs ys : List A) →
|
||||||
from [] ys ⟨ [] , AllPys ⟩ = AllPys
|
All P xs × All P ys → All P (xs ++ ys)
|
||||||
from (x ∷ xs) ys ⟨ Px ∷ AllPxs , AllPys ⟩ = Px ∷ from xs ys ⟨ AllPxs , AllPys ⟩
|
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) → (AllPxsys : All P (xs ++ ys)) →
|
from∘to : ∀ { A : Set} {P : A → Set} (xs ys : List A) →
|
||||||
from xs ys (to xs ys AllPxsys) ≡ AllPxsys
|
∀ (u : All P (xs ++ ys)) → from xs ys (to xs ys u) ≡ u
|
||||||
from∘to [] ys AllPys = refl
|
from∘to [] ys ∀Pys = refl
|
||||||
from∘to (x ∷ xs) ys (Px ∷ AllPxsys) = cong (Px ∷_) (from∘to xs ys AllPxsys)
|
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) → (AllPxsAllPys : All P xs × All P ys) →
|
to∘from : ∀ { A : Set} {P : A → Set} (xs ys : List A) →
|
||||||
to xs ys (from xs ys AllPxsAllPys) ≡ AllPxsAllPys
|
∀ (v : All P xs × All P ys) → to xs ys (from xs ys v) ≡ v
|
||||||
to∘from [] ys ⟨ [] , AllPys ⟩ = refl
|
to∘from [] ys ⟨ [] , ∀Pys ⟩ = refl
|
||||||
to∘from (x ∷ xs) ys ⟨ Px ∷ AllPxs , AllPys ⟩ rewrite to∘from xs ys ⟨ AllPxs , AllPys ⟩ = refl
|
to∘from (x ∷ xs) ys ⟨ Px ∷ ∀Pxs , ∀Pys ⟩ rewrite to∘from xs ys ⟨ ∀Pxs , ∀Pys ⟩ = refl
|
||||||
\end{code}
|
\end{code}
|
||||||
|
|
||||||
*Exercise* `Any-++`
|
### Exercise (`Any-++`)
|
||||||
|
|
||||||
Prove a result similar to `All-++`, but with `Any` in place of `All`, and a suitable
|
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
|
replacement for `_×_`. As a consequence, demonstrate an isomorphism relating
|
||||||
`_∈_` and `_++_`.
|
`_∈_` and `_++_`.
|
||||||
|
|
||||||
*Exercise* `¬Any≃All¬`
|
### Exercise (`¬Any≃All¬`)
|
||||||
|
|
||||||
Show that `Any` and `All` satisfy a version of De Morgan's Law.
|
Show that `Any` and `All` satisfy a version of De Morgan's Law.
|
||||||
|
|
||||||
\begin{code}
|
\begin{code}
|
||||||
postulate
|
postulate
|
||||||
¬Any≃All¬ : ∀ {A : Set} (P : A → Set) (xs : List A) → (¬_ ∘ Any P) xs ≃ All (¬_ ∘ P) xs
|
¬Any≃All¬ : ∀ {A : Set} (P : A → Set) (xs : List A) → (¬_ ∘ Any P) xs ≃ All (¬_ ∘ P) xs
|
||||||
|
|
|
@ -386,6 +386,7 @@ import Data.Product using (Σ; _,_; ∃; Σ-syntax; ∃-syntax)
|
||||||
|
|
||||||
This chapter uses the following unicode.
|
This chapter uses the following unicode.
|
||||||
|
|
||||||
|
Π U+03A0 GREEK CAPITAL LETTER PI (\Pi)
|
||||||
∃ U+2203 THERE EXISTS (\ex, \exists)
|
∃ U+2203 THERE EXISTS (\ex, \exists)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue