2020-06-04 02:46:06 +00:00
|
|
|
(** * Basics: Functional Programming in Coq *)
|
|
|
|
|
|
|
|
(* REMINDER:
|
|
|
|
|
|
|
|
#####################################################
|
|
|
|
### PLEASE DO NOT DISTRIBUTE SOLUTIONS PUBLICLY ###
|
|
|
|
#####################################################
|
|
|
|
|
|
|
|
(See the [Preface] for why.)
|
|
|
|
*)
|
|
|
|
|
|
|
|
(* ################################################################# *)
|
|
|
|
(** * Introduction *)
|
|
|
|
|
|
|
|
(** The functional programming style is founded on simple, everyday
|
|
|
|
mathematical intuition: 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 gives rise to a host of useful and powerful
|
|
|
|
programming 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.
|
|
|
|
Coq offers all of these features.
|
|
|
|
|
|
|
|
The first half of this chapter introduces the most essential
|
|
|
|
elements of Coq's functional programming language, called
|
|
|
|
_Gallina_. The second half introduces some basic _tactics_ that
|
|
|
|
can be used to prove properties of Coq programs. *)
|
|
|
|
|
|
|
|
(* ################################################################# *)
|
|
|
|
(** * Data and Functions *)
|
|
|
|
(* ================================================================= *)
|
|
|
|
(** ** Enumerated Types *)
|
|
|
|
|
|
|
|
(** One notable aspect of Coq 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.), Coq offers a powerful mechanism for defining new
|
|
|
|
data types from scratch, with all these familiar types as
|
|
|
|
instances.
|
|
|
|
|
|
|
|
Naturally, the Coq distribution comes preloaded 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. *)
|
|
|
|
|
|
|
|
(* ================================================================= *)
|
|
|
|
(** ** Days of the Week *)
|
|
|
|
|
|
|
|
(** To see how this definition mechanism works, let's start with
|
|
|
|
a very simple example. The following declaration tells Coq that
|
|
|
|
we are defining a new set of data values -- a _type_. *)
|
|
|
|
|
|
|
|
Inductive day : Type :=
|
|
|
|
| monday
|
|
|
|
| tuesday
|
|
|
|
| wednesday
|
|
|
|
| thursday
|
|
|
|
| friday
|
|
|
|
| saturday
|
|
|
|
| sunday.
|
|
|
|
|
|
|
|
(** The type is called [day], and its members are [monday],
|
|
|
|
[tuesday], etc.
|
|
|
|
|
|
|
|
Having defined [day], we can write functions that operate on
|
|
|
|
days. *)
|
|
|
|
|
|
|
|
Definition next_weekday (d:day) : day :=
|
|
|
|
match d with
|
|
|
|
| monday => tuesday
|
|
|
|
| tuesday => wednesday
|
|
|
|
| wednesday => thursday
|
|
|
|
| thursday => friday
|
|
|
|
| friday => monday
|
|
|
|
| saturday => monday
|
|
|
|
| sunday => monday
|
|
|
|
end.
|
|
|
|
|
|
|
|
(** One thing to note is that the argument and return types of
|
|
|
|
this function are explicitly declared. Like most functional
|
|
|
|
programming languages, Coq can often figure out these types for
|
|
|
|
itself when they are not given explicitly -- i.e., it can do _type
|
|
|
|
inference_ -- but we'll generally 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 Coq. First, we can use the command [Compute] to evaluate a
|
|
|
|
compound expression involving [next_weekday]. *)
|
|
|
|
|
|
|
|
Compute (next_weekday friday).
|
|
|
|
(* ==> monday : day *)
|
|
|
|
|
|
|
|
Compute (next_weekday (next_weekday saturday)).
|
|
|
|
(* ==> tuesday : day *)
|
|
|
|
|
|
|
|
(** (We show Coq's responses in comments, but, if you have a
|
|
|
|
computer handy, this would be an excellent moment to fire up the
|
|
|
|
Coq interpreter under your favorite IDE -- either CoqIde or Proof
|
|
|
|
General -- and try this for yourself. Load this file, [Basics.v],
|
|
|
|
from the book's Coq sources, find the above example, submit it to
|
|
|
|
Coq, and observe the result.) *)
|
|
|
|
|
|
|
|
(** Second, we can record what we _expect_ the result to be in the
|
|
|
|
form of a Coq example: *)
|
|
|
|
|
|
|
|
Example test_next_weekday:
|
|
|
|
(next_weekday (next_weekday saturday)) = tuesday.
|
|
|
|
|
|
|
|
(** 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 can also ask Coq to verify
|
|
|
|
it, like this: *)
|
|
|
|
|
|
|
|
Proof. simpl. reflexivity. Qed.
|
|
|
|
|
|
|
|
(** The details are not important for now (we'll come back to
|
|
|
|
them in a bit), but essentially this can be read as "The assertion
|
|
|
|
we've just made can be proved by observing that both sides of the
|
|
|
|
equality evaluate to the same thing, after some simplification."
|
|
|
|
|
|
|
|
Third, we can ask Coq to _extract_, from our [Definition], a
|
|
|
|
program in some other, more conventional, programming
|
|
|
|
language (OCaml, Scheme, or Haskell) with a high-performance
|
|
|
|
compiler. This facility is very interesting, since it gives us a
|
|
|
|
way to go from proved-correct algorithms written in Gallina to
|
|
|
|
efficient machine code. (Of course, we are trusting the
|
|
|
|
correctness of the OCaml/Haskell/Scheme compiler, and of Coq's
|
|
|
|
extraction facility itself, but this is still a big step forward
|
|
|
|
from the way most software is developed today.) Indeed, this is
|
|
|
|
one of the main uses for which Coq was developed. We'll come back
|
|
|
|
to this topic in later chapters. *)
|
|
|
|
|
|
|
|
(* ================================================================= *)
|
|
|
|
(** ** Homework Submission Guidelines *)
|
|
|
|
|
|
|
|
(** If you are using _Software Foundations_ in a course, your
|
|
|
|
instructor may use automatic scripts to help grade your homework
|
|
|
|
assignments. In order for these scripts to work correctly (so
|
|
|
|
that you get full credit for your work!), please be careful to
|
|
|
|
follow these rules:
|
|
|
|
- The grading scripts work by extracting marked regions of the
|
|
|
|
[.v] files that you submit. It is therefore important that
|
|
|
|
you do not alter the "markup" that delimits exercises: the
|
|
|
|
Exercise header, the name of the exercise, the "empty square
|
|
|
|
bracket" marker at the end, etc. Please leave this markup
|
|
|
|
exactly as you find it.
|
|
|
|
- Do not delete exercises. If you skip an exercise (e.g.,
|
|
|
|
because it is marked Optional, or because you can't solve it),
|
|
|
|
it is OK to leave a partial proof in your [.v] file, but in
|
|
|
|
this case please make sure it ends with [Admitted] (not, for
|
|
|
|
example [Abort]).
|
|
|
|
- It is fine to use additional definitions (of helper functions,
|
|
|
|
useful lemmas, etc.) in your solutions. You can put these
|
|
|
|
between the exercise header and the theorem you are asked to
|
|
|
|
prove.
|
|
|
|
|
|
|
|
You will also notice that each chapter (like [Basics.v]) is
|
|
|
|
accompanied by a _test script_ ([BasicsTest.v]) that automatically
|
|
|
|
calculates points for the finished homework problems in the
|
|
|
|
chapter. These scripts are mostly for the auto-grading
|
|
|
|
infrastructure that your instructor may use to help process
|
|
|
|
assignments, but you may also like to use them to double-check
|
|
|
|
that your file is well formatted before handing it in. In a
|
|
|
|
terminal window either type [make BasicsTest.vo] or do the
|
|
|
|
following:
|
|
|
|
|
|
|
|
coqc -Q . LF Basics.v
|
|
|
|
coqc -Q . LF BasicsTest.v
|
|
|
|
|
|
|
|
There is no need to hand in [BasicsTest.v] itself (or [Preface.v]).
|
|
|
|
|
|
|
|
_If your class is using the Canvas system to hand in assignments_:
|
|
|
|
- If you submit multiple versions of the assignment, you may
|
|
|
|
notice that they are given different names. This is fine: The
|
|
|
|
most recent submission is the one that will be graded.
|
|
|
|
- To hand in multiple files at the same time (if more than one
|
|
|
|
chapter is assigned in the same week), you need to make a
|
|
|
|
single submission with all the files at once using the button
|
|
|
|
"Add another file" just above the comment box. *)
|
|
|
|
|
|
|
|
(* ================================================================= *)
|
|
|
|
(** ** Booleans *)
|
|
|
|
|
|
|
|
(** In a similar way, we can define the standard type [bool] of
|
|
|
|
booleans, with members [true] and [false]. *)
|
|
|
|
|
|
|
|
Inductive bool : Type :=
|
|
|
|
| true
|
|
|
|
| false.
|
|
|
|
|
|
|
|
(** Although we are rolling our own booleans here for the sake
|
|
|
|
of building up everything from scratch, Coq does, of course,
|
|
|
|
provide a default implementation of the booleans, together with a
|
|
|
|
multitude of useful functions and lemmas. (Take a look at
|
|
|
|
[Coq.Init.Datatypes] in the Coq library documentation if you're
|
|
|
|
interested.) Whenever possible, we'll name our own definitions
|
|
|
|
and theorems so that they exactly coincide with the ones in the
|
|
|
|
standard library.
|
|
|
|
|
|
|
|
Functions over booleans can be defined in the same way as
|
|
|
|
above: *)
|
|
|
|
|
|
|
|
Definition negb (b:bool) : bool :=
|
|
|
|
match b with
|
|
|
|
| true => false
|
|
|
|
| false => true
|
|
|
|
end.
|
|
|
|
|
|
|
|
Definition andb (b1:bool) (b2:bool) : bool :=
|
|
|
|
match b1 with
|
|
|
|
| true => b2
|
|
|
|
| false => false
|
|
|
|
end.
|
|
|
|
|
|
|
|
Definition orb (b1:bool) (b2:bool) : bool :=
|
|
|
|
match b1 with
|
|
|
|
| true => true
|
|
|
|
| false => b2
|
|
|
|
end.
|
|
|
|
|
|
|
|
(** The last two of these illustrate Coq's syntax for
|
|
|
|
multi-argument function definitions. The corresponding
|
|
|
|
multi-argument application syntax is illustrated by the following
|
|
|
|
"unit tests," which constitute a complete specification -- a truth
|
|
|
|
table -- for the [orb] function: *)
|
|
|
|
|
|
|
|
Example test_orb1: (orb true false) = true.
|
|
|
|
Proof. simpl. reflexivity. Qed.
|
|
|
|
Example test_orb2: (orb false false) = false.
|
|
|
|
Proof. simpl. reflexivity. Qed.
|
|
|
|
Example test_orb3: (orb false true) = true.
|
|
|
|
Proof. simpl. reflexivity. Qed.
|
|
|
|
Example test_orb4: (orb true true) = true.
|
|
|
|
Proof. simpl. reflexivity. Qed.
|
|
|
|
|
|
|
|
(** We can also introduce some familiar syntax for the boolean
|
|
|
|
operations we have just defined. The [Notation] command defines a new
|
|
|
|
symbolic notation for an existing definition. *)
|
|
|
|
|
|
|
|
Notation "x && y" := (andb x y).
|
|
|
|
Notation "x || y" := (orb x y).
|
|
|
|
|
|
|
|
Example test_orb5: false || false || true = true.
|
|
|
|
Proof. simpl. reflexivity. Qed.
|
|
|
|
|
|
|
|
(** _A note on notation_: In [.v] files, we use square brackets
|
|
|
|
to delimit fragments of Coq code within comments; this convention,
|
|
|
|
also used by the [coqdoc] documentation tool, keeps them visually
|
|
|
|
separate from the surrounding text. In the HTML version of the
|
|
|
|
files, these pieces of text appear in a [different font].
|
|
|
|
|
|
|
|
The command [Admitted] can be used as a placeholder for an
|
|
|
|
incomplete proof. We'll use it in exercises, to indicate the
|
|
|
|
parts that we're leaving for you -- i.e., your job is to replace
|
|
|
|
[Admitted]s with real proofs. *)
|
|
|
|
|
|
|
|
(** **** Exercise: 1 star, standard (nandb)
|
|
|
|
|
|
|
|
Remove "[Admitted.]" and complete the definition of the following
|
|
|
|
function; then make sure that the [Example] assertions below can
|
|
|
|
each be verified by Coq. (I.e., fill in each proof, following the
|
|
|
|
model of the [orb] tests above.) The function should return [true]
|
|
|
|
if either or both of its inputs are [false]. *)
|
|
|
|
|
2020-06-04 05:02:38 +00:00
|
|
|
Definition nandb (b1:bool) (b2:bool) : bool :=
|
|
|
|
match b1, b2 with
|
|
|
|
| true, true => false
|
|
|
|
| _, _ => true
|
|
|
|
end.
|
2020-06-04 02:46:06 +00:00
|
|
|
|
|
|
|
Example test_nandb1: (nandb true false) = true.
|
2020-06-04 05:02:38 +00:00
|
|
|
Proof. reflexivity. Qed.
|
2020-06-04 02:46:06 +00:00
|
|
|
Example test_nandb2: (nandb false false) = true.
|
2020-06-04 05:02:38 +00:00
|
|
|
Proof. reflexivity. Qed.
|
2020-06-04 02:46:06 +00:00
|
|
|
Example test_nandb3: (nandb false true) = true.
|
2020-06-04 05:02:38 +00:00
|
|
|
Proof. reflexivity. Qed.
|
2020-06-04 02:46:06 +00:00
|
|
|
Example test_nandb4: (nandb true true) = false.
|
2020-06-04 05:02:38 +00:00
|
|
|
Proof. reflexivity. Qed.
|
2020-06-04 02:46:06 +00:00
|
|
|
(** [] *)
|
|
|
|
|
|
|
|
(** **** Exercise: 1 star, standard (andb3)
|
|
|
|
|
|
|
|
Do the same for the [andb3] function below. This function should
|
|
|
|
return [true] when all of its inputs are [true], and [false]
|
|
|
|
otherwise. *)
|
|
|
|
|
2020-06-04 05:02:38 +00:00
|
|
|
Definition andb3 (b1:bool) (b2:bool) (b3:bool) : bool :=
|
|
|
|
match b1, b2, b3 with
|
|
|
|
| true, true, true => true
|
|
|
|
| _, _, _ => false
|
|
|
|
end.
|
2020-06-04 02:46:06 +00:00
|
|
|
|
|
|
|
Example test_andb31: (andb3 true true true) = true.
|
2020-06-04 05:02:38 +00:00
|
|
|
Proof. reflexivity. Qed.
|
2020-06-04 02:46:06 +00:00
|
|
|
Example test_andb32: (andb3 false true true) = false.
|
2020-06-04 05:02:38 +00:00
|
|
|
Proof. reflexivity. Qed.
|
2020-06-04 02:46:06 +00:00
|
|
|
Example test_andb33: (andb3 true false true) = false.
|
2020-06-04 05:02:38 +00:00
|
|
|
Proof. reflexivity. Qed.
|
2020-06-04 02:46:06 +00:00
|
|
|
Example test_andb34: (andb3 true true false) = false.
|
2020-06-04 05:02:38 +00:00
|
|
|
Proof. reflexivity. Qed.
|
2020-06-04 02:46:06 +00:00
|
|
|
(** [] *)
|
|
|
|
|
|
|
|
(* ================================================================= *)
|
|
|
|
(** ** Types *)
|
|
|
|
|
|
|
|
(** Every expression in Coq has a type, describing what sort of
|
|
|
|
thing it computes. The [Check] command asks Coq to print the type
|
|
|
|
of an expression. *)
|
|
|
|
|
|
|
|
Check true.
|
|
|
|
(* ===> true : bool *)
|
|
|
|
Check (negb true).
|
|
|
|
(* ===> negb true : bool *)
|
|
|
|
|
|
|
|
(** Functions like [negb] itself are also data values, just like
|
|
|
|
[true] and [false]. Their types are called _function types_, and
|
|
|
|
they are written with arrows. *)
|
|
|
|
|
|
|
|
Check negb.
|
|
|
|
(* ===> negb : bool -> bool *)
|
|
|
|
|
|
|
|
(** The type of [negb], written [bool -> bool] and pronounced
|
|
|
|
"[bool] arrow [bool]," can be read, "Given an input of type
|
|
|
|
[bool], this function produces an output of type [bool]."
|
|
|
|
Similarly, the type of [andb], written [bool -> bool -> bool], can
|
|
|
|
be read, "Given two inputs, both of type [bool], this function
|
|
|
|
produces an output of type [bool]." *)
|
|
|
|
|
|
|
|
(* ================================================================= *)
|
|
|
|
(** ** New Types from Old *)
|
|
|
|
|
|
|
|
(** The types we have defined so far are examples of "enumerated
|
|
|
|
types": their definitions explicitly enumerate a finite set of
|
|
|
|
elements, each of which is just a bare constructor. Here is a
|
|
|
|
more interesting type definition, where one of the constructors
|
|
|
|
takes an argument: *)
|
|
|
|
|
|
|
|
Inductive rgb : Type :=
|
|
|
|
| red
|
|
|
|
| green
|
|
|
|
| blue.
|
|
|
|
|
|
|
|
Inductive color : Type :=
|
|
|
|
| black
|
|
|
|
| white
|
|
|
|
| primary (p : rgb).
|
|
|
|
|
|
|
|
(** Let's look at this in a little more detail.
|
|
|
|
|
|
|
|
Every inductively defined type ([day], [bool], [rgb], [color],
|
|
|
|
etc.) contains a set of _constructor expressions_ built from
|
|
|
|
_constructors_ like [red], [primary], [true], [false], [monday],
|
|
|
|
etc.
|
|
|
|
|
|
|
|
The definitions of [rgb] and [color] say how expressions in the
|
|
|
|
sets [rgb] and [color] can be built:
|
|
|
|
|
|
|
|
- [red], [green], and [blue] are the constructors of [rgb];
|
|
|
|
- [black], [white], and [primary] are the constructors of [color];
|
|
|
|
- the expression [red] belongs to the set [rgb], as do the
|
|
|
|
expressions [green] and [blue];
|
|
|
|
- the expressions [black] and [white] belong to the set [color];
|
|
|
|
- if [p] is an expression belonging to the set [rgb], then
|
|
|
|
[primary p] (pronounced "the constructor [primary] applied to
|
|
|
|
the argument [p]") is an expression belonging to the set
|
|
|
|
[color]; and
|
|
|
|
- expressions formed in these ways are the _only_ ones belonging
|
|
|
|
to the sets [rgb] and [color]. *)
|
|
|
|
|
|
|
|
(** We can define functions on colors using pattern matching just as
|
|
|
|
we have done for [day] and [bool]. *)
|
|
|
|
|
|
|
|
Definition monochrome (c : color) : bool :=
|
|
|
|
match c with
|
|
|
|
| black => true
|
|
|
|
| white => true
|
|
|
|
| primary q => false
|
|
|
|
end.
|
|
|
|
|
|
|
|
(** Since the [primary] constructor takes an argument, a pattern
|
|
|
|
matching [primary] should include either a variable (as above --
|
|
|
|
note that we can choose its name freely) or a constant of
|
|
|
|
appropriate type (as below). *)
|
|
|
|
|
|
|
|
Definition isred (c : color) : bool :=
|
|
|
|
match c with
|
|
|
|
| black => false
|
|
|
|
| white => false
|
|
|
|
| primary red => true
|
|
|
|
| primary _ => false
|
|
|
|
end.
|
|
|
|
|
|
|
|
(** The pattern [primary _] here is shorthand for "[primary] applied
|
|
|
|
to any [rgb] constructor except [red]." (The wildcard pattern [_]
|
|
|
|
has the same effect as the dummy pattern variable [p] in the
|
|
|
|
definition of [monochrome].) *)
|
|
|
|
|
|
|
|
(* ================================================================= *)
|
|
|
|
(** ** Tuples *)
|
|
|
|
|
|
|
|
(** A single constructor with multiple parameters can be used
|
|
|
|
to create a tuple type. As an example, consider representing
|
|
|
|
the four bits in a nybble (half a byte). We first define
|
|
|
|
a datatype [bit] that resembles [bool] (using the
|
|
|
|
constructors [B0] and [B1] for the two possible bit values),
|
|
|
|
and then define the datatype [nybble], which is essentially
|
|
|
|
a tuple of four bits. *)
|
|
|
|
|
|
|
|
Inductive bit : Type :=
|
|
|
|
| B0
|
|
|
|
| B1.
|
|
|
|
|
|
|
|
Inductive nybble : Type :=
|
|
|
|
| bits (b0 b1 b2 b3 : bit).
|
|
|
|
|
|
|
|
Check (bits B1 B0 B1 B0).
|
|
|
|
(* ==> bits B1 B0 B1 B0 : nybble *)
|
|
|
|
|
|
|
|
(** The [bits] constructor acts as a wrapper for its contents.
|
|
|
|
Unwrapping can be done by pattern-matching, as in the [all_zero]
|
|
|
|
function which tests a nybble to see if all its bits are O.
|
|
|
|
Note that we are using underscore (_) as a _wildcard pattern_ to
|
|
|
|
avoid inventing variable names that will not be used. *)
|
|
|
|
|
|
|
|
Definition all_zero (nb : nybble) : bool :=
|
|
|
|
match nb with
|
|
|
|
| (bits B0 B0 B0 B0) => true
|
|
|
|
| (bits _ _ _ _) => false
|
|
|
|
end.
|
|
|
|
|
|
|
|
Compute (all_zero (bits B1 B0 B1 B0)).
|
|
|
|
(* ===> false : bool *)
|
|
|
|
Compute (all_zero (bits B0 B0 B0 B0)).
|
|
|
|
(* ===> true : bool *)
|
|
|
|
|
|
|
|
(* ================================================================= *)
|
|
|
|
(** ** Modules *)
|
|
|
|
|
|
|
|
(** Coq provides a _module system_, to aid in organizing large
|
|
|
|
developments. In this course we won't need most of its features,
|
|
|
|
but one is useful: If we enclose a collection of declarations
|
|
|
|
between [Module X] and [End X] markers, then, in the remainder of
|
|
|
|
the file after the [End], these definitions are referred to by
|
|
|
|
names like [X.foo] instead of just [foo]. We will use this
|
|
|
|
feature to introduce the definition of the type [nat] in an inner
|
|
|
|
module so that it does not interfere with the one from the
|
|
|
|
standard library (which we want to use in the rest because it
|
|
|
|
comes with a tiny bit of convenient special notation). *)
|
|
|
|
|
|
|
|
Module NatPlayground.
|
|
|
|
|
|
|
|
(* ================================================================= *)
|
|
|
|
(** ** Numbers *)
|
|
|
|
|
|
|
|
(** The types we have defined so far, "enumerated types" such as
|
|
|
|
[day], [bool], and [bit], and tuple types such as [nybble] built
|
|
|
|
from them, share the property that each type has a finite set of
|
|
|
|
values. The natural numbers are an infinite set, and we need to
|
|
|
|
represent all of them in a datatype with a finite number of
|
|
|
|
constructors. There are many representations of numbers to choose
|
|
|
|
from. We are most familiar with decimal notation (base 10), using
|
|
|
|
the digits 0 through 9, for example, to form the number 123. You
|
|
|
|
may have encountered hexadecimal notation (base 16), in which the
|
|
|
|
same number is represented as 7B, or octal (base 8), where it is
|
|
|
|
173, or binary (base 2), where it is 1111011. Using an enumerated
|
|
|
|
type to represent digits, we could use any of these to represent
|
|
|
|
natural numbers. There are circumstances where each of these
|
|
|
|
choices can be useful.
|
|
|
|
|
|
|
|
Binary is valuable in computer hardware because it can in turn be
|
|
|
|
represented with two voltage levels, resulting in simple
|
|
|
|
circuitry. Analogously, we wish here to choose a representation
|
|
|
|
that makes _proofs_ simpler.
|
|
|
|
|
|
|
|
Indeed, there is a representation of numbers that is even simpler
|
|
|
|
than binary, namely unary (base 1), in which only a single digit
|
|
|
|
is used (as one might do while counting days in prison by scratching
|
|
|
|
on the walls). To represent unary with a Coq datatype, we use
|
|
|
|
two constructors. The capital-letter [O] constructor represents zero.
|
|
|
|
When the [S] constructor is applied to the representation of the
|
|
|
|
natural number _n_, the result is the representation of _n+1_.
|
|
|
|
([S] stands for "successor", or "scratch" if one is in prison.)
|
|
|
|
Here is the complete datatype definition. *)
|
|
|
|
|
|
|
|
Inductive nat : Type :=
|
|
|
|
| O
|
|
|
|
| S (n : nat).
|
|
|
|
|
|
|
|
(** With this definition, 0 is represented by [O], 1 by [S O],
|
|
|
|
2 by [S (S O)], and so on. *)
|
|
|
|
|
|
|
|
(** The clauses of this definition can be read:
|
|
|
|
- [O] is a natural number (note that this is the letter "[O],"
|
|
|
|
not the numeral "[0]").
|
|
|
|
- [S] can be put in front of a natural number to yield another
|
|
|
|
one -- if [n] is a natural number, then [S n] is too. *)
|
|
|
|
|
|
|
|
(** Again, let's look at this in a little more detail. The definition
|
|
|
|
of [nat] says how expressions in the set [nat] can be built:
|
|
|
|
|
|
|
|
- [O] and [S] are constructors;
|
|
|
|
- the expression [O] belongs to the set [nat];
|
|
|
|
- if [n] is an expression belonging to the set [nat], then [S n]
|
|
|
|
is also an expression belonging to the set [nat]; and
|
|
|
|
- expressions formed in these two ways are the only ones belonging
|
|
|
|
to the set [nat]. *)
|
|
|
|
|
|
|
|
(** The same rules apply for our definitions of [day], [bool],
|
|
|
|
[color], etc.
|
|
|
|
|
|
|
|
The above conditions are the precise force of the [Inductive]
|
|
|
|
declaration. They imply that the expression [O], the expression
|
|
|
|
[S O], the expression [S (S O)], the expression [S (S (S O))], and
|
|
|
|
so on all belong to the set [nat], while other expressions built
|
|
|
|
from data constructors, like [true], [andb true false], [S (S
|
|
|
|
false)], and [O (O (O S))] do not.
|
|
|
|
|
|
|
|
A critical point here is that what we've done so far is just to
|
|
|
|
define a _representation_ of numbers: a way of writing them down.
|
|
|
|
The names [O] and [S] are arbitrary, and at this point they have
|
|
|
|
no special meaning -- they are just two different marks that we
|
|
|
|
can use to write down numbers (together with a rule that says any
|
|
|
|
[nat] will be written as some string of [S] marks followed by an
|
|
|
|
[O]). If we like, we can write essentially the same definition
|
|
|
|
this way: *)
|
|
|
|
|
|
|
|
Inductive nat' : Type :=
|
|
|
|
| stop
|
|
|
|
| tick (foo : nat').
|
|
|
|
|
|
|
|
(** The _interpretation_ of these marks comes from how we use them to
|
|
|
|
compute. *)
|
|
|
|
|
|
|
|
(** We can do this by writing functions that pattern match on
|
|
|
|
representations of natural numbers just as we did above with
|
|
|
|
booleans and days -- for example, here is the predecessor
|
|
|
|
function: *)
|
|
|
|
|
|
|
|
Definition pred (n : nat) : nat :=
|
|
|
|
match n with
|
|
|
|
| O => O
|
|
|
|
| S n' => n'
|
|
|
|
end.
|
|
|
|
|
|
|
|
(** The second branch can be read: "if [n] has the form [S n']
|
|
|
|
for some [n'], then return [n']." *)
|
|
|
|
|
|
|
|
End NatPlayground.
|
|
|
|
|
|
|
|
(** Because natural numbers are such a pervasive form of data,
|
|
|
|
Coq provides a tiny bit of built-in magic for parsing and printing
|
|
|
|
them: ordinary decimal numerals can be used as an alternative to
|
|
|
|
the "unary" notation defined by the constructors [S] and [O]. Coq
|
|
|
|
prints numbers in decimal form by default: *)
|
|
|
|
|
|
|
|
Check (S (S (S (S O)))).
|
|
|
|
(* ===> 4 : nat *)
|
|
|
|
|
|
|
|
Definition minustwo (n : nat) : nat :=
|
|
|
|
match n with
|
|
|
|
| O => O
|
|
|
|
| S O => O
|
|
|
|
| S (S n') => n'
|
|
|
|
end.
|
|
|
|
|
|
|
|
Compute (minustwo 4).
|
|
|
|
(* ===> 2 : nat *)
|
|
|
|
|
|
|
|
(** The constructor [S] has the type [nat -> nat], just like
|
|
|
|
[pred] and functions like [minustwo]: *)
|
|
|
|
|
|
|
|
Check S.
|
|
|
|
Check pred.
|
|
|
|
Check minustwo.
|
|
|
|
|
|
|
|
(** These are all things that can be applied to a number to yield a
|
|
|
|
number. However, there is a fundamental difference between the
|
|
|
|
first one and the other two: functions like [pred] and [minustwo]
|
|
|
|
come with _computation rules_ -- e.g., the definition of [pred]
|
|
|
|
says that [pred 2] can be simplified to [1] -- while the
|
|
|
|
definition of [S] has no such behavior attached. Although it is
|
|
|
|
like a function in the sense that it can be applied to an
|
|
|
|
argument, it does not _do_ anything at all! It is just a way of
|
|
|
|
writing down numbers. (Think about standard decimal numerals: the
|
|
|
|
numeral [1] is not a computation; it's a piece of data. When we
|
|
|
|
write [111] to mean the number one hundred and eleven, we are
|
|
|
|
using [1], three times, to write down a concrete representation of
|
|
|
|
a number.)
|
|
|
|
|
|
|
|
For most function definitions over numbers, just pattern matching
|
|
|
|
is not enough: we also need recursion. For example, to check that
|
|
|
|
a number [n] is even, we may need to recursively check whether
|
|
|
|
[n-2] is even. To write such functions, we use the keyword
|
|
|
|
[Fixpoint]. *)
|
|
|
|
|
|
|
|
Fixpoint evenb (n:nat) : bool :=
|
|
|
|
match n with
|
|
|
|
| O => true
|
|
|
|
| S O => false
|
|
|
|
| S (S n') => evenb n'
|
|
|
|
end.
|
|
|
|
|
|
|
|
(** We can define [oddb] by a similar [Fixpoint] declaration, but here
|
|
|
|
is a simpler definition: *)
|
|
|
|
|
|
|
|
Definition oddb (n:nat) : bool := negb (evenb n).
|
|
|
|
|
|
|
|
Example test_oddb1: oddb 1 = true.
|
|
|
|
Proof. simpl. reflexivity. Qed.
|
|
|
|
Example test_oddb2: oddb 4 = false.
|
|
|
|
Proof. simpl. reflexivity. Qed.
|
|
|
|
|
|
|
|
(** (You will notice if you step through these proofs that
|
|
|
|
[simpl] actually has no effect on the goal -- all of the work is
|
|
|
|
done by [reflexivity]. We'll see more about why that is shortly.)
|
|
|
|
|
|
|
|
Naturally, we can also define multi-argument functions by
|
|
|
|
recursion. *)
|
|
|
|
|
|
|
|
Module NatPlayground2.
|
|
|
|
|
|
|
|
Fixpoint plus (n : nat) (m : nat) : nat :=
|
|
|
|
match n with
|
|
|
|
| O => m
|
|
|
|
| S n' => S (plus n' m)
|
|
|
|
end.
|
|
|
|
|
|
|
|
(** Adding three to two now gives us five, as we'd expect. *)
|
|
|
|
|
|
|
|
Compute (plus 3 2).
|
|
|
|
|
|
|
|
(** The simplification that Coq performs to reach this conclusion can
|
|
|
|
be visualized as follows: *)
|
|
|
|
|
|
|
|
(* [plus (S (S (S O))) (S (S O))]
|
|
|
|
==> [S (plus (S (S O)) (S (S O)))]
|
|
|
|
by the second clause of the [match]
|
|
|
|
==> [S (S (plus (S O) (S (S O))))]
|
|
|
|
by the second clause of the [match]
|
|
|
|
==> [S (S (S (plus O (S (S O)))))]
|
|
|
|
by the second clause of the [match]
|
|
|
|
==> [S (S (S (S (S O))))]
|
|
|
|
by the first clause of the [match]
|
|
|
|
*)
|
|
|
|
|
|
|
|
(** As a notational convenience, if two or more arguments have
|
|
|
|
the same type, they can be written together. In the following
|
|
|
|
definition, [(n m : nat)] means just the same as if we had written
|
|
|
|
[(n : nat) (m : nat)]. *)
|
|
|
|
|
|
|
|
Fixpoint mult (n m : nat) : nat :=
|
|
|
|
match n with
|
|
|
|
| O => O
|
|
|
|
| S n' => plus m (mult n' m)
|
|
|
|
end.
|
|
|
|
|
|
|
|
Example test_mult1: (mult 3 3) = 9.
|
|
|
|
Proof. simpl. reflexivity. Qed.
|
|
|
|
|
|
|
|
(** You can match two expressions at once by putting a comma
|
|
|
|
between them: *)
|
|
|
|
|
|
|
|
Fixpoint minus (n m:nat) : nat :=
|
|
|
|
match n, m with
|
|
|
|
| O , _ => O
|
|
|
|
| S _ , O => n
|
|
|
|
| S n', S m' => minus n' m'
|
|
|
|
end.
|
|
|
|
|
|
|
|
End NatPlayground2.
|
|
|
|
|
|
|
|
Fixpoint exp (base power : nat) : nat :=
|
|
|
|
match power with
|
|
|
|
| O => S O
|
|
|
|
| S p => mult base (exp base p)
|
|
|
|
end.
|
|
|
|
|
|
|
|
(** **** Exercise: 1 star, standard (factorial)
|
|
|
|
|
|
|
|
Recall the standard mathematical factorial function:
|
|
|
|
|
|
|
|
factorial(0) = 1
|
|
|
|
factorial(n) = n * factorial(n-1) (if n>0)
|
|
|
|
|
|
|
|
Translate this into Coq. *)
|
|
|
|
|
2020-06-04 05:02:38 +00:00
|
|
|
Fixpoint factorial (n:nat) : nat :=
|
|
|
|
match n with
|
|
|
|
| 0 => 1
|
|
|
|
| S n => (S n) * factorial (n)
|
|
|
|
end.
|
2020-06-04 02:46:06 +00:00
|
|
|
|
|
|
|
Example test_factorial1: (factorial 3) = 6.
|
2020-06-04 05:02:38 +00:00
|
|
|
Proof. reflexivity. Qed.
|
2020-06-04 02:46:06 +00:00
|
|
|
Example test_factorial2: (factorial 5) = (mult 10 12).
|
2020-06-04 05:02:38 +00:00
|
|
|
Proof. reflexivity. Qed.
|
2020-06-04 02:46:06 +00:00
|
|
|
(** [] *)
|
|
|
|
|
|
|
|
(** Again, we can make numerical expressions easier to read and write
|
|
|
|
by introducing notations for addition, multiplication, and
|
|
|
|
subtraction. *)
|
|
|
|
|
|
|
|
Notation "x + y" := (plus x y)
|
|
|
|
(at level 50, left associativity)
|
|
|
|
: nat_scope.
|
|
|
|
Notation "x - y" := (minus x y)
|
|
|
|
(at level 50, left associativity)
|
|
|
|
: nat_scope.
|
|
|
|
Notation "x * y" := (mult x y)
|
|
|
|
(at level 40, left associativity)
|
|
|
|
: nat_scope.
|
|
|
|
|
|
|
|
Check ((0 + 1) + 1).
|
|
|
|
|
|
|
|
(** (The [level], [associativity], and [nat_scope] annotations
|
|
|
|
control how these notations are treated by Coq's parser. The
|
|
|
|
details are not important for our purposes, but interested readers
|
|
|
|
can refer to the "More on Notation" section at the end of this
|
|
|
|
chapter.)
|
|
|
|
|
|
|
|
Note that these do not change the definitions we've already made:
|
|
|
|
they are simply instructions to the Coq parser to accept [x + y]
|
|
|
|
in place of [plus x y] and, conversely, to the Coq pretty-printer
|
|
|
|
to display [plus x y] as [x + y]. *)
|
|
|
|
|
|
|
|
(** When we say that Coq comes with almost nothing built-in, we really
|
|
|
|
mean it: even equality testing is a user-defined operation!
|
|
|
|
|
|
|
|
Here is a function [eqb], which tests natural numbers for
|
|
|
|
[eq]uality, yielding a [b]oolean. Note the use of nested
|
|
|
|
[match]es (we could also have used a simultaneous match, as we did
|
|
|
|
in [minus].) *)
|
|
|
|
|
|
|
|
Fixpoint eqb (n m : nat) : bool :=
|
|
|
|
match n with
|
|
|
|
| O => match m with
|
|
|
|
| O => true
|
|
|
|
| S m' => false
|
|
|
|
end
|
|
|
|
| S n' => match m with
|
|
|
|
| O => false
|
|
|
|
| S m' => eqb n' m'
|
|
|
|
end
|
|
|
|
end.
|
|
|
|
|
|
|
|
(** Similarly, the [leb] function tests whether its first argument is
|
|
|
|
less than or equal to its second argument, yielding a boolean. *)
|
|
|
|
|
|
|
|
Fixpoint leb (n m : nat) : bool :=
|
|
|
|
match n with
|
|
|
|
| O => true
|
|
|
|
| S n' =>
|
|
|
|
match m with
|
|
|
|
| O => false
|
|
|
|
| S m' => leb n' m'
|
|
|
|
end
|
|
|
|
end.
|
|
|
|
|
|
|
|
Example test_leb1: (leb 2 2) = true.
|
|
|
|
Proof. simpl. reflexivity. Qed.
|
|
|
|
Example test_leb2: (leb 2 4) = true.
|
|
|
|
Proof. simpl. reflexivity. Qed.
|
|
|
|
Example test_leb3: (leb 4 2) = false.
|
|
|
|
Proof. simpl. reflexivity. Qed.
|
|
|
|
|
|
|
|
(** Since we'll be using these (especially [eqb]) a lot, let's give
|
|
|
|
them infix notations. *)
|
|
|
|
|
|
|
|
Notation "x =? y" := (eqb x y) (at level 70) : nat_scope.
|
|
|
|
Notation "x <=? y" := (leb x y) (at level 70) : nat_scope.
|
|
|
|
|
|
|
|
Example test_leb3': (4 <=? 2) = false.
|
|
|
|
Proof. simpl. reflexivity. Qed.
|
|
|
|
|
|
|
|
(** **** Exercise: 1 star, standard (ltb)
|
|
|
|
|
|
|
|
The [ltb] function tests natural numbers for [l]ess-[t]han,
|
|
|
|
yielding a [b]oolean. Instead of making up a new [Fixpoint] for
|
|
|
|
this one, define it in terms of a previously defined
|
|
|
|
function. (It can be done with just one previously defined
|
|
|
|
function, but you can use two if you need to.) *)
|
|
|
|
|
2020-06-04 05:02:38 +00:00
|
|
|
Definition ltb (n m : nat) : bool :=
|
|
|
|
1 <=? m - n.
|
2020-06-04 02:46:06 +00:00
|
|
|
|
|
|
|
Notation "x <? y" := (ltb x y) (at level 70) : nat_scope.
|
|
|
|
|
|
|
|
Example test_ltb1: (ltb 2 2) = false.
|
2020-06-04 05:02:38 +00:00
|
|
|
Proof. reflexivity. Qed.
|
2020-06-04 02:46:06 +00:00
|
|
|
Example test_ltb2: (ltb 2 4) = true.
|
2020-06-04 05:02:38 +00:00
|
|
|
Proof. reflexivity. Qed.
|
2020-06-04 02:46:06 +00:00
|
|
|
Example test_ltb3: (ltb 4 2) = false.
|
2020-06-04 05:02:38 +00:00
|
|
|
Proof. reflexivity. Qed.
|
2020-06-04 02:46:06 +00:00
|
|
|
(** [] *)
|
|
|
|
|
|
|
|
(* ################################################################# *)
|
|
|
|
(** * Proof by Simplification *)
|
|
|
|
|
|
|
|
(** Now that we've defined a few datatypes and functions, let's
|
|
|
|
turn to stating and proving properties of their behavior.
|
|
|
|
Actually, we've already started doing this: each [Example] in the
|
|
|
|
previous sections makes a precise claim about the behavior of some
|
|
|
|
function on some particular inputs. The proofs of these claims
|
|
|
|
were always the same: use [simpl] to simplify both sides of the
|
|
|
|
equation, then use [reflexivity] to check that both sides contain
|
|
|
|
identical values.
|
|
|
|
|
|
|
|
The same sort of "proof by simplification" can be used to prove
|
|
|
|
more interesting properties as well. For example, the fact that
|
|
|
|
[0] is a "neutral element" for [+] on the left can be proved just
|
|
|
|
by observing that [0 + n] reduces to [n] no matter what [n] is, a
|
|
|
|
fact that can be read directly off the definition of [plus]. *)
|
|
|
|
|
|
|
|
Theorem plus_O_n : forall n : nat, 0 + n = n.
|
|
|
|
Proof.
|
|
|
|
intros n. simpl. reflexivity. Qed.
|
|
|
|
|
|
|
|
(** (You may notice that the above statement looks different in
|
|
|
|
the [.v] file in your IDE than it does in the HTML rendition in
|
|
|
|
your browser, if you are viewing both. In [.v] files, we write the
|
|
|
|
[forall] universal quantifier using the reserved identifier
|
|
|
|
"forall." When the [.v] files are converted to HTML, this gets
|
|
|
|
transformed into an upside-down-A symbol.)
|
|
|
|
|
|
|
|
This is a good place to mention that [reflexivity] is a bit
|
|
|
|
more powerful than we have admitted. In the examples we have seen,
|
|
|
|
the calls to [simpl] were actually not needed, because
|
|
|
|
[reflexivity] can perform some simplification automatically when
|
|
|
|
checking that two sides are equal; [simpl] was just added so that
|
|
|
|
we could see the intermediate state -- after simplification but
|
|
|
|
before finishing the proof. Here is a shorter proof of the
|
|
|
|
theorem: *)
|
|
|
|
|
|
|
|
Theorem plus_O_n' : forall n : nat, 0 + n = n.
|
|
|
|
Proof.
|
|
|
|
intros n. reflexivity. Qed.
|
|
|
|
|
|
|
|
(** Moreover, it will be useful later to know that [reflexivity]
|
|
|
|
does somewhat _more_ simplification than [simpl] does -- for
|
|
|
|
example, it tries "unfolding" defined terms, replacing them with
|
|
|
|
their right-hand sides. The reason for this difference is that,
|
|
|
|
if reflexivity succeeds, the whole goal is finished and we don't
|
|
|
|
need to look at whatever expanded expressions [reflexivity] has
|
|
|
|
created by all this simplification and unfolding; by contrast,
|
|
|
|
[simpl] is used in situations where we may have to read and
|
|
|
|
understand the new goal that it creates, so we would not want it
|
|
|
|
blindly expanding definitions and leaving the goal in a messy
|
|
|
|
state.
|
|
|
|
|
|
|
|
The form of the theorem we just stated and its proof are almost
|
|
|
|
exactly the same as the simpler examples we saw earlier; there are
|
|
|
|
just a few differences.
|
|
|
|
|
|
|
|
First, we've used the keyword [Theorem] instead of [Example].
|
|
|
|
This difference is mostly a matter of style; the keywords
|
|
|
|
[Example] and [Theorem] (and a few others, including [Lemma],
|
|
|
|
[Fact], and [Remark]) mean pretty much the same thing to Coq.
|
|
|
|
|
|
|
|
Second, we've added the quantifier [forall n:nat], so that our
|
|
|
|
theorem talks about _all_ natural numbers [n]. Informally, to
|
|
|
|
prove theorems of this form, we generally start by saying "Suppose
|
|
|
|
[n] is some number..." Formally, this is achieved in the proof by
|
|
|
|
[intros n], which moves [n] from the quantifier in the goal to a
|
|
|
|
_context_ of current assumptions.
|
|
|
|
|
|
|
|
The keywords [intros], [simpl], and [reflexivity] are examples of
|
|
|
|
_tactics_. A tactic is a command that is used between [Proof] and
|
|
|
|
[Qed] to guide the process of checking some claim we are making.
|
|
|
|
We will see several more tactics in the rest of this chapter and
|
|
|
|
yet more in future chapters. *)
|
|
|
|
|
|
|
|
(** Other similar theorems can be proved with the same pattern. *)
|
|
|
|
|
|
|
|
Theorem plus_1_l : forall n:nat, 1 + n = S n.
|
|
|
|
Proof.
|
|
|
|
intros n. reflexivity. Qed.
|
|
|
|
|
|
|
|
Theorem mult_0_l : forall n:nat, 0 * n = 0.
|
|
|
|
Proof.
|
|
|
|
intros n. reflexivity. Qed.
|
|
|
|
|
|
|
|
(** The [_l] suffix in the names of these theorems is
|
|
|
|
pronounced "on the left." *)
|
|
|
|
|
|
|
|
(** It is worth stepping through these proofs to observe how the
|
|
|
|
context and the goal change. You may want to add calls to [simpl]
|
|
|
|
before [reflexivity] to see the simplifications that Coq performs
|
|
|
|
on the terms before checking that they are equal. *)
|
|
|
|
|
|
|
|
(* ################################################################# *)
|
|
|
|
(** * Proof by Rewriting *)
|
|
|
|
|
|
|
|
(** This theorem is a bit more interesting than the others we've
|
|
|
|
seen: *)
|
|
|
|
|
|
|
|
Theorem plus_id_example : forall n m:nat,
|
|
|
|
n = m ->
|
|
|
|
n + n = m + m.
|
|
|
|
|
|
|
|
(** Instead of making a universal claim about all numbers [n] and [m],
|
|
|
|
it talks about a more specialized property that only holds when [n
|
|
|
|
= m]. The arrow symbol is pronounced "implies."
|
|
|
|
|
|
|
|
As before, we need to be able to reason by assuming we are given such
|
|
|
|
numbers [n] and [m]. We also need to assume the hypothesis
|
|
|
|
[n = m]. The [intros] tactic will serve to move all three of these
|
|
|
|
from the goal into assumptions in the current context.
|
|
|
|
|
|
|
|
Since [n] and [m] are arbitrary numbers, we can't just use
|
|
|
|
simplification to prove this theorem. Instead, we prove it by
|
|
|
|
observing that, if we are assuming [n = m], then we can replace
|
|
|
|
[n] with [m] in the goal statement and obtain an equality with the
|
|
|
|
same expression on both sides. The tactic that tells Coq to
|
|
|
|
perform this replacement is called [rewrite]. *)
|
|
|
|
|
|
|
|
Proof.
|
|
|
|
(* move both quantifiers into the context: *)
|
|
|
|
intros n m.
|
|
|
|
(* move the hypothesis into the context: *)
|
|
|
|
intros H.
|
|
|
|
(* rewrite the goal using the hypothesis: *)
|
|
|
|
rewrite -> H.
|
|
|
|
reflexivity. Qed.
|
|
|
|
|
|
|
|
(** The first line of the proof moves the universally quantified
|
|
|
|
variables [n] and [m] into the context. The second moves the
|
|
|
|
hypothesis [n = m] into the context and gives it the name [H].
|
|
|
|
The third tells Coq to rewrite the current goal ([n + n = m + m])
|
|
|
|
by replacing the left side of the equality hypothesis [H] with the
|
|
|
|
right side.
|
|
|
|
|
|
|
|
(The arrow symbol in the [rewrite] has nothing to do with
|
|
|
|
implication: it tells Coq to apply the rewrite from left to right.
|
|
|
|
To rewrite from right to left, you can use [rewrite <-]. Try
|
|
|
|
making this change in the above proof and see what difference it
|
|
|
|
makes.) *)
|
|
|
|
|
|
|
|
(** **** Exercise: 1 star, standard (plus_id_exercise)
|
|
|
|
|
|
|
|
Remove "[Admitted.]" and fill in the proof. *)
|
|
|
|
|
|
|
|
Theorem plus_id_exercise : forall n m o : nat,
|
|
|
|
n = m -> m = o -> n + m = m + o.
|
|
|
|
Proof.
|
2020-06-04 05:02:38 +00:00
|
|
|
intros n m o.
|
|
|
|
intros H J.
|
|
|
|
rewrite -> H.
|
|
|
|
rewrite -> J.
|
|
|
|
reflexivity.
|
|
|
|
Qed.
|
2020-06-04 02:46:06 +00:00
|
|
|
(** [] *)
|
|
|
|
|
|
|
|
(** The [Admitted] command tells Coq that we want to skip trying
|
|
|
|
to prove this theorem and just accept it as a given. This can be
|
|
|
|
useful for developing longer proofs, since we can state subsidiary
|
|
|
|
lemmas that we believe will be useful for making some larger
|
|
|
|
argument, use [Admitted] to accept them on faith for the moment,
|
|
|
|
and continue working on the main argument until we are sure it
|
|
|
|
makes sense; then we can go back and fill in the proofs we
|
|
|
|
skipped. Be careful, though: every time you say [Admitted] you
|
|
|
|
are leaving a door open for total nonsense to enter Coq's nice,
|
|
|
|
rigorous, formally checked world! *)
|
|
|
|
|
|
|
|
(** We can also use the [rewrite] tactic with a previously proved
|
|
|
|
theorem instead of a hypothesis from the context. If the statement
|
|
|
|
of the previously proved theorem involves quantified variables,
|
|
|
|
as in the example below, Coq tries to instantiate them
|
|
|
|
by matching with the current goal. *)
|
|
|
|
|
|
|
|
Theorem mult_0_plus : forall n m : nat,
|
|
|
|
(0 + n) * m = n * m.
|
|
|
|
Proof.
|
|
|
|
intros n m.
|
|
|
|
rewrite -> plus_O_n.
|
|
|
|
reflexivity. Qed.
|
|
|
|
|
|
|
|
(** **** Exercise: 2 stars, standard (mult_S_1) *)
|
|
|
|
Theorem mult_S_1 : forall n m : nat,
|
|
|
|
m = S n ->
|
|
|
|
m * (1 + n) = m * m.
|
|
|
|
Proof.
|
2020-06-04 05:02:38 +00:00
|
|
|
intros n m.
|
|
|
|
intros H.
|
|
|
|
simpl.
|
|
|
|
rewrite <- H.
|
|
|
|
reflexivity.
|
|
|
|
Qed.
|
2020-06-04 02:46:06 +00:00
|
|
|
|
|
|
|
(* (N.b. This proof can actually be completed with tactics other than
|
|
|
|
[rewrite], but please do use [rewrite] for the sake of the exercise.)
|
|
|
|
|
|
|
|
[] *)
|
|
|
|
|
|
|
|
(* ################################################################# *)
|
|
|
|
(** * Proof by Case Analysis *)
|
|
|
|
|
|
|
|
(** Of course, not everything can be proved by simple
|
|
|
|
calculation and rewriting: In general, unknown, hypothetical
|
|
|
|
values (arbitrary numbers, booleans, lists, etc.) can block
|
|
|
|
simplification. For example, if we try to prove the following
|
|
|
|
fact using the [simpl] tactic as above, we get stuck. (We then
|
|
|
|
use the [Abort] command to give up on it for the moment.)*)
|
|
|
|
|
|
|
|
Theorem plus_1_neq_0_firsttry : forall n : nat,
|
|
|
|
(n + 1) =? 0 = false.
|
|
|
|
Proof.
|
|
|
|
intros n.
|
|
|
|
simpl. (* does nothing! *)
|
|
|
|
Abort.
|
|
|
|
|
|
|
|
(** The reason for this is that the definitions of both
|
|
|
|
[eqb] and [+] begin by performing a [match] on their first
|
|
|
|
argument. But here, the first argument to [+] is the unknown
|
|
|
|
number [n] and the argument to [eqb] is the compound
|
|
|
|
expression [n + 1]; neither can be simplified.
|
|
|
|
|
|
|
|
To make progress, we need to consider the possible forms of [n]
|
|
|
|
separately. If [n] is [O], then we can calculate the final result
|
|
|
|
of [(n + 1) =? 0] and check that it is, indeed, [false]. And
|
|
|
|
if [n = S n'] for some [n'], then, although we don't know exactly
|
|
|
|
what number [n + 1] yields, we can calculate that, at least, it
|
|
|
|
will begin with one [S], and this is enough to calculate that,
|
|
|
|
again, [(n + 1) =? 0] will yield [false].
|
|
|
|
|
|
|
|
The tactic that tells Coq to consider, separately, the cases where
|
|
|
|
[n = O] and where [n = S n'] is called [destruct]. *)
|
|
|
|
|
|
|
|
Theorem plus_1_neq_0 : forall n : nat,
|
|
|
|
(n + 1) =? 0 = false.
|
|
|
|
Proof.
|
|
|
|
intros n. destruct n as [| n'] eqn:E.
|
|
|
|
- reflexivity.
|
|
|
|
- reflexivity. Qed.
|
|
|
|
|
|
|
|
(** The [destruct] generates _two_ subgoals, which we must then
|
|
|
|
prove, separately, in order to get Coq to accept the theorem.
|
|
|
|
|
|
|
|
The annotation "[as [| n']]" is called an _intro pattern_. It
|
|
|
|
tells Coq what variable names to introduce in each subgoal. In
|
|
|
|
general, what goes between the square brackets is a _list of
|
|
|
|
lists_ of names, separated by [|]. In this case, the first
|
|
|
|
component is empty, since the [O] constructor is nullary (it
|
|
|
|
doesn't have any arguments). The second component gives a single
|
|
|
|
name, [n'], since [S] is a unary constructor.
|
|
|
|
|
|
|
|
In each subgoal, Coq remembers the assumption about [n] that is
|
|
|
|
relevant for this subgoal -- either [n = 0] or [n = S n'] for some
|
|
|
|
n'. The [eqn:E] annotation tells [destruct] to give the name [E] to
|
|
|
|
this equation. (Leaving off the [eqn:E] annotation causes Coq to
|
|
|
|
elide these assumptions in the subgoals. This slightly
|
|
|
|
streamlines proofs where the assumptions are not explicitly used,
|
|
|
|
but it is better practice to keep them for the sake of
|
|
|
|
documentation, as they can help keep you oriented when working
|
|
|
|
with the subgoals.)
|
|
|
|
|
|
|
|
The [-] signs on the second and third lines are called _bullets_,
|
|
|
|
and they mark the parts of the proof that correspond to each
|
|
|
|
generated subgoal. The proof script that comes after a bullet is
|
|
|
|
the entire proof for a subgoal. In this example, each of the
|
|
|
|
subgoals is easily proved by a single use of [reflexivity], which
|
|
|
|
itself performs some simplification -- e.g., the second one
|
|
|
|
simplifies [(S n' + 1) =? 0] to [false] by first rewriting [(S n'
|
|
|
|
+ 1)] to [S (n' + 1)], then unfolding [eqb], and then simplifying
|
|
|
|
the [match].
|
|
|
|
|
|
|
|
Marking cases with bullets is entirely optional: if bullets are
|
|
|
|
not present, Coq simply asks you to prove each subgoal in
|
|
|
|
sequence, one at a time. But it is a good idea to use bullets.
|
|
|
|
For one thing, they make the structure of a proof apparent, making
|
|
|
|
it more readable. Also, bullets instruct Coq to ensure that a
|
|
|
|
subgoal is complete before trying to verify the next one,
|
|
|
|
preventing proofs for different subgoals from getting mixed
|
|
|
|
up. These issues become especially important in large
|
|
|
|
developments, where fragile proofs lead to long debugging
|
|
|
|
sessions.
|
|
|
|
|
|
|
|
There are no hard and fast rules for how proofs should be
|
|
|
|
formatted in Coq -- in particular, where lines should be broken
|
|
|
|
and how sections of the proof should be indented to indicate their
|
|
|
|
nested structure. However, if the places where multiple subgoals
|
|
|
|
are generated are marked with explicit bullets at the beginning of
|
|
|
|
lines, then the proof will be readable almost no matter what
|
|
|
|
choices are made about other aspects of layout.
|
|
|
|
|
|
|
|
This is also a good place to mention one other piece of somewhat
|
|
|
|
obvious advice about line lengths. Beginning Coq users sometimes
|
|
|
|
tend to the extremes, either writing each tactic on its own line
|
|
|
|
or writing entire proofs on one line. Good style lies somewhere
|
|
|
|
in the middle. One reasonable convention is to limit yourself to
|
|
|
|
80-character lines.
|
|
|
|
|
|
|
|
The [destruct] tactic can be used with any inductively defined
|
|
|
|
datatype. For example, we use it next to prove that boolean
|
|
|
|
negation is involutive -- i.e., that negation is its own
|
|
|
|
inverse. *)
|
|
|
|
|
|
|
|
Theorem negb_involutive : forall b : bool,
|
|
|
|
negb (negb b) = b.
|
|
|
|
Proof.
|
|
|
|
intros b. destruct b eqn:E.
|
|
|
|
- reflexivity.
|
|
|
|
- reflexivity. Qed.
|
|
|
|
|
|
|
|
(** Note that the [destruct] here has no [as] clause because
|
|
|
|
none of the subcases of the [destruct] need to bind any variables,
|
|
|
|
so there is no need to specify any names. (We could also have
|
|
|
|
written [as [|]], or [as []].) In fact, we can omit the [as]
|
|
|
|
clause from _any_ [destruct] and Coq will fill in variable names
|
|
|
|
automatically. This is generally considered bad style, since Coq
|
|
|
|
often makes confusing choices of names when left to its own
|
|
|
|
devices.
|
|
|
|
|
|
|
|
It is sometimes useful to invoke [destruct] inside a subgoal,
|
|
|
|
generating yet more proof obligations. In this case, we use
|
|
|
|
different kinds of bullets to mark goals on different "levels."
|
|
|
|
For example: *)
|
|
|
|
|
|
|
|
Theorem andb_commutative : forall b c, andb b c = andb c b.
|
|
|
|
Proof.
|
|
|
|
intros b c. destruct b eqn:Eb.
|
|
|
|
- destruct c eqn:Ec.
|
|
|
|
+ reflexivity.
|
|
|
|
+ reflexivity.
|
|
|
|
- destruct c eqn:Ec.
|
|
|
|
+ reflexivity.
|
|
|
|
+ reflexivity.
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
(** Each pair of calls to [reflexivity] corresponds to the
|
|
|
|
subgoals that were generated after the execution of the [destruct c]
|
|
|
|
line right above it. *)
|
|
|
|
|
|
|
|
(** Besides [-] and [+], we can use [*] (asterisk) as a third kind of
|
|
|
|
bullet. We can also enclose sub-proofs in curly braces, which is
|
|
|
|
useful in case we ever encounter a proof that generates more than
|
|
|
|
three levels of subgoals: *)
|
|
|
|
|
|
|
|
Theorem andb_commutative' : forall b c, andb b c = andb c b.
|
|
|
|
Proof.
|
|
|
|
intros b c. destruct b eqn:Eb.
|
|
|
|
{ destruct c eqn:Ec.
|
|
|
|
{ reflexivity. }
|
|
|
|
{ reflexivity. } }
|
|
|
|
{ destruct c eqn:Ec.
|
|
|
|
{ reflexivity. }
|
|
|
|
{ reflexivity. } }
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
(** Since curly braces mark both the beginning and the end of a
|
|
|
|
proof, they can be used for multiple subgoal levels, as this
|
|
|
|
example shows. Furthermore, curly braces allow us to reuse the
|
|
|
|
same bullet shapes at multiple levels in a proof: *)
|
|
|
|
|
|
|
|
Theorem andb3_exchange :
|
|
|
|
forall b c d, andb (andb b c) d = andb (andb b d) c.
|
|
|
|
Proof.
|
|
|
|
intros b c d. destruct b eqn:Eb.
|
|
|
|
- destruct c eqn:Ec.
|
|
|
|
{ destruct d eqn:Ed.
|
|
|
|
- reflexivity.
|
|
|
|
- reflexivity. }
|
|
|
|
{ destruct d eqn:Ed.
|
|
|
|
- reflexivity.
|
|
|
|
- reflexivity. }
|
|
|
|
- destruct c eqn:Ec.
|
|
|
|
{ destruct d eqn:Ed.
|
|
|
|
- reflexivity.
|
|
|
|
- reflexivity. }
|
|
|
|
{ destruct d eqn:Ed.
|
|
|
|
- reflexivity.
|
|
|
|
- reflexivity. }
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
(** Before closing the chapter, let's mention one final
|
|
|
|
convenience. As you may have noticed, many proofs perform case
|
|
|
|
analysis on a variable right after introducing it:
|
|
|
|
|
|
|
|
intros x y. destruct y as [|y] eqn:E.
|
|
|
|
|
|
|
|
This pattern is so common that Coq provides a shorthand for it: we
|
|
|
|
can perform case analysis on a variable when introducing it by
|
|
|
|
using an intro pattern instead of a variable name. For instance,
|
|
|
|
here is a shorter proof of the [plus_1_neq_0] theorem
|
|
|
|
above. (You'll also note one downside of this shorthand: we lose
|
|
|
|
the equation recording the assumption we are making in each
|
|
|
|
subgoal, which we previously got from the [eqn:E] annotation.) *)
|
|
|
|
|
|
|
|
Theorem plus_1_neq_0' : forall n : nat,
|
|
|
|
(n + 1) =? 0 = false.
|
|
|
|
Proof.
|
|
|
|
intros [|n].
|
|
|
|
- reflexivity.
|
|
|
|
- reflexivity. Qed.
|
|
|
|
|
|
|
|
(** If there are no arguments to name, we can just write [[]]. *)
|
|
|
|
|
|
|
|
Theorem andb_commutative'' :
|
|
|
|
forall b c, andb b c = andb c b.
|
|
|
|
Proof.
|
|
|
|
intros [] [].
|
|
|
|
- reflexivity.
|
|
|
|
- reflexivity.
|
|
|
|
- reflexivity.
|
|
|
|
- reflexivity.
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
(** **** Exercise: 2 stars, standard (andb_true_elim2)
|
|
|
|
|
|
|
|
Prove the following claim, marking cases (and subcases) with
|
|
|
|
bullets when you use [destruct]. *)
|
|
|
|
|
|
|
|
Theorem andb_true_elim2 : forall b c : bool,
|
|
|
|
andb b c = true -> c = true.
|
|
|
|
Proof.
|
2020-06-04 05:02:38 +00:00
|
|
|
intros [] [].
|
|
|
|
- reflexivity.
|
|
|
|
- intros H. destruct H. reflexivity.
|
|
|
|
- reflexivity.
|
|
|
|
- intros H. destruct H. reflexivity.
|
|
|
|
Qed.
|
2020-06-04 02:46:06 +00:00
|
|
|
|
|
|
|
(** **** Exercise: 1 star, standard (zero_nbeq_plus_1) *)
|
|
|
|
Theorem zero_nbeq_plus_1 : forall n : nat,
|
|
|
|
0 =? (n + 1) = false.
|
|
|
|
Proof.
|
2020-06-04 05:02:38 +00:00
|
|
|
intros [].
|
|
|
|
- reflexivity.
|
|
|
|
- reflexivity.
|
|
|
|
Qed.
|
2020-06-04 02:46:06 +00:00
|
|
|
|
|
|
|
(* ================================================================= *)
|
|
|
|
(** ** More on Notation (Optional) *)
|
|
|
|
|
|
|
|
(** (In general, sections marked Optional are not needed to follow the
|
|
|
|
rest of the book, except possibly other Optional sections. On a
|
|
|
|
first reading, you might want to skim these sections so that you
|
|
|
|
know what's there for future reference.)
|
|
|
|
|
|
|
|
Recall the notation definitions for infix plus and times: *)
|
|
|
|
|
|
|
|
Notation "x + y" := (plus x y)
|
|
|
|
(at level 50, left associativity)
|
|
|
|
: nat_scope.
|
|
|
|
Notation "x * y" := (mult x y)
|
|
|
|
(at level 40, left associativity)
|
|
|
|
: nat_scope.
|
|
|
|
|
|
|
|
(** For each notation symbol in Coq, we can specify its _precedence
|
|
|
|
level_ and its _associativity_. The precedence level [n] is
|
|
|
|
specified by writing [at level n]; this helps Coq parse compound
|
|
|
|
expressions. The associativity setting helps to disambiguate
|
|
|
|
expressions containing multiple occurrences of the same
|
|
|
|
symbol. For example, the parameters specified above for [+] and
|
|
|
|
[*] say that the expression [1+2*3*4] is shorthand for
|
|
|
|
[(1+((2*3)*4))]. Coq uses precedence levels from 0 to 100, and
|
|
|
|
_left_, _right_, or _no_ associativity. We will see more examples
|
|
|
|
of this later, e.g., in the [Lists]
|
|
|
|
chapter.
|
|
|
|
|
|
|
|
Each notation symbol is also associated with a _notation scope_.
|
|
|
|
Coq tries to guess what scope is meant from context, so when it
|
|
|
|
sees [S(O*O)] it guesses [nat_scope], but when it sees the
|
|
|
|
cartesian product (tuple) type [bool*bool] (which we'll see in
|
|
|
|
later chapters) it guesses [type_scope]. Occasionally, it is
|
|
|
|
necessary to help it out with percent-notation by writing
|
|
|
|
[(x*y)%nat], and sometimes in what Coq prints it will use [%nat]
|
|
|
|
to indicate what scope a notation is in.
|
|
|
|
|
|
|
|
Notation scopes also apply to numeral notation ([3], [4], [5],
|
|
|
|
etc.), so you may sometimes see [0%nat], which means [O] (the
|
|
|
|
natural number [0] that we're using in this chapter), or [0%Z],
|
|
|
|
which means the Integer zero (which comes from a different part of
|
|
|
|
the standard library).
|
|
|
|
|
|
|
|
Pro tip: Coq's notation mechanism is not especially powerful.
|
|
|
|
Don't expect too much from it! *)
|
|
|
|
|
|
|
|
(* ================================================================= *)
|
|
|
|
(** ** Fixpoints and Structural Recursion (Optional) *)
|
|
|
|
|
|
|
|
(** Here is a copy of the definition of addition: *)
|
|
|
|
|
|
|
|
Fixpoint plus' (n : nat) (m : nat) : nat :=
|
|
|
|
match n with
|
|
|
|
| O => m
|
|
|
|
| S n' => S (plus' n' m)
|
|
|
|
end.
|
|
|
|
|
|
|
|
(** When Coq checks this definition, it notes that [plus'] is
|
|
|
|
"decreasing on 1st argument." What this means is that we are
|
|
|
|
performing a _structural recursion_ over the argument [n] -- i.e.,
|
|
|
|
that we make recursive calls only on strictly smaller values of
|
|
|
|
[n]. This implies that all calls to [plus'] will eventually
|
|
|
|
terminate. Coq demands that some argument of _every_ [Fixpoint]
|
|
|
|
definition is "decreasing."
|
|
|
|
|
|
|
|
This requirement is a fundamental feature of Coq's design: In
|
|
|
|
particular, it guarantees that every function that can be defined
|
|
|
|
in Coq will terminate on all inputs. However, because Coq's
|
|
|
|
"decreasing analysis" is not very sophisticated, it is sometimes
|
|
|
|
necessary to write functions in slightly unnatural ways. *)
|
|
|
|
|
|
|
|
(** **** Exercise: 2 stars, standard, optional (decreasing)
|
|
|
|
|
|
|
|
To get a concrete sense of this, find a way to write a sensible
|
|
|
|
[Fixpoint] definition (of a simple function on numbers, say) that
|
|
|
|
_does_ terminate on all inputs, but that Coq will reject because
|
|
|
|
of this restriction. (If you choose to turn in this optional
|
|
|
|
exercise as part of a homework assignment, make sure you comment
|
|
|
|
out your solution so that it doesn't cause Coq to reject the whole
|
|
|
|
file!) *)
|
|
|
|
|
|
|
|
(* FILL IN HERE
|
|
|
|
|
|
|
|
[] *)
|
|
|
|
|
|
|
|
(* ################################################################# *)
|
|
|
|
(** * More Exercises *)
|
|
|
|
|
|
|
|
(** Each SF chapter comes with a tester file (e.g. [BasicsTest.v]),
|
|
|
|
containing scripts that check most of the exercises. You can run
|
|
|
|
[make BasicsTest.vo] in a terminal and check its output to make
|
|
|
|
sure you didn't miss anything. *)
|
|
|
|
|
|
|
|
(** **** Exercise: 1 star, standard (indentity_fn_applied_twice)
|
|
|
|
|
|
|
|
Use the tactics you have learned so far to prove the following
|
|
|
|
theorem about boolean functions. *)
|
|
|
|
|
|
|
|
Theorem identity_fn_applied_twice :
|
|
|
|
forall (f : bool -> bool),
|
|
|
|
(forall (x : bool), f x = x) ->
|
|
|
|
forall (b : bool), f (f b) = b.
|
|
|
|
Proof.
|
2020-06-04 05:02:38 +00:00
|
|
|
intros f x b.
|
|
|
|
rewrite -> x.
|
|
|
|
rewrite -> x.
|
|
|
|
reflexivity.
|
|
|
|
Qed.
|
2020-06-04 02:46:06 +00:00
|
|
|
|
|
|
|
(** **** Exercise: 1 star, standard (negation_fn_applied_twice)
|
|
|
|
|
|
|
|
Now state and prove a theorem [negation_fn_applied_twice] similar
|
|
|
|
to the previous one but where the second hypothesis says that the
|
|
|
|
function [f] has the property that [f x = negb x]. *)
|
|
|
|
|
|
|
|
(* FILL IN HERE *)
|
|
|
|
(* The [Import] statement on the next line tells Coq to use the
|
|
|
|
standard library String module. We'll use strings more in later
|
|
|
|
chapters, but for the moment we just need syntax for literal
|
|
|
|
strings for the grader comments. *)
|
|
|
|
From Coq Require Export String.
|
|
|
|
|
|
|
|
(* Do not modify the following line: *)
|
|
|
|
Definition manual_grade_for_negation_fn_applied_twice : option (nat*string) := None.
|
|
|
|
(** [] *)
|
|
|
|
|
|
|
|
(** **** Exercise: 3 stars, standard, optional (andb_eq_orb)
|
|
|
|
|
|
|
|
Prove the following theorem. (Hint: This one can be a bit tricky,
|
|
|
|
depending on how you approach it. You will probably need both
|
|
|
|
[destruct] and [rewrite], but destructing everything in sight is
|
|
|
|
not the best way.) *)
|
|
|
|
|
|
|
|
Theorem andb_eq_orb :
|
|
|
|
forall (b c : bool),
|
|
|
|
(andb b c = orb b c) ->
|
|
|
|
b = c.
|
|
|
|
Proof.
|
2020-06-04 05:02:38 +00:00
|
|
|
intros [] [].
|
|
|
|
- reflexivity.
|
|
|
|
- simpl. intros H. rewrite -> H. reflexivity.
|
|
|
|
- simpl. intros H. rewrite -> H. reflexivity.
|
|
|
|
- reflexivity.
|
|
|
|
Qed.
|
2020-06-04 02:46:06 +00:00
|
|
|
|
|
|
|
(** [] *)
|
|
|
|
|
|
|
|
(** **** Exercise: 3 stars, standard (binary)
|
|
|
|
|
|
|
|
We can generalize our unary representation of natural numbers to
|
|
|
|
the more efficient binary representation by treating a binary
|
|
|
|
number as a sequence of constructors [A] and [B] (representing 0s
|
|
|
|
and 1s), terminated by a [Z]. For comparison, in the unary
|
|
|
|
representation, a number is a sequence of [S]s terminated by an
|
|
|
|
[O].
|
|
|
|
|
|
|
|
For example:
|
|
|
|
|
|
|
|
decimal binary unary
|
|
|
|
0 Z O
|
|
|
|
1 B Z S O
|
|
|
|
2 A (B Z) S (S O)
|
|
|
|
3 B (B Z) S (S (S O))
|
|
|
|
4 A (A (B Z)) S (S (S (S O)))
|
|
|
|
5 B (A (B Z)) S (S (S (S (S O))))
|
|
|
|
6 A (B (B Z)) S (S (S (S (S (S O)))))
|
|
|
|
7 B (B (B Z)) S (S (S (S (S (S (S O))))))
|
|
|
|
8 A (A (A (B Z))) S (S (S (S (S (S (S (S O)))))))
|
|
|
|
|
|
|
|
Note that the low-order bit is on the left and the high-order bit
|
|
|
|
is on the right -- the opposite of the way binary numbers are
|
|
|
|
usually written. This choice makes them easier to manipulate. *)
|
|
|
|
|
|
|
|
Inductive bin : Type :=
|
|
|
|
| Z
|
|
|
|
| A (n : bin)
|
|
|
|
| B (n : bin).
|
|
|
|
|
|
|
|
(** (a) Complete the definitions below of an increment function [incr]
|
|
|
|
for binary numbers, and a function [bin_to_nat] to convert
|
|
|
|
binary numbers to unary numbers. *)
|
|
|
|
|
2020-06-04 05:02:38 +00:00
|
|
|
Fixpoint incr (m:bin) : bin :=
|
|
|
|
match m with
|
|
|
|
| Z => B Z
|
|
|
|
| A n => B n
|
|
|
|
| B n => A (incr n)
|
|
|
|
end.
|
2020-06-04 02:46:06 +00:00
|
|
|
|
2020-06-04 05:02:38 +00:00
|
|
|
Fixpoint bin_to_nat (m:bin) : nat :=
|
|
|
|
match m with
|
|
|
|
| Z => 0
|
|
|
|
| A n => 2 * (bin_to_nat n)
|
|
|
|
| B n => 1 + 2 * (bin_to_nat n)
|
|
|
|
end.
|
2020-06-04 02:46:06 +00:00
|
|
|
|
|
|
|
(** (b) Write five unit tests [test_bin_incr1], [test_bin_incr2], etc.
|
|
|
|
for your increment and binary-to-unary functions. (A "unit
|
|
|
|
test" in Coq is a specific [Example] that can be proved with
|
|
|
|
just [reflexivity], as we've done for several of our
|
|
|
|
definitions.) Notice that incrementing a binary number and
|
|
|
|
then converting it to unary should yield the same result as
|
|
|
|
first converting it to unary and then incrementing. *)
|
|
|
|
|
2020-06-04 05:02:38 +00:00
|
|
|
Example test_bin_incr1 : incr Z = B Z.
|
|
|
|
Proof. reflexivity. Qed.
|
|
|
|
Example test_bin_incr2 : incr (B Z) = A (B Z).
|
|
|
|
Proof. reflexivity. Qed.
|
|
|
|
Example test_bin_incr3 : incr (A (B Z)) = B (B Z).
|
|
|
|
Proof. reflexivity. Qed.
|
|
|
|
Example test_bin_incr4 : incr (B (B Z)) = A (A (B Z)).
|
|
|
|
Proof. reflexivity. Qed.
|
|
|
|
Example test_bin_incr5 : incr (A (A (B Z))) = B (A (B Z)).
|
|
|
|
Proof. reflexivity. Qed.
|
|
|
|
|
|
|
|
Example test_bin_to_nat0 : bin_to_nat Z = 0.
|
|
|
|
Proof. reflexivity. Qed.
|
|
|
|
Example test_bin_to_nat1 : bin_to_nat (B Z) = 1.
|
|
|
|
Proof. reflexivity. Qed.
|
|
|
|
Example test_bin_to_nat2 : bin_to_nat (A (B Z)) = 2.
|
|
|
|
Proof. reflexivity. Qed.
|
|
|
|
Example test_bin_to_nat3 : bin_to_nat (B (B Z)) = 3.
|
|
|
|
Proof. reflexivity. Qed.
|
|
|
|
Example test_bin_to_nat4 : bin_to_nat (A (A (B Z))) = 4.
|
|
|
|
Proof. reflexivity. Qed.
|
2020-06-04 02:46:06 +00:00
|
|
|
|
|
|
|
(* Do not modify the following line: *)
|
|
|
|
Definition manual_grade_for_binary : option (nat*string) := None.
|
2020-06-04 05:02:38 +00:00
|
|
|
|
2020-06-04 02:46:06 +00:00
|
|
|
(** [] *)
|
|
|
|
|
|
|
|
(* Wed Jan 9 12:02:44 EST 2019 *)
|