refinements to Basics

This commit is contained in:
Philip Wadler 2017-10-03 12:59:23 +01:00
parent 964ed65922
commit 3f10630ab8
2 changed files with 236 additions and 0 deletions

99
src/Basics0.lagda Normal file
View file

@ -0,0 +1,99 @@
---
title : "Basics: Functional Programming in Agda"
layout : page
permalink : /Basics
---
\begin{code}
open import Data.Empty using (⊥; ⊥-elim)
open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Binary.PropositionalEquality
using (_≡_; refl; _≢_; trans; sym)
\end{code}
# Natural numbers
\begin{code}
data : Set where
zero :
suc :
{-# BUILTIN NATURAL #-}
\end{code}
\begin{code}
congruent : ∀ {m n} → m ≡ n → suc m ≡ suc n
congruent refl = refl
injective : ∀ {m n} → suc m ≡ suc n → m ≡ n
injective refl = refl
distinct : ∀ {m} → zero ≢ suc m
distinct ()
\end{code}
\begin{code}
_≟_ : ∀ (m n : ) → Dec (m ≡ n)
zero ≟ zero = yes refl
zero ≟ suc n = no (λ())
suc m ≟ zero = no (λ())
suc m ≟ suc n with m ≟ n
... | yes refl = yes refl
... | no p = no (λ r → p (injective r))
\end{code}
# Addition and its properties
\begin{code}
_+_ :
zero + n = n
suc m + n = suc (m + n)
\end{code}
\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
+-zero : ∀ m → m + zero ≡ m
+-zero zero = refl
+-zero (suc m) rewrite +-zero m = refl
+-suc : ∀ m n → m + (suc n) ≡ suc (m + n)
+-suc zero n = refl
+-suc (suc m) n rewrite +-suc m n = refl
+-comm : ∀ m n → m + n ≡ n + m
+-comm m zero = +-zero m
+-comm m (suc n) rewrite +-suc m n | +-comm m n = refl
\end{code}
# Equality and decidable equality for naturals
# Showing `double` injective
\begin{code}
double :
double zero = zero
double (suc n) = suc (suc (double n))
\end{code}
\begin{code}
double-injective : ∀ m n → double m ≡ double n → m ≡ n
double-injective zero zero refl = refl
double-injective zero (suc n) ()
double-injective (suc m) zero ()
double-injective (suc m) (suc n) r =
congruent (double-injective m n (injective (injective r)))
\end{code}
In Coq, the inductive proof for `double-injective`
is sensitive to how one inducts on `m` and `n`. In Agda, that aspect
is straightforward. However, Agda requires helper functions for
injection and congruence which are not required in Coq.
I can remove the use of `congruent` by rewriting with its argument.
Is there an easy way to remove the two uses of `injective`?

137
src/extra/Basics-old.lagda Normal file
View file

@ -0,0 +1,137 @@
---
title : "Basics: Functional Programming in Agda"
layout : page
permalink : /Basics
---
\begin{code}
open import Relation.Binary.PropositionalEquality using (_≡_; refl)
\end{code}
The functional programming style brings programming closer to
simple, everyday mathematics: If a procedure or method has no side
effects, then (ignoring efficiency) all we need to understand
about it is how it maps inputs to outputs -- that is, we can think
of it as just a concrete method for computing a mathematical
function. This is one sense of the word "functional" in
"functional programming." The direct connection between programs
and simple mathematical objects supports both formal correctness
proofs and sound informal reasoning about program behavior.
The other sense in which functional programming is "functional" is
that it emphasizes the use of functions (or methods) as
_first-class_ values -- i.e., values that can be passed as
arguments to other functions, returned as results, included in
data structures, etc. The recognition that functions can be
treated as data in this way enables a host of useful and powerful
idioms.
Other common features of functional languages include _algebraic
data types_ and _pattern matching_, which make it easy to
construct and manipulate rich data structures, and sophisticated
_polymorphic type systems_ supporting abstraction and code reuse.
Agda shares all of these features.
This chapter introduces the most essential elements of Agda.
## Enumerated Types
One unusual aspect of Agda is that its set of built-in
features is _extremely_ small. For example, instead of providing
the usual palette of atomic data types (booleans, integers,
strings, etc.), Agda offers a powerful mechanism for defining new
data types from scratch, from which all these familiar types arise
as instances.
Naturally, the Agda distribution comes with an extensive standard
library providing definitions of booleans, numbers, and many
common data structures like lists and hash tables. But there is
nothing magic or primitive about these library definitions. To
illustrate this, we will explicitly recapitulate all the
definitions we need in this course, rather than just getting them
implicitly from the library.
To see how this definition mechanism works, let's start with a
very simple example.
### Days of the Week
The following declaration tells Agda that we are defining
a new set of data values -- a _type_.
\begin{code}
data Day : Set where
monday : Day
tuesday : Day
wednesday : Day
thursday : Day
friday : Day
saturday : Day
sunday : Day
\end{code}
The type is called `day`, and its members are `monday`,
`tuesday`, etc. The second and following lines of the definition
can be read "`monday` is a `day`, `tuesday` is a `day`, etc."
Having defined `day`, we can write functions that operate on
days.
\begin{code}
nextWeekday : Day -> Day
nextWeekday monday = tuesday
nextWeekday tuesday = wednesday
nextWeekday wednesday = thursday
nextWeekday thursday = friday
nextWeekday friday = monday
nextWeekday saturday = monday
nextWeekday sunday = monday
\end{code}
One thing to note is that the argument and return types of
this function are explicitly declared. Like most functional
programming languages, Agda can often figure out these types for
itself when they are not given explicitly -- i.e., it performs
_type inference_ -- but we'll include them to make reading
easier.
Having defined a function, we should check that it works on
some examples. There are actually three different ways to do this
in Agda.
First, we can use the Emacs command `C-c C-n` to evaluate a
compound expression involving `nextWeekday`. For instance, `nextWeekday
friday` should evaluate to `monday`. If you have a computer handy, this
would be an excellent moment to fire up Agda and try this for yourself.
Load this file, `Basics.lagda`, load it using `C-c C-l`, submit the
above example to Agda, and observe the result.
Second, we can record what we _expect_ the result to be in the
form of an Agda type:
\begin{code}
test-nextWeekday : nextWeekday (nextWeekday saturday) ≡ tuesday
\end{code}
This declaration does two things: it makes an assertion (that the second
weekday after `saturday` is `tuesday`), and it gives the assertion a name
that can be used to refer to it later.
Having made the assertion, we must also verify it. We do this by giving
a term of the above type:
\begin{code}
test-nextWeekday = refl
\end{code}
There is no essential difference between the definition for
`test-nextWeekday` here and the definition for `nextWeekday` above,
except for the new symbol for equality `≡` and the constructor `refl`.
The details of these are not important for now (we'll come back to them in
a bit), but essentially `refl` can be read as "The assertion we've made
can be proved by observing that both sides of the equality evaluate to the
same thing, after some simplification."
Third, we can ask Agda to _compile_ some program involving our definition,
This facility is very interesting, since it gives us a way to construct
_fully certified_ programs. We'll come back to this topic in later chapters.