making sure everything is committed
This commit is contained in:
parent
9f58620f8d
commit
858e191639
5 changed files with 142 additions and 64 deletions
|
@ -20,6 +20,7 @@ open import Data.Product using (_×_) renaming (_,_ to ⟨_,_⟩)
|
||||||
open import Data.Sum using (_⊎_; inj₁; inj₂)
|
open import Data.Sum using (_⊎_; inj₁; inj₂)
|
||||||
open import Relation.Nullary using (¬_)
|
open import Relation.Nullary using (¬_)
|
||||||
open import Relation.Nullary.Negation using (contraposition)
|
open import Relation.Nullary.Negation using (contraposition)
|
||||||
|
renaming (contradiction to ¬¬-intro)
|
||||||
open import Data.Unit using (⊤; tt)
|
open import Data.Unit using (⊤; tt)
|
||||||
open import Data.Empty using (⊥; ⊥-elim)
|
open import Data.Empty using (⊥; ⊥-elim)
|
||||||
open import Data.List using (List; []; _∷_; foldr; map)
|
open import Data.List using (List; []; _∷_; foldr; map)
|
||||||
|
@ -128,7 +129,6 @@ 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`
|
Another way to put this is that `T b` is inhabited exactly when `b ≡ true`
|
||||||
is inhabited.
|
is inhabited.
|
||||||
|
|
||||||
In the forward direction, we need to do a case analysis on the boolean `b`.
|
In the forward direction, we need to do a case analysis on the boolean `b`.
|
||||||
\begin{code}
|
\begin{code}
|
||||||
T→≡ : ∀ (b : Bool) → T b → b ≡ true
|
T→≡ : ∀ (b : Bool) → T b → b ≡ true
|
||||||
|
@ -276,14 +276,14 @@ trouble normalising evidence of negation.)
|
||||||
|
|
||||||
## Decidables from booleans, and booleans from decidables
|
## Decidables from booleans, and booleans from decidables
|
||||||
|
|
||||||
Curious readers might wonder if we could reuse the definition of `m ≤ᵇ
|
Curious readers might wonder if we could reuse the definition of
|
||||||
n`, together with the proofs that it is equivalent to `m ≤ n`, to show
|
`m ≤ᵇ n`, together with the proofs that it is equivalent to `m ≤ n`, to show
|
||||||
decidability. Indeed we can do so as follows.
|
decidability. Indeed we can do so as follows.
|
||||||
\begin{code}
|
\begin{code}
|
||||||
_≤?′_ : ∀ (m n : ℕ) → Dec (m ≤ n)
|
_≤?′_ : ∀ (m n : ℕ) → Dec (m ≤ n)
|
||||||
m ≤?′ n with m ≤ᵇ n | ≤ᵇ→≤ m n | ≤→≤ᵇ {m} {n}
|
m ≤?′ n with m ≤ᵇ n | ≤ᵇ→≤ m n | ≤→≤ᵇ {m} {n}
|
||||||
... | true | p | _ = yes (p tt)
|
... | true | p | _ = yes (p tt)
|
||||||
... | false | _ | ¬p = no ¬p
|
... | false | _ | ¬p = no ¬p
|
||||||
\end{code}
|
\end{code}
|
||||||
If `m ≤ᵇ n` is true then `≤ᵇ→≤` yields a proof that `m ≤ n` holds,
|
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.
|
while if it is false then `≤→≤ᵇ` takes a proof the `m ≤ n` holds into a contradiction.
|
||||||
|
@ -304,7 +304,7 @@ then Agda would make two complaints, one for each clause
|
||||||
T (m ≤ᵇ n) !=< ⊥ of type Set
|
T (m ≤ᵇ n) !=< ⊥ of type Set
|
||||||
when checking that the expression ≤→≤ᵇ {m} {n} has type ¬ m ≤ n
|
when checking that the expression ≤→≤ᵇ {m} {n} has type ¬ m ≤ n
|
||||||
|
|
||||||
Putting the expressions into the with clause permits Agda to exploit
|
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
|
the fact that `T (m ≤ᵇ n)` is `⊤` when `m ≤ᵇ n` is true, and that
|
||||||
`T (m ≤ᵇ n)` is `⊥` when `m ≤ᵇ n` is false.
|
`T (m ≤ᵇ n)` is `⊥` when `m ≤ᵇ n` is false.
|
||||||
|
|
||||||
|
@ -401,6 +401,11 @@ true ∨ _ = true
|
||||||
_ ∨ true = true
|
_ ∨ true = true
|
||||||
false ∨ false = false
|
false ∨ false = false
|
||||||
\end{code}
|
\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
|
Correspondingly, given two decidable propositions, we can
|
||||||
decide their disjunction.
|
decide their disjunction.
|
||||||
\begin{code}
|
\begin{code}
|
||||||
|
@ -417,6 +422,12 @@ If either holds, we inject the evidence to yield
|
||||||
evidence of the disjunct. If the negation of both hold,
|
evidence of the disjunct. If the negation of both hold,
|
||||||
assuming either disjunct will lead to a contradiction.
|
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,
|
The negation of a boolean is false if its argument is true,
|
||||||
and vice versa.
|
and vice versa.
|
||||||
\begin{code}
|
\begin{code}
|
||||||
|
@ -427,9 +438,9 @@ not false = true
|
||||||
Correspondingly, given a decidable proposition, we
|
Correspondingly, given a decidable proposition, we
|
||||||
can decide its negation.
|
can decide its negation.
|
||||||
\begin{code}
|
\begin{code}
|
||||||
not? : {A : Set} → Dec A → Dec (¬ A)
|
¬? : {A : Set} → Dec A → Dec (¬ A)
|
||||||
not? (yes x) = no λ{ ¬x → ¬x x }
|
¬? (yes x) = no (¬¬-intro x)
|
||||||
not? (no ¬x) = yes ¬x
|
¬? (no ¬x) = yes ¬x
|
||||||
\end{code}
|
\end{code}
|
||||||
We simply swap yes and no. In the first equation,
|
We simply swap yes and no. In the first equation,
|
||||||
the right-hand side asserts that the negation of `¬ A` holds,
|
the right-hand side asserts that the negation of `¬ A` holds,
|
||||||
|
@ -449,6 +460,10 @@ whenever the first is true then the second is true.
|
||||||
Hence, the implication of two booleans is true if
|
Hence, the implication of two booleans is true if
|
||||||
the second is true or the first is false,
|
the second is true or the first is false,
|
||||||
and false if the first is true and the second 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,
|
Correspondingly, given two decidable propositions,
|
||||||
we can decide if the first implies the second.
|
we can decide if the first implies the second.
|
||||||
|
@ -472,6 +487,12 @@ we apply the evidence of the implication `f` to the evidence of the
|
||||||
first `x`, yielding a contradiction with the evidence `¬y` of
|
first `x`, yielding a contradiction with the evidence `¬y` of
|
||||||
the negation of the second.
|
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.
|
||||||
|
|
||||||
|
|
||||||
## Decidability of All
|
## Decidability of All
|
||||||
|
|
||||||
Recall that in Chapter [Lists](Lists#All) we defined a predicate `All P`
|
Recall that in Chapter [Lists](Lists#All) we defined a predicate `All P`
|
||||||
|
@ -500,17 +521,17 @@ a function of type `A → Set`, taking a value `x` of type `A` into evidence
|
||||||
if we have a function that for a given `x` can decide `P x`.
|
if we have a function that for a given `x` can decide `P x`.
|
||||||
\begin{code}
|
\begin{code}
|
||||||
Decidable : ∀ {A : Set} → (A → Set) → Set
|
Decidable : ∀ {A : Set} → (A → Set) → Set
|
||||||
Decidable {A} P = (x : A) → Dec (P x)
|
Decidable {A} P = ∀ (x : A) → Dec (P x)
|
||||||
\end{code}
|
\end{code}
|
||||||
Then if predicate `P` is decidable, it is also decidable whether every
|
Then if predicate `P` is decidable, it is also decidable whether every
|
||||||
element of a list satisfies the predicate.
|
element of a list satisfies the predicate.
|
||||||
\begin{code}
|
\begin{code}
|
||||||
all? : ∀ {A : Set} {P : A → Set} → Decidable P → Decidable (All P)
|
All? : ∀ {A : Set} {P : A → Set} → Decidable P → Decidable (All P)
|
||||||
all? p? [] = yes []
|
All? P? [] = yes []
|
||||||
all? p? (x ∷ xs) with p? x | all? p? xs
|
All? P? (x ∷ xs) with P? x | All? P? xs
|
||||||
... | yes px | yes pxs = yes (px ∷ pxs)
|
... | yes Px | yes Pxs = yes (Px ∷ Pxs)
|
||||||
... | no ¬px | _ = no λ{ (px ∷ pxs) → ¬px px }
|
... | no ¬Px | _ = no λ{ (Px ∷ Pxs) → ¬Px Px }
|
||||||
... | _ | no ¬pxs = no λ{ (px ∷ pxs) → ¬pxs pxs }
|
... | _ | no ¬Pxs = no λ{ (Px ∷ Pxs) → ¬Pxs Pxs }
|
||||||
\end{code}
|
\end{code}
|
||||||
If the list is empty, then trivially `P` holds for every element of
|
If the list is empty, then trivially `P` holds for every element of
|
||||||
the list. Otherwise, the structure of the proof is similar to that
|
the list. Otherwise, the structure of the proof is similar to that
|
||||||
|
@ -525,8 +546,21 @@ predicate holds for every element of a list, so does `Any` have
|
||||||
analogues `any` and `any?` which determine whether a predicates holds
|
analogues `any` and `any?` which determine whether a predicates holds
|
||||||
for some element of a list. Give their definitions.
|
for some element of a list. Give their definitions.
|
||||||
|
|
||||||
<!-- import Data.List.All using (All; []; _∷_) renaming (all to all?) -->
|
## Standard Library
|
||||||
|
|
||||||
|
\begin{code}
|
||||||
|
import Data.Bool.Base using (Bool; 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
|
## Unicode
|
||||||
|
|
||||||
ᵇ U+1D47 MODIFIER LETTER SMALL B (\^b)
|
ᵇ U+1D47 MODIFIER LETTER SMALL B (\^b)
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ examples of polymorphic types and higher-order functions.
|
||||||
import Relation.Binary.PropositionalEquality as Eq
|
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
|
open import Data.Nat.Properties using
|
||||||
(+-assoc; +-identityˡ; +-identityʳ; *-assoc; *-identityˡ; *-identityʳ)
|
(+-assoc; +-identityˡ; +-identityʳ; *-assoc; *-identityˡ; *-identityʳ)
|
||||||
open import Relation.Nullary using (¬_)
|
open import Relation.Nullary using (¬_)
|
||||||
|
@ -343,8 +343,8 @@ 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
|
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
|
`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
|
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 - 1` is `n * (n - 1) / 2`.
|
||||||
(We will validate that last fact later in this chapter.)
|
(We will validate that last fact in an exercise later in this chapter.)
|
||||||
|
|
||||||
### Exercise (`reverse-++-commute`)
|
### Exercise (`reverse-++-commute`)
|
||||||
|
|
||||||
|
@ -544,8 +544,8 @@ 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.
|
Here is an example showing how to use fold to find the sum of a list.
|
||||||
\begin{code}
|
\begin{code}
|
||||||
ex₇ : foldr _+_ 0 [ 1 , 2 , 3 , 4 ] ≡ 10
|
_ : foldr _+_ 0 [ 1 , 2 , 3 , 4 ] ≡ 10
|
||||||
ex₇ =
|
_ =
|
||||||
begin
|
begin
|
||||||
foldr _+_ 0 (1 ∷ 2 ∷ 3 ∷ 4 ∷ [])
|
foldr _+_ 0 (1 ∷ 2 ∷ 3 ∷ 4 ∷ [])
|
||||||
≡⟨⟩
|
≡⟨⟩
|
||||||
|
@ -570,7 +570,14 @@ sum : List ℕ → ℕ
|
||||||
sum = foldr _+_ 0
|
sum = foldr _+_ 0
|
||||||
|
|
||||||
_ : sum [ 1 , 2 , 3 , 4 ] ≡ 10
|
_ : sum [ 1 , 2 , 3 , 4 ] ≡ 10
|
||||||
_ = ex₇
|
_ =
|
||||||
|
begin
|
||||||
|
sum [ 1 , 2 , 3 , 4 ]
|
||||||
|
≡⟨⟩
|
||||||
|
foldr _+_ 0 [ 1 , 2 , 3 , 4 ]
|
||||||
|
≡⟨⟩
|
||||||
|
10
|
||||||
|
∎
|
||||||
\end{code}
|
\end{code}
|
||||||
|
|
||||||
Just as the list type has two constructors, `[]` and `_∷_`,
|
Just as the list type has two constructors, `[]` and `_∷_`,
|
||||||
|
@ -579,13 +586,13 @@ 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* (`product`)
|
## 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-++`)
|
### Exercise (`foldr-++`)
|
||||||
|
|
||||||
Show that fold and append are related as follows.
|
Show that fold and append are related as follows.
|
||||||
\begin{code}
|
\begin{code}
|
||||||
|
@ -595,7 +602,7 @@ postulate
|
||||||
\end{code}
|
\end{code}
|
||||||
|
|
||||||
|
|
||||||
*Exercise* (`map-is-foldr`) <!-- `mapIsFold` in Data.List.Properties -->
|
### Exercise (`map-is-foldr`)
|
||||||
|
|
||||||
Show that map can be defined using fold.
|
Show that map can be defined using fold.
|
||||||
\begin{code}
|
\begin{code}
|
||||||
|
@ -605,6 +612,33 @@ postulate
|
||||||
\end{code}
|
\end{code}
|
||||||
This requires extensionality.
|
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
|
## Monoids
|
||||||
|
|
||||||
|
@ -828,9 +862,23 @@ Do we also have the following?
|
||||||
|
|
||||||
If so, prove; if not, explain why.
|
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)
|
||||||
|
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
|
## Unicode
|
||||||
|
|
||||||
|
This chapter uses the following unicode.
|
||||||
|
|
||||||
∷ U+2237 PROPORTION (\::)
|
∷ U+2237 PROPORTION (\::)
|
||||||
⊗ U+2297 CIRCLED TIMES (\otimes)
|
⊗ U+2297 CIRCLED TIMES (\otimes)
|
||||||
∈ U+2208 ELEMENT OF (\in)
|
∈ U+2208 ELEMENT OF (\in)
|
||||||
|
|
|
@ -290,8 +290,8 @@ just a couple of lines.
|
||||||
Here is the definition of addition in Agda:
|
Here is the definition of addition in Agda:
|
||||||
\begin{code}
|
\begin{code}
|
||||||
_+_ : ℕ → ℕ → ℕ
|
_+_ : ℕ → ℕ → ℕ
|
||||||
zero + n = n -- (i)
|
zero + n = n
|
||||||
(suc m) + n = suc (m + n) -- (ii)
|
(suc m) + n = suc (m + n)
|
||||||
\end{code}
|
\end{code}
|
||||||
|
|
||||||
Let's unpack this definition. Addition is an infix operator. It is
|
Let's unpack this definition. Addition is an infix operator. It is
|
||||||
|
|
|
@ -311,11 +311,9 @@ Stable A = ¬ ¬ A → A
|
||||||
Show that any negated formula is stable, and that the conjunction
|
Show that any negated formula is stable, and that the conjunction
|
||||||
of two stable formulas is stable.
|
of two stable formulas is stable.
|
||||||
\begin{code}
|
\begin{code}
|
||||||
¬-Stable : Set₁
|
postulate
|
||||||
¬-Stable = ∀ {A : Set} → Stable (¬ A)
|
¬-stable : ∀ {A : Set} → Stable (¬ A)
|
||||||
|
×-stable : ∀ {A B : Set} → Stable A → Stable B → Stable (A × B)
|
||||||
×-Stable : Set₁
|
|
||||||
×-Stable = ∀ {A B : Set} → Stable A → Stable B → Stable (A × B)
|
|
||||||
\end{code}
|
\end{code}
|
||||||
|
|
||||||
## Standard Prelude
|
## Standard Prelude
|
||||||
|
|
|
@ -8,8 +8,9 @@ permalink : /ListsAns
|
||||||
import Relation.Binary.PropositionalEquality as Eq
|
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 (ℕ; suc; zero; _+_; _*_)
|
open import Data.Nat using (ℕ; suc; zero; _+_; _*_; _∸_)
|
||||||
open import Data.Nat.Properties.Simple using (*-comm; distribʳ-*-+)
|
open import Data.Nat.Properties using (*-comm; *-distribˡ-+)
|
||||||
|
renaming (*-distribʳ-+ to funny-*-distribʳ-+)
|
||||||
open import Data.List using (List; []; _∷_; [_]; _++_; length; foldr)
|
open import Data.List using (List; []; _∷_; [_]; _++_; length; foldr)
|
||||||
open import Data.Product using (proj₁; proj₂)
|
open import Data.Product using (proj₁; proj₂)
|
||||||
\end{code}
|
\end{code}
|
||||||
|
@ -82,14 +83,6 @@ reverse [] = []
|
||||||
reverse (x ∷ xs) = reverse xs ++ [ x ]
|
reverse (x ∷ xs) = reverse xs ++ [ x ]
|
||||||
\end{code}
|
\end{code}
|
||||||
|
|
||||||
The proof of distribution of multiplication over addition from
|
|
||||||
the standard library takes its arguments in a strange order.
|
|
||||||
We fix that here.
|
|
||||||
\begin{code}
|
|
||||||
*-distrib-+ : ∀ (m n p : ℕ) → (m + n) * p ≡ m * p + n * p
|
|
||||||
*-distrib-+ m n p = distribʳ-*-+ p m n
|
|
||||||
\end{code}
|
|
||||||
|
|
||||||
|
|
||||||
## Reverse and append
|
## Reverse and append
|
||||||
|
|
||||||
|
@ -150,39 +143,44 @@ reverse-involutive (x ∷ xs) =
|
||||||
|
|
||||||
## Sum of count
|
## Sum of count
|
||||||
|
|
||||||
|
The proof of distribution of multiplication over addition from
|
||||||
|
the standard library takes its arguments in a strange order.
|
||||||
|
We fix that here.
|
||||||
|
\begin{code}
|
||||||
|
*-distribʳ-+ : ∀ (m n p : ℕ) → (m + n) * p ≡ m * p + n * p
|
||||||
|
*-distribʳ-+ m n p = funny-*-distribʳ-+ p m n
|
||||||
|
\end{code}
|
||||||
|
|
||||||
\begin{code}
|
\begin{code}
|
||||||
sum : List ℕ → ℕ
|
sum : List ℕ → ℕ
|
||||||
sum = foldr _+_ 0
|
sum = foldr _+_ 0
|
||||||
|
|
||||||
countdown : ℕ → List ℕ
|
downFrom : ℕ → List ℕ
|
||||||
countdown zero = []
|
downFrom zero = []
|
||||||
countdown (suc n) = suc n ∷ countdown n
|
downFrom (suc n) = n ∷ downFrom n
|
||||||
|
|
||||||
infix 6 _+
|
|
||||||
|
|
||||||
_+ : ℕ → ℕ → ℕ
|
|
||||||
(m +) n = m + n
|
|
||||||
|
|
||||||
cong2 : ∀ {A B C : Set} {x x′ : A} {y y′ : B} →
|
cong2 : ∀ {A B C : Set} {x x′ : A} {y y′ : B} →
|
||||||
(f : A → B → C) → (x ≡ x′) → (y ≡ y′) → (f x y ≡ f x′ y′)
|
(f : A → B → C) → (x ≡ x′) → (y ≡ y′) → (f x y ≡ f x′ y′)
|
||||||
cong2 f x≡x′ y≡y′ rewrite x≡x′ | y≡y′ = refl
|
cong2 f x≡x′ y≡y′ rewrite x≡x′ | y≡y′ = refl
|
||||||
|
|
||||||
sum-countdown : ∀ (n : ℕ) → sum (countdown n) * 2 ≡ suc n * n
|
sum-downFrom : ∀ (n : ℕ) → sum (downFrom n) * 2 ≡ n * (n ∸ 1)
|
||||||
sum-countdown zero = refl
|
sum-downFrom zero = refl
|
||||||
sum-countdown (suc n) =
|
sum-downFrom (suc zero) = refl
|
||||||
|
sum-downFrom (suc (suc n)) =
|
||||||
begin
|
begin
|
||||||
sum (countdown (suc n)) * 2
|
sum (downFrom (suc (suc n))) * 2
|
||||||
≡⟨⟩
|
≡⟨⟩
|
||||||
sum (suc n ∷ countdown n) * 2
|
sum (suc n ∷ downFrom (suc n)) * 2
|
||||||
≡⟨⟩
|
≡⟨⟩
|
||||||
(suc n + sum (countdown n)) * 2
|
(suc n + sum (downFrom (suc n))) * 2
|
||||||
≡⟨ *-distrib-+ (suc n) (sum (countdown n)) 2 ⟩
|
≡⟨ *-distribʳ-+ (suc n) (sum (downFrom (suc n))) 2 ⟩
|
||||||
suc n * 2 + sum (countdown n) * 2
|
suc n * 2 + sum (downFrom (suc n)) * 2
|
||||||
≡⟨ cong (suc n * 2 +) (sum-countdown n) ⟩
|
≡⟨ cong (suc n * 2 +_) (sum-downFrom (suc n)) ⟩
|
||||||
suc n * 2 + suc n * n
|
suc n * 2 + suc n * n
|
||||||
≡⟨ cong2 _+_ (*-comm (suc n) 2) (*-comm (suc n) n) ⟩
|
≡⟨ sym (*-distribˡ-+ (suc n) 2 n) ⟩
|
||||||
2 * suc n + n * suc n
|
suc n * (2 + n)
|
||||||
≡⟨ sym (*-distrib-+ 2 n (suc n))⟩
|
≡⟨ *-comm (suc n) (2 + n) ⟩
|
||||||
(2 + n) * suc n
|
suc (suc n) * suc n
|
||||||
∎
|
∎
|
||||||
\end{code}
|
\end{code}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue