finished Lists foldr monoid
This commit is contained in:
parent
ab9e5d6c7d
commit
462a88508f
1 changed files with 99 additions and 19 deletions
118
src/Lists.lagda
118
src/Lists.lagda
|
@ -14,6 +14,7 @@ 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; _+_; _*_)
|
open import Data.Nat using (ℕ; zero; suc; _+_; _*_)
|
||||||
|
open import Data.Nat.Properties using (+-assoc; +-identityˡ; +-identityʳ; *-assoc; *-identityˡ; *-identityʳ)
|
||||||
\end{code}
|
\end{code}
|
||||||
|
|
||||||
## Lists
|
## Lists
|
||||||
|
@ -69,9 +70,9 @@ the second form it would be permitted to replace an occurrence
|
||||||
of `List A` by `List ℕ`, say.
|
of `List A` by `List ℕ`, say.
|
||||||
|
|
||||||
Including the lines
|
Including the lines
|
||||||
\begin{code}
|
|
||||||
{-# BUILTIN LIST List #-}
|
{-# BUILTIN LIST List #-}
|
||||||
\end{code}
|
|
||||||
tells Agda that the type `List` corresponds to the Haskell type
|
tells Agda that the type `List` corresponds to the Haskell type
|
||||||
list, and the constructors `[]` and `_∷_` correspond to nil and
|
list, and the constructors `[]` and `_∷_` correspond to nil and
|
||||||
cons respectively, allowing a more efficient representation of lists.
|
cons respectively, allowing a more efficient representation of lists.
|
||||||
|
@ -152,24 +153,24 @@ number of elements in the first list.
|
||||||
We can reason about lists in much the same way that we reason
|
We can reason about lists in much the same way that we reason
|
||||||
about numbers. Here is the proof that append is associative.
|
about numbers. Here is the proof that append is associative.
|
||||||
\begin{code}
|
\begin{code}
|
||||||
++-assoc : ∀ {A : Set} (xs ys zs : List A) → xs ++ (ys ++ zs) ≡ (xs ++ ys) ++ zs
|
++-assoc : ∀ {A : Set} (xs ys zs : List A) → (xs ++ ys) ++ zs ≡ xs ++ (ys ++ zs)
|
||||||
++-assoc [] ys zs =
|
++-assoc [] ys zs =
|
||||||
begin
|
begin
|
||||||
[] ++ (ys ++ zs)
|
([] ++ ys) ++ zs
|
||||||
≡⟨⟩
|
≡⟨⟩
|
||||||
ys ++ zs
|
ys ++ zs
|
||||||
≡⟨⟩
|
≡⟨⟩
|
||||||
([] ++ ys) ++ zs
|
[] ++ (ys ++ zs)
|
||||||
∎
|
∎
|
||||||
++-assoc (x ∷ xs) ys zs =
|
++-assoc (x ∷ xs) ys zs =
|
||||||
begin
|
begin
|
||||||
(x ∷ xs) ++ (ys ++ zs)
|
(x ∷ xs ++ ys) ++ zs
|
||||||
≡⟨⟩
|
≡⟨⟩
|
||||||
x ∷ (xs ++ (ys ++ zs))
|
|
||||||
≡⟨ cong (x ∷_) (++-assoc xs ys zs) ⟩
|
|
||||||
x ∷ ((xs ++ ys) ++ zs)
|
x ∷ ((xs ++ ys) ++ zs)
|
||||||
|
≡⟨ cong (x ∷_) (++-assoc xs ys zs) ⟩
|
||||||
|
x ∷ (xs ++ (ys ++ zs))
|
||||||
≡⟨⟩
|
≡⟨⟩
|
||||||
((x ∷ xs) ++ ys) ++ zs
|
x ∷ xs ++ (ys ++ zs)
|
||||||
∎
|
∎
|
||||||
\end{code}
|
\end{code}
|
||||||
The proof is by induction on the first argument. The base case instantiates
|
The proof is by induction on the first argument. The base case instantiates
|
||||||
|
@ -355,14 +356,14 @@ list, and the sum of the numbers up to `n` is `n * (n + 1) / 2`.
|
||||||
|
|
||||||
## Reasoning about reverse
|
## Reasoning about reverse
|
||||||
|
|
||||||
*Exercise*
|
*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*
|
*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.
|
||||||
|
@ -403,7 +404,7 @@ shunt-reverse (x ∷ xs) ys =
|
||||||
reverse xs ++ (x ∷ ys)
|
reverse xs ++ (x ∷ ys)
|
||||||
≡⟨⟩
|
≡⟨⟩
|
||||||
reverse xs ++ ([ x ] ++ ys)
|
reverse xs ++ ([ x ] ++ ys)
|
||||||
≡⟨ ++-assoc (reverse xs) ([ x ]) ys ⟩
|
≡⟨ sym (++-assoc (reverse xs) ([ x ]) ys) ⟩
|
||||||
(reverse xs ++ [ x ]) ++ ys
|
(reverse xs ++ [ x ]) ++ ys
|
||||||
≡⟨⟩
|
≡⟨⟩
|
||||||
reverse (x ∷ xs) ++ ys
|
reverse (x ∷ xs) ++ ys
|
||||||
|
@ -515,7 +516,7 @@ parameterised on *n* types will have a map that is parameterised on
|
||||||
*n* functions.
|
*n* functions.
|
||||||
|
|
||||||
|
|
||||||
*Exercise*
|
*Exercise* `map-compose`
|
||||||
|
|
||||||
The composition of two functions applies one and then the other.
|
The composition of two functions applies one and then the other.
|
||||||
\begin{code}
|
\begin{code}
|
||||||
|
@ -532,7 +533,7 @@ postulate
|
||||||
extensionality : ∀ {A B : Set} → {f g : A → B} → (∀ (x : A) → f x ≡ g x) → f ≡ g
|
extensionality : ∀ {A B : Set} → {f g : A → B} → (∀ (x : A) → f x ≡ g x) → f ≡ g
|
||||||
\end{code}
|
\end{code}
|
||||||
|
|
||||||
*Exercise*
|
*Exercise* `map-++-commute`
|
||||||
|
|
||||||
Prove the following relationship between map and append.
|
Prove the following relationship between map and append.
|
||||||
|
|
||||||
|
@ -590,12 +591,26 @@ so the fold function takes two arguments, `e` and `_⊕_`
|
||||||
In general, a data type with *n* constructors will have
|
In general, a data type with *n* constructors will have
|
||||||
a corresponding fold function that takes *n* arguments.
|
a corresponding fold function that takes *n* arguments.
|
||||||
|
|
||||||
*Exercise*
|
*Exercise* (`product`)
|
||||||
|
|
||||||
Use fold to define a function to find the product of a list of numbers.
|
Use fold to define a function to find the product of a list of numbers.
|
||||||
|
|
||||||
product ([ 1 , 2 , 3 , 4 ]) ≡ 24
|
product ([ 1 , 2 , 3 , 4 ]) ≡ 24
|
||||||
|
|
||||||
|
*Exercise* (`foldr-++`)
|
||||||
|
|
||||||
|
Show that fold and append are related as follows.
|
||||||
|
|
||||||
|
foldr _⊗_ e (xs ++ ys) ≡ foldr _⊗_ (foldr _⊗_ e ys) xs
|
||||||
|
|
||||||
|
*Exercise* (`map-is-foldr`) <!-- `mapIsFold` in Data.List.Properties -->
|
||||||
|
|
||||||
|
Show that map can be defined using fold.
|
||||||
|
|
||||||
|
map f ≡ foldr (λ x xs → f x ∷ xs) []
|
||||||
|
|
||||||
|
This requires extensionality.
|
||||||
|
|
||||||
|
|
||||||
## Monoids
|
## Monoids
|
||||||
|
|
||||||
|
@ -607,11 +622,75 @@ 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 Monoid {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
|
||||||
\end{code}
|
\end{code}
|
||||||
|
|
||||||
|
As examples, sum and zero, multiplication and one, and append and the empty
|
||||||
|
list, are all examples of monoids.
|
||||||
|
\begin{code}
|
||||||
|
+-monoid : Monoid _+_ 0
|
||||||
|
+-monoid =
|
||||||
|
record
|
||||||
|
{ assoc = +-assoc
|
||||||
|
; identityˡ = +-identityˡ
|
||||||
|
; identityʳ = +-identityʳ
|
||||||
|
}
|
||||||
|
|
||||||
|
*-monoid : Monoid _*_ 1
|
||||||
|
*-monoid =
|
||||||
|
record
|
||||||
|
{ assoc = *-assoc
|
||||||
|
; identityˡ = *-identityˡ
|
||||||
|
; identityʳ = *-identityʳ
|
||||||
|
}
|
||||||
|
|
||||||
|
++-monoid : ∀ {A : Set} → Monoid {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}
|
||||||
|
fold-monoid : ∀ {A : Set} (_⊗_ : A → A → A) (e : A) → Monoid _⊗_ e →
|
||||||
|
∀ (y : A) (xs : List A) → foldr _⊗_ e xs ⊗ y ≡ foldr _⊗_ y xs
|
||||||
|
fold-monoid _⊗_ e ⊗-monoid y [] =
|
||||||
|
begin
|
||||||
|
foldr _⊗_ e [] ⊗ y
|
||||||
|
≡⟨⟩
|
||||||
|
(e ⊗ y)
|
||||||
|
≡⟨ identityˡ ⊗-monoid y ⟩
|
||||||
|
y
|
||||||
|
≡⟨⟩
|
||||||
|
foldr _⊗_ y []
|
||||||
|
∎
|
||||||
|
fold-monoid _⊗_ e ⊗-monoid y (x ∷ xs) =
|
||||||
|
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 ⊗_) (fold-monoid _⊗_ e ⊗-monoid y xs) ⟩
|
||||||
|
x ⊗ (foldr _⊗_ y xs)
|
||||||
|
≡⟨⟩
|
||||||
|
foldr _⊗_ y (x ∷ xs)
|
||||||
|
∎
|
||||||
|
\end{code}
|
||||||
|
|
||||||
|
As a consequence of `foldr-++` and `fold-monoid`, it is easy to show
|
||||||
|
|
||||||
|
foldr _⊗_ e (xs ++ ys) ≡ foldr _⊗_ e xs ⊗ foldr _⊗_ e ys
|
||||||
|
|
||||||
|
|
||||||
## Element
|
## Element
|
||||||
|
|
||||||
\begin{code}
|
\begin{code}
|
||||||
|
@ -625,3 +704,4 @@ infix 4 _∈_
|
||||||
## Unicode
|
## Unicode
|
||||||
|
|
||||||
∷ U+2237 PROPORTION (\::)
|
∷ U+2237 PROPORTION (\::)
|
||||||
|
⊗ (\otimes)
|
||||||
|
|
Loading…
Reference in a new issue