finished proof of assoc+
This commit is contained in:
parent
7c7ecbe950
commit
bf6c5a0602
4 changed files with 203 additions and 66 deletions
|
@ -47,7 +47,7 @@ https://github.com/agda/agda/blob/master/src/data/emacs-mode/agda-input.el#L194
|
|||
## Bindings for Agda mode
|
||||
|
||||
? create hole
|
||||
{!...!} create holde
|
||||
{!...!} create hole
|
||||
C-c C-l reload
|
||||
C-c C-c x split on variable x
|
||||
C-c C-space fill in hole
|
||||
|
|
1
index.md
1
index.md
|
@ -22,6 +22,7 @@ http://homepages.inf.ed.ac.uk/wadler/
|
|||
-->
|
||||
|
||||
- [Naturals: Natural numbers]({{ "/Naturals" | relative_url }})
|
||||
- [Properties: Proof by induction]({{ "/Properties" | relative_url }})
|
||||
- [Maps: Total and Partial Maps]({{ "/Maps" | relative_url }})
|
||||
- [Stlc: The Simply Typed Lambda-Calculus]({{ "/Stlc" | relative_url }})
|
||||
- [StlcProp: Properties of STLC]({{ "/StlcProp" | relative_url }})
|
||||
|
|
|
@ -42,9 +42,9 @@ as a pair of inference rules:
|
|||
--------
|
||||
zero : ℕ
|
||||
|
||||
n : ℕ
|
||||
m : ℕ
|
||||
---------
|
||||
suc n : ℕ
|
||||
suc m : ℕ
|
||||
|
||||
And here is the definition in Agda:
|
||||
\begin{code}
|
||||
|
@ -58,8 +58,9 @@ and `zero` and `suc` (short for *successor*) are the
|
|||
|
||||
Both definitions above tell us the same two things:
|
||||
|
||||
1. The term `zero` is a natural number.
|
||||
2. If `n` is a natural number, then the term `suc n` is also a natural number.
|
||||
+ *Base case*: `zero` is a natural number.
|
||||
+ *Inductive case*: if `m` is a natural number, then `suc m` is also a
|
||||
natural number.
|
||||
|
||||
Further, these two rules give the *only* ways of creating natural numbers.
|
||||
Hence, the possible natural numbers are
|
||||
|
@ -81,14 +82,14 @@ successor of two; and so on.
|
|||
|
||||
## Unpacking the inference rules
|
||||
|
||||
Let's unpack the inference rules. Each inference rule consists of zero
|
||||
or more *judgments* written above a horizontal line, called the *hypotheses*,
|
||||
and a single judgment written below, called the *conclusion*.
|
||||
|
||||
The first rule has no hypotheses, and the conclusion asserts that zero
|
||||
is a natural. The second rule has one hypothesis, which assumes that
|
||||
`n` is a natural number, and the conclusion asserts that `suc n` is a
|
||||
natural number.
|
||||
Let's unpack the inference rules. Each inference rule consists of
|
||||
zero or more *judgments* written above a horizontal line, called the
|
||||
*hypotheses*, and a single judgment written below, called the
|
||||
*conclusion*. The first rule is the base case. It has no hypotheses,
|
||||
and the conclusion asserts that `zero` is a natural. The second rule
|
||||
is the inductive case. It has one hypothesis, which assumes that `m`
|
||||
is a natural, and the conclusion asserts that `suc n` is a also a
|
||||
natural.
|
||||
|
||||
|
||||
## Unpacking the Agda definition
|
||||
|
@ -112,18 +113,20 @@ corresponding `data` declaration. The lines
|
|||
tell us that `zero` is a natural number and that `suc` takes a natural
|
||||
number as argument and returns a natural number.
|
||||
|
||||
Here `ℕ` and `→` are unicode symbols that you won't find on your
|
||||
keyboard. At the end of each chapter is a list of all the unicode used
|
||||
in the chapter, including instructions on how to type them in the
|
||||
Emacs text editor.
|
||||
You may have notices that `ℕ` and `→` are don't appear on your
|
||||
keyboard. They are symbols in *unicode*. At the end of each chapter
|
||||
is a list of all the unicode used in the chapter, including
|
||||
instructions on how to type them in the Emacs text editor using keys
|
||||
that are on your keyboard.
|
||||
|
||||
|
||||
## The story of creation
|
||||
|
||||
Let's look again at the definition of natural numbers:
|
||||
|
||||
1. The term `zero` is a natural number.
|
||||
2. If `n` is a natural number, then the term `suc n` is also a natural number.
|
||||
+ *Base case*: `zero` is a natural number.
|
||||
+ *Inductive case*: if `m` is a natural number, then `suc m` is also a
|
||||
natural number.
|
||||
|
||||
Wait a minute! The second line defines natural numbers
|
||||
in terms of natural numbers. How can that posssibly be allowed?
|
||||
|
@ -139,28 +142,27 @@ no natural numbers at all.
|
|||
|
||||
-- in the beginning, there are no natural numbers
|
||||
|
||||
Now, we apply the rules to all the natural numbers we know about. One
|
||||
rule tells us that `zero` is a natural number, so we add it to the set
|
||||
of known natural numbers. The other rule tells us that if `n` is a
|
||||
natural number (on the day before today) then `suc n` is also a
|
||||
Now, we apply the two cases to all the natural numbers we know about. The
|
||||
base case tells us that `zero` is a natural number, so we add it to the set
|
||||
of known natural numbers. The inductive case tells us that if `m` is a
|
||||
natural number (on the day before today) then `suc m` is also a
|
||||
natural number (today). We didn't know about any natural numbers
|
||||
before today, so we don't add any natural numbers of the form `suc n`.
|
||||
before today, so the inductive case doesn't apply.
|
||||
|
||||
-- on the first day, there is one natural number
|
||||
zero
|
||||
|
||||
Then we repeat the process, so on the next day we know about all the
|
||||
numbers from the day before, plus any numbers added by the rules. One
|
||||
rule tells us that `zero` is a natural number, but we already knew
|
||||
that. But now the other rule tells us that since `zero` was a natural
|
||||
number yesterday, `suc zero` is a natural number today.
|
||||
numbers from the day before, plus any numbers added by the two cases. The
|
||||
base case tells us that `zero` is a natural number, but we already knew
|
||||
that. But now the inductive case tells us that since `zero` was a natural
|
||||
number yesterday, then `suc zero` is a natural number today.
|
||||
|
||||
-- on the second day, there are two natural numbers
|
||||
zero
|
||||
suc zero
|
||||
|
||||
And we repeat the process again. Once more, one rule tells us what
|
||||
we already knew, that `zero` is a natural number. And now the other rule
|
||||
And we repeat the process again. Now the inductive case
|
||||
tells us that since `zero` and `suc zero` are both natural numbers, then
|
||||
`suc zero` and `suc (suc zero)` are natural numbers. We already knew about
|
||||
the first of these, but the second is new.
|
||||
|
@ -179,9 +181,8 @@ You've probably got the hang of it by now.
|
|||
suc (suc (suc zero))
|
||||
|
||||
The process continues. On the *n*th day there will be *n* distinct
|
||||
natural numbers. Note that in this way, we only talk about finite sets
|
||||
of numbers. Every natural number will appear on some given finite
|
||||
day. In particular, the number *n* first appears on day *n+1*. And we
|
||||
natural numbers. Every natural number will appear on some given day.
|
||||
In particular, the number *n* first appears on day *n+1*. And we
|
||||
never actually define the set of numbers in terms of itself. Instead,
|
||||
we define the set of numbers on day *n+1* in terms of the set of
|
||||
numbers on day *n*.
|
||||
|
@ -203,10 +204,10 @@ A philosopher might note that our reference to the first day, second
|
|||
day, and so on, implicitly involves an understanding of natural
|
||||
numbers. In this sense, our definition might indeed be regarded as in
|
||||
some sense circular. We won't worry about the philosophy, but are ok
|
||||
with taking some intuitive notions---such as counting---as given.
|
||||
with taking some intuitive notions--such as counting--as given.
|
||||
|
||||
While the natural numbers have been understood for as long as people
|
||||
could count, this way of viewing the natural numbers is relatively
|
||||
could count, the inductive definition of the natural numbers is relatively
|
||||
recent. It can be traced back to Richard Dedekind's paper "*Was sind
|
||||
und was sollen die Zahlen?*" (What are and what should be the
|
||||
numbers?), published in 1888, and Giuseppe Peano's book "*Arithmetices
|
||||
|
@ -243,14 +244,13 @@ a machine with 64-bit words.
|
|||
## Operations on naturals are recursive functions
|
||||
|
||||
Now that we have the natural numbers, what can we do with them?
|
||||
An obvious first step is to define basic operations such as
|
||||
addition and multiplication.
|
||||
For instance, can we define arithmetic operations such as
|
||||
addition and multiplication?
|
||||
|
||||
As a child I spent much time memorising tables of addition and
|
||||
multiplication. At first the rules seemed tricky and I would often
|
||||
make mistakes. So it came as a shock to realise that all of addition
|
||||
can be precisely defined in just a couple of lines, and the same is true of
|
||||
multiplication.
|
||||
make mistakes. So it came as a shock to me to realise that all of addition
|
||||
and multiplication can be precisely defined in just a couple of lines.
|
||||
|
||||
Here is the definition of addition in Agda:
|
||||
\begin{code}
|
||||
|
|
|
@ -4,22 +4,23 @@ layout : page
|
|||
permalink : /Properties
|
||||
---
|
||||
|
||||
Now that we've defined the naturals and operations upon them,
|
||||
our next step is to learn how to prove properties that they
|
||||
satisfy. Unsurprisingly, properties of *inductive datatypes*
|
||||
are proved by *induction*.
|
||||
Now that we've defined the naturals and operations upon them, our next
|
||||
step is to learn how to prove properties that they satisfy. As hinted
|
||||
by their name, properties of *inductive datatypes* are proved by
|
||||
*induction*.
|
||||
|
||||
|
||||
## Imports
|
||||
|
||||
Each chapter will begin with a list of the imports we require from the
|
||||
Agda standard library. We will, of course, require the naturals;
|
||||
Agda standard library.
|
||||
|
||||
<!-- We will, of course, require the naturals;
|
||||
everything in the previous chapter is also found in the library module
|
||||
`Data.Nat`, so we import the required definitions from there. We also
|
||||
require propositional equality.
|
||||
`Data.Nat`, so we import the required definitions from there.
|
||||
We also require propositional equality. -->
|
||||
|
||||
\begin{code}
|
||||
open import Data.Nat using (ℕ; zero; suc)
|
||||
open import Relation.Binary.PropositionalEquality using (_≡_; refl)
|
||||
\end{code}
|
||||
|
||||
|
@ -54,18 +55,40 @@ variables.
|
|||
3 + (4 + 5)
|
||||
|
||||
Here we have displayed the computation in tabular form, one term to a
|
||||
line. We will often use such a form. It is often easiest to read
|
||||
such computations from the top down until one reaches the simplest
|
||||
possible term (in this case, 12), and then from the bottom up until
|
||||
one reaches the same term.
|
||||
line. It is often easiest to read such computations from the top down
|
||||
until one reaches the simplest term (in this case, `12`), and
|
||||
then from the bottom up until one reaches the same term.
|
||||
|
||||
We could go on testing the proposition by choosing other numbers, but---since there are an infinite number of naturals---we will never finish.
|
||||
The test reveals that associativity is perhaps not as obvious as first
|
||||
it appears. Why should `7 + 5` be the same as `3 + 9`? We might want
|
||||
to gather more evidence, testing the proposition by choosing other
|
||||
numbers. But---since there are an infinite number of
|
||||
naturals---testing can never be complete. Is there any way we can be
|
||||
sure that associativity holds for *all* the natural numbers?
|
||||
|
||||
The answer is yes! We can prove a property holds for all naturals using
|
||||
*proof by induction*.
|
||||
|
||||
|
||||
## Proof by induction
|
||||
|
||||
Recall the definition of natural numbers.
|
||||
\begin{code}
|
||||
data ℕ : Set where
|
||||
zero : ℕ
|
||||
suc : ℕ → ℕ
|
||||
\end{code}
|
||||
This tells us that `zero` is a natural--the *base case*--and that if
|
||||
`m` is a natural then `suc m` is also a natural---the *inductive
|
||||
case*.
|
||||
|
||||
Proofs by induction follow the structure of this definition. To prove
|
||||
a property of natural numbers by induction, we need prove two cases.
|
||||
First is the *base case*, where we need to show the property holds for
|
||||
`zero`. Second is the *inductive case*, where we assume as the
|
||||
*inductive hypothesis* that the property holds for an arbitary natural
|
||||
`m` and then show that the property must also hold for `suc m`.
|
||||
|
||||
To prove a property of natural numbers by induction, we need to prove two things.
|
||||
First, we prove the property holds for `zero`, and secondly we prove that if
|
||||
the property holds for an arbitrary natural `m` then it also holds for `suc m`.
|
||||
If we write `P m` for a property of `m`, then we can write out the principle
|
||||
of induction as an inference rule:
|
||||
|
||||
|
@ -74,13 +97,61 @@ of induction as an inference rule:
|
|||
-----------------------------
|
||||
∀ (m : ℕ) → P m
|
||||
|
||||
Let's unpack this rule. The first hypothesis states
|
||||
that property `P` holds for `zero`. The second hypothesis states that for all natural
|
||||
numbers `m`, if `P` holds for `m` then `P` also holds for `suc m`. The conclusion
|
||||
states that for all natural numbers `m` we have that `P` holds for `m`.
|
||||
We call the first hypothesis the *base case*; it requires we show `P zero`.
|
||||
We call the second hypothesis the *inductive case*; it requires we assume `P m`, which
|
||||
we call the *induction hypothesis*, and use it to show `P (suc m)`.
|
||||
Let's unpack this rule. The first hypothesis is the base case, and
|
||||
requires we show that property `P` holds for `zero`. The second
|
||||
hypothesis is the inductive case, and requires that for any natural
|
||||
`m` assuming the the induction hypothesis `P` holds for `m` we must
|
||||
then show that `P` also holds for `suc m`.
|
||||
|
||||
Why does this work? Again, it can be explained by a creation story.
|
||||
To start with, we know no properties.
|
||||
|
||||
-- in the beginning, no properties are known
|
||||
|
||||
Now, we apply the two cases to all the properties we know about. The
|
||||
base case tells us that `P zero` holds, so we add it to the set of
|
||||
known properties. The inductive case tells us that if `P m` holds (on
|
||||
the day before today) then `P (suc m)` also holds (today). We didn't
|
||||
know about any properties before today, so the inductive case doesn't
|
||||
apply.
|
||||
|
||||
-- on the first day, one property is known
|
||||
P zero
|
||||
|
||||
Then we repeat the process, so on the next day we know about all the
|
||||
properties from the day before, plus any properties added by the two
|
||||
cases. The base case tells us that `P zero` holds, but we already
|
||||
knew that. But now the inductive case tells us that since `P zero`
|
||||
held yesterday, then `P (suc zero)` holds today.
|
||||
|
||||
-- on the second day, two properties are known
|
||||
P zero
|
||||
P (suc zero)
|
||||
|
||||
And we repeat the process again. Now the inductive case
|
||||
tells us that since `P zero` and `P (suc zero)` both hold, then
|
||||
`P (suc zero)` and `P (suc (suc zero))` also hold. We already knew about
|
||||
the first of these, but the second is new.
|
||||
|
||||
-- on the third day, three properties are known
|
||||
P zero
|
||||
P (suc zero)
|
||||
P (suc (suc zero))
|
||||
|
||||
You've probably got the hang of it by now.
|
||||
|
||||
-- on the fourth day, four properties are known
|
||||
P zero
|
||||
P (suc zero)
|
||||
P (suc (suc zero))
|
||||
P (suc (suc (suc zero)))
|
||||
|
||||
The process continues. On the *n*th day there will be *n* distinct
|
||||
properties that hold. The property of every natural number will appear
|
||||
on some given day. In particular, the property `P n` first appears on
|
||||
day *n+1*.
|
||||
|
||||
## Our first proof: associativity
|
||||
|
||||
In order to prove associativity, we take `P m` to be the property
|
||||
|
||||
|
@ -108,7 +179,7 @@ For the base case, we must show:
|
|||
(zero + n) + p ≡ zero + (n + p)
|
||||
|
||||
By (i), both sides of the equation simplify to `n + p`, so it holds.
|
||||
In tabular form, we write this as follows:
|
||||
In tabular form we have:
|
||||
|
||||
(zero + n) + p
|
||||
≡ (i)
|
||||
|
@ -116,8 +187,9 @@ In tabular form, we write this as follows:
|
|||
≡ (i)
|
||||
zero + (n + p)
|
||||
|
||||
It is often easiest to read such proofs down from the top and up from
|
||||
the bottom, meeting in the middle where the two terms are the same.
|
||||
Again, it is easiest to read from the top down until one reaches the
|
||||
simplest term (`n + p`), and then from the bottom up
|
||||
until one reaches the same term.
|
||||
|
||||
For the inductive case, we assume
|
||||
|
||||
|
@ -141,9 +213,73 @@ these follow from what we assumed. In tabular form:
|
|||
≡ (ii)
|
||||
suc m + (n + p)
|
||||
|
||||
Here it is easiest to read from the top down until one reaches the
|
||||
simplest term (`suc ((m + n) + p)`), and then from the bottom up until
|
||||
one reaches the simplest term (`suc (m + (n + p))`). In this case,
|
||||
the two simplest terms are not the same, but are equated by the
|
||||
induction hypothesis.
|
||||
|
||||
## Encoding the proof in Agda
|
||||
|
||||
We can encode this proof in Agda as follows.
|
||||
\begin{code}
|
||||
assoc+ : ∀ (m n p : ℕ) → (m + n) + p ≡ m + (n + p)
|
||||
assoc+ zero n p = refl
|
||||
assoc+ (suc m) n p rewrite assoc+ m n p = refl
|
||||
\end{code}
|
||||
Here we have named the proof `assoc+`. In Agda, identifiers can consist of
|
||||
any sequence of characters not including spaces or the characters `@.(){};_`.
|
||||
|
||||
Let's unpack this code. The first line states that we are
|
||||
defining the identifier `assoc+` which is a proof of the
|
||||
proposition
|
||||
|
||||
∀ (m n p : ℕ) → (m + n) + p ≡ m + (n + p)
|
||||
|
||||
Such a proof is a function that takes three natural
|
||||
numbers---corresponding to `m`, `n`, and `p`---and returns
|
||||
a proof of the proposition `(m + n) + p ≡ m + (n + p)`.
|
||||
Proof by induction corresponds exactly to a recursive
|
||||
definition. Here we are inducting on the first
|
||||
argument `m`, and leaving the other two arguments `n` and `p`
|
||||
fixed.
|
||||
|
||||
The base case corresponds to instantiating `m` by
|
||||
pattern matching on `zero`, so what we are required to
|
||||
prove is:
|
||||
|
||||
(zero + n) + p ≡ zero + (n + p)
|
||||
|
||||
After simplifying with the definition of addition, this equation
|
||||
becomes:
|
||||
|
||||
n + p ≡ n + p
|
||||
|
||||
The proof that a term is equal to itself is written `refl`.
|
||||
|
||||
The inductive case corresponds to instantiating `m` by `suc zero`,
|
||||
so what we are required to prove is:
|
||||
|
||||
(suc m + n) + p ≡ suc m + (n + p)
|
||||
|
||||
After simplifying with the definition of addition, this equation
|
||||
becomes:
|
||||
|
||||
suc ((m + n) + p) ≡ suc (m + (n + p))
|
||||
|
||||
After rewriting with the inductive hypothesis these two terms are
|
||||
equal, and the proof is again given by `refl`.
|
||||
|
||||
Rewriting by a given equation is indicated by the keyword `rewrite`
|
||||
followed by a proof of that equation. Here the inductive hypothesis
|
||||
is not assumed, but instead proved by a recursive invocation of the
|
||||
function we are definining, `assoc+ m n p`. As with addition, this is
|
||||
well founded because associativity of larger numbers is defined in
|
||||
terms of associativity of smaller numbers. In this case,
|
||||
`assoc (suc m) n p` is defined in terms of `assoc m n p`.
|
||||
|
||||
This correspondence between proof by induction and definition by
|
||||
recursion is one of the most appealing aspects of Agda.
|
||||
|
||||
## Unicode
|
||||
|
||||
|
|
Loading…
Reference in a new issue