Built with Alectryon, running Coq+SerAPI v8.10.0+0.7.0. Coq sources are in this panel; goals and messages will appear in the other. Bubbles () indicate interactive fragments: hover for details, tap to reveal contents. Use Ctrl+↑ Ctrl+↓ to navigate, Ctrl+🖱️ to focus.

Logic: Logic in Coq

Set Warnings "-notation-overridden,-parsing".
From LF Require Export Tactics.
In previous chapters, we have seen many examples of factual claims (propositions) and ways of presenting evidence of their truth (proofs). In particular, we have worked extensively with equality propositions of the form e1 = e2, with implications (P Q), and with quantified propositions ( x, P). In this chapter, we will see how Coq can be used to carry out other familiar forms of logical reasoning.
Before diving into details, let's talk a bit about the status of mathematical statements in Coq. Recall that Coq is a typed language, which means that every sensible expression in its world has an associated type. Logical claims are no exception: any statement we might try to prove in Coq has a type, namely Prop, the type of propositions. We can see this with the Check command:
3 = 3 : Prop
forall n m : nat, n + m = m + n : Prop
Note that all syntactically well-formed propositions have type Prop in Coq, regardless of whether they are true.
Simply being a proposition is one thing; being provable is something else!
2 = 2 : Prop
forall n : nat, n = 2 : Prop
3 = 4 : Prop
Indeed, propositions don't just have types: they are first-class objects that can be manipulated in the same ways as the other entities in Coq's world.
So far, we've seen one primary place that propositions can appear: in Theorem (and Lemma and Example) declarations.

2 + 2 = 4

2 + 2 = 4
reflexivity. Qed.
But propositions can be used in many other ways. For example, we can give a name to a proposition using a Definition, just as we have given names to expressions of other sorts.
Definition plus_fact : Prop := 2 + 2 = 4.
plus_fact : Prop
We can later use this name in any situation where a proposition is expected -- for example, as the claim in a Theorem declaration.

plus_fact

plus_fact
reflexivity. Qed.
We can also write parameterized propositions -- that is, functions that take arguments of some type and return a proposition.
For instance, the following function takes a number and returns a proposition asserting that this number is equal to three:
Definition is_three (n : nat) : Prop :=
  n = 3.
is_three : nat -> Prop
In Coq, functions that return propositions are said to define properties of their arguments.
For instance, here's a (polymorphic) property defining the familiar notion of an injective function.
Definition injective {A B} (f : A -> B) :=
  forall x y : A, f x = f y -> x = y.


injective S

injective S
n, m:nat
H:S n = S m

n = m
n, m:nat
H1:n = m

n = m
apply H1. Qed.
The equality operator = is also a function that returns a Prop.
The expression n = m is syntactic sugar for eq n m (defined using Coq's Notation mechanism). Because eq can be used with elements of any type, it is also polymorphic:
@eq : forall A : Type, A -> A -> Prop
(Notice that we wrote @eq instead of eq: The type argument A to eq is declared as implicit, so we need to turn off implicit arguments to see the full type of eq.)
(* ################################################################# *)

Logical Connectives

(* ================================================================= *)

Conjunction

The conjunction, or logical and, of propositions A and B is written A B, representing the claim that both A and B are true.

3 + 4 = 7 /\ 2 * 2 = 4
To prove a conjunction, use the split tactic. It will generate two subgoals, one for each part of the statement:

3 + 4 = 7 /\ 2 * 2 = 4

3 + 4 = 7

2 * 2 = 4

3 + 4 = 7
reflexivity.

2 * 2 = 4
reflexivity. Qed.
For any propositions A and B, if we assume that A is true and we assume that B is true, we can conclude that A B is also true.

forall A B : Prop, A -> B -> A /\ B

forall A B : Prop, A -> B -> A /\ B
A, B:Prop
HA:A
HB:B

A /\ B
A, B:Prop
HA:A
HB:B

A
A, B:Prop
HA:A
HB:B
B
A, B:Prop
HA:A
HB:B

A
apply HA.
A, B:Prop
HA:A
HB:B

B
apply HB. Qed.
Since applying a theorem with hypotheses to some goal has the effect of generating as many subgoals as there are hypotheses for that theorem, we can apply and_intro to achieve the same effect as split.

3 + 4 = 7 /\ 2 * 2 = 4

3 + 4 = 7 /\ 2 * 2 = 4

3 + 4 = 7

2 * 2 = 4

3 + 4 = 7
reflexivity.

2 * 2 = 4
reflexivity. Qed.

Exercise: 2 stars, standard (and_exercise)


forall n m : nat, n + m = 0 -> n = 0 /\ m = 0

forall n m : nat, n + m = 0 -> n = 0 /\ m = 0
(* FILL IN HERE *) Admitted.
So much for proving conjunctive statements. To go in the other direction -- i.e., to use a conjunctive hypothesis to help prove something else -- we employ the destruct tactic.
If the proof context contains a hypothesis H of the form A B, writing destruct H as [HA HB] will remove H from the context and add two new hypotheses: HA, stating that A is true, and HB, stating that B is true.

forall n m : nat, n = 0 /\ m = 0 -> n + m = 0

forall n m : nat, n = 0 /\ m = 0 -> n + m = 0
(* WORKED IN CLASS *)
n, m:nat
H:n = 0 /\ m = 0

n + m = 0
n, m:nat
Hn:n = 0
Hm:m = 0

n + m = 0
n, m:nat
Hn:n = 0
Hm:m = 0

0 + m = 0
n, m:nat
Hn:n = 0
Hm:m = 0

0 + 0 = 0
reflexivity. Qed.
As usual, we can also destruct H right when we introduce it, instead of introducing and then destructing it:

forall n m : nat, n = 0 /\ m = 0 -> n + m = 0

forall n m : nat, n = 0 /\ m = 0 -> n + m = 0
n, m:nat
Hn:n = 0
Hm:m = 0

n + m = 0
n, m:nat
Hn:n = 0
Hm:m = 0

0 + m = 0
n, m:nat
Hn:n = 0
Hm:m = 0

0 + 0 = 0
reflexivity. Qed.
You may wonder why we bothered packing the two hypotheses n = 0 and m = 0 into a single conjunction, since we could have also stated the theorem with two separate premises:

forall n m : nat, n = 0 -> m = 0 -> n + m = 0

forall n m : nat, n = 0 -> m = 0 -> n + m = 0
n, m:nat
Hn:n = 0
Hm:m = 0

n + m = 0
n, m:nat
Hn:n = 0
Hm:m = 0

0 + m = 0
n, m:nat
Hn:n = 0
Hm:m = 0

0 + 0 = 0
reflexivity. Qed.
For this theorem, both formulations are fine. But it's important to understand how to work with conjunctive hypotheses because conjunctions often arise from intermediate steps in proofs, especially in bigger developments. Here's a simple example:

forall n m : nat, n + m = 0 -> n * m = 0

forall n m : nat, n + m = 0 -> n * m = 0
(* WORKED IN CLASS *)
n, m:nat
H:n + m = 0

n * m = 0
n, m:nat
H:n + m = 0

n = 0 /\ m = 0
n, m:nat
H:n + m = 0
H':n = 0 /\ m = 0
n * m = 0
n, m:nat
H:n + m = 0

n = 0 /\ m = 0
n, m:nat
H:n + m = 0

n + m = 0
apply H.
n, m:nat
H:n + m = 0
H':n = 0 /\ m = 0

n * m = 0
n, m:nat
H:n + m = 0
Hn:n = 0
Hm:m = 0

n * m = 0
n, m:nat
H:n + m = 0
Hn:n = 0
Hm:m = 0

0 * m = 0
reflexivity. Qed.
Another common situation with conjunctions is that we know A B but in some context we need just A (or just B). The following lemmas are useful in such cases:

forall P Q : Prop, P /\ Q -> P

forall P Q : Prop, P /\ Q -> P
P, Q:Prop
HP:P
HQ:Q

P
apply HP. Qed.

Exercise: 1 star, standard, optional (proj2)


forall P Q : Prop, P /\ Q -> Q

forall P Q : Prop, P /\ Q -> Q
(* FILL IN HERE *) Admitted.
Finally, we sometimes need to rearrange the order of conjunctions and/or the grouping of multi-way conjunctions. The following commutativity and associativity theorems are handy in such cases.

forall P Q : Prop, P /\ Q -> Q /\ P

forall P Q : Prop, P /\ Q -> Q /\ P
P, Q:Prop
HP:P
HQ:Q

Q /\ P
P, Q:Prop
HP:P
HQ:Q

Q
P, Q:Prop
HP:P
HQ:Q
P
P, Q:Prop
HP:P
HQ:Q

Q
apply HQ.
P, Q:Prop
HP:P
HQ:Q

P
apply HP. Qed.

Exercise: 2 stars, standard (and_assoc)

(In the following proof of associativity, notice how the nested intros pattern breaks the hypothesis H : P (Q R) down into HP : P, HQ : Q, and HR : R. Finish the proof from there.)

forall P Q R : Prop, P /\ Q /\ R -> (P /\ Q) /\ R

forall P Q R : Prop, P /\ Q /\ R -> (P /\ Q) /\ R
P, Q, R:Prop
HP:P
HQ:Q
HR:R

(P /\ Q) /\ R
(* FILL IN HERE *) Admitted.
By the way, the infix notation is actually just syntactic sugar for and A B. That is, and is a Coq operator that takes two propositions as arguments and yields a proposition.
and : Prop -> Prop -> Prop
(* ================================================================= *)

Disjunction

Another important connective is the disjunction, or logical or, of two propositions: A B is true when either A or B is. (This infix notation stands for or A B, where or : Prop Prop Prop.)
To use a disjunctive hypothesis in a proof, we proceed by case analysis, which, as for nat or other data types, can be done explicitly with destruct or implicitly with an intros pattern:

forall n m : nat, n = 0 \/ m = 0 -> n * m = 0

forall n m : nat, n = 0 \/ m = 0 -> n * m = 0
(* This pattern implicitly does case analysis on [n = 0 \/ m = 0] *)
n, m:nat
Hn:n = 0

n * m = 0
n, m:nat
Hm:m = 0
n * m = 0
n, m:nat
Hn:n = 0

n * m = 0
n, m:nat
Hn:n = 0

0 * m = 0
reflexivity.
n, m:nat
Hm:m = 0

n * m = 0
n, m:nat
Hm:m = 0

n * 0 = 0
n, m:nat
Hm:m = 0

0 = 0
reflexivity. Qed.
Conversely, to show that a disjunction holds, we need to show that one of its sides does. This is done via two tactics, left and right. As their names imply, the first one requires proving the left side of the disjunction, while the second requires proving its right side. Here is a trivial use...

forall A B : Prop, A -> A \/ B

forall A B : Prop, A -> A \/ B
A, B:Prop
HA:A

A \/ B
A, B:Prop
HA:A

A
apply HA. Qed.
... and here is a slightly more interesting example requiring both left and right:

forall n : nat, n = 0 \/ n = S (Nat.pred n)

forall n : nat, n = 0 \/ n = S (Nat.pred n)
(* WORKED IN CLASS *)

0 = 0 \/ 0 = S (Nat.pred 0)
n:nat
S n = 0 \/ S n = S (Nat.pred (S n))

0 = 0 \/ 0 = S (Nat.pred 0)

0 = 0
reflexivity.
n:nat

S n = 0 \/ S n = S (Nat.pred (S n))
n:nat

S n = S (Nat.pred (S n))
reflexivity. Qed.

Exercise: 1 star, standard (mult_eq_0)


forall n m : nat, n * m = 0 -> n = 0 \/ m = 0

forall n m : nat, n * m = 0 -> n = 0 \/ m = 0
(* FILL IN HERE *) Admitted.

Exercise: 1 star, standard (or_commut)


forall P Q : Prop, P \/ Q -> Q \/ P

forall P Q : Prop, P \/ Q -> Q \/ P
(* FILL IN HERE *) Admitted.
(* ================================================================= *)

Falsehood and Negation

So far, we have mostly been concerned with proving that certain things are true -- addition is commutative, appending lists is associative, etc. Of course, we may also be interested in negative results, showing that some given proposition is not true. In Coq, such statements are expressed with the negation operator ¬.
To see how negation works, recall the principle of explosion from the Tactics chapter; it asserts that, if we assume a contradiction, then any other proposition can be derived.
Following this intuition, we could define ¬ P ("not P") as Q, P Q.
Coq actually makes a slightly different (but equivalent) choice, defining ¬ P as P False, where False is a specific contradictory proposition defined in the standard library.
Module MyNot.

Definition not (P:Prop) := P -> False.

Notation "~ x" := (not x) : type_scope.

not : Prop -> Prop
End MyNot.
Since False is a contradictory proposition, the principle of explosion also applies to it. If we get False into the proof context, we can use destruct on it to complete any goal:

forall P : Prop, False -> P

forall P : Prop, False -> P
(* WORKED IN CLASS *)
P:Prop
contra:False

P
destruct contra. Qed.
The Latin ex falso quodlibet means, literally, "from falsehood follows whatever you like"; this is another common name for the principle of explosion.

Exercise: 2 stars, standard, optional (not_implies_our_not)

Show that Coq's definition of negation implies the intuitive one mentioned above:

forall P : Prop, ~ P -> forall Q : Prop, P -> Q

forall P : Prop, ~ P -> forall Q : Prop, P -> Q
(* FILL IN HERE *) Admitted.
Inequality is a frequent enough example of negated statement that there is a special notation for it, x y:
Notation "x <> y" := (~(x = y)).
We can use not to state that 0 and 1 are different elements of nat:

0 <> 1

0 <> 1
The proposition 0 1 is exactly the same as ~(0 = 1), that is not (0 = 1), which unfolds to (0 = 1) False. (We use unfold not explicitly here to illustrate that point, but generally it can be omitted.)
  

0 = 1 -> False
To prove an inequality, we may assume the opposite equality...
  
contra:0 = 1

False
... and deduce a contradiction from it. Here, the equality O = S O contradicts the disjointness of constructors O and S, so discriminate takes care of it.
  discriminate contra.
Qed.
It takes a little practice to get used to working with negation in Coq. Even though you can see perfectly well why a statement involving negation is true, it can be a little tricky at first to get things into the right configuration so that Coq can understand it! Here are proofs of a few familiar facts to get you warmed up.

~ False

~ False

False -> False
H:False

False
destruct H. Qed.

forall P Q : Prop, P /\ ~ P -> Q

forall P Q : Prop, P /\ ~ P -> Q
(* WORKED IN CLASS *)
P, Q:Prop
HP:P
HNA:~ P

Q
P, Q:Prop
HP:P
HNA:P -> False

Q
P, Q:Prop
HP:False
HNA:P -> False

Q
destruct HP. Qed.

forall P : Prop, P -> ~ ~ P

forall P : Prop, P -> ~ ~ P
(* WORKED IN CLASS *)
P:Prop
H:P

~ ~ P
P:Prop
H:P

(P -> False) -> False
P:Prop
H:P
G:P -> False

False
P:Prop
H:P
G:P -> False

P
apply H. Qed.

Exercise: 2 stars, advanced (double_neg_inf)

Write an informal proof of double_neg:
Theorem: P implies ~~P, for any proposition P.
(* FILL IN HERE *)

(* Do not modify the following line: *)
Definition manual_grade_for_double_neg_inf : option (nat*string) := None.

Exercise: 2 stars, standard, recommended (contrapositive)


forall P Q : Prop, (P -> Q) -> ~ Q -> ~ P

forall P Q : Prop, (P -> Q) -> ~ Q -> ~ P
(* FILL IN HERE *) Admitted.

Exercise: 1 star, standard (not_both_true_and_false)


forall P : Prop, ~ (P /\ ~ P)

forall P : Prop, ~ (P /\ ~ P)
(* FILL IN HERE *) Admitted.

Exercise: 1 star, advanced (informal_not_PNP)

Write an informal proof (in English) of the proposition P : Prop, ~(P ¬P).
(* FILL IN HERE *)

(* Do not modify the following line: *)
Definition manual_grade_for_informal_not_PNP : option (nat*string) := None.
Similarly, since inequality involves a negation, it requires a little practice to be able to work with it fluently. Here is one useful trick. If you are trying to prove a goal that is nonsensical (e.g., the goal state is false = true), apply ex_falso_quodlibet to change the goal to False. This makes it easier to use assumptions of the form ¬P that may be available in the context -- in particular, assumptions of the form xy.

forall b : bool, b <> true -> b = false

forall b : bool, b <> true -> b = false
H:true <> true

true = false
H:false <> true
false = false
H:true <> true

true = false
H:true = true -> False

true = false
H:true = true -> False

False
H:true = true -> False

true = true
reflexivity.
H:false <> true

false = false
reflexivity. Qed.
Since reasoning with ex_falso_quodlibet is quite common, Coq provides a built-in tactic, exfalso, for applying it.

forall b : bool, b <> true -> b = false

forall b : bool, b <> true -> b = false
H:true <> true

true = false
H:false <> true
false = false
H:true <> true

true = false
H:true = true -> False

true = false
H:true = true -> False

False
H:true = true -> False

true = true
reflexivity.
H:false <> true

false = false
reflexivity. Qed. (* ================================================================= *)

Truth

Besides False, Coq's standard library also defines True, a proposition that is trivially true. To prove it, we use the predefined constant I : True:

True

True
apply I. Qed.
Unlike False, which is used extensively, True is used quite rarely, since it is trivial (and therefore uninteresting) to prove as a goal, and it carries no useful information as a hypothesis.
But it can be quite useful when defining complex Props using conditionals or as a parameter to higher-order Props. We will see examples of such uses of True later on.
(* ================================================================= *)

Logical Equivalence

The handy "if and only if" connective, which asserts that two propositions have the same truth value, is just the conjunction of two implications.
Module MyIff.

Definition iff (P Q : Prop) := (P -> Q) /\ (Q -> P).

Notation "P <-> Q" := (iff P Q)
                      (at level 95, no associativity)
                      : type_scope.

End MyIff.


forall P Q : Prop, P <-> Q -> Q <-> P

forall P Q : Prop, P <-> Q -> Q <-> P
(* WORKED IN CLASS *)
P, Q:Prop
HAB:P -> Q
HBA:Q -> P

Q <-> P
P, Q:Prop
HAB:P -> Q
HBA:Q -> P

Q -> P
P, Q:Prop
HAB:P -> Q
HBA:Q -> P
P -> Q
P, Q:Prop
HAB:P -> Q
HBA:Q -> P

Q -> P
apply HBA.
P, Q:Prop
HAB:P -> Q
HBA:Q -> P

P -> Q
apply HAB. Qed.

forall b : bool, b <> true <-> b = false

forall b : bool, b <> true <-> b = false
(* WORKED IN CLASS *)
b:bool

b <> true <-> b = false
b:bool

b <> true -> b = false
b:bool
b = false -> b <> true
b:bool

b <> true -> b = false
apply not_true_is_false.
b:bool

b = false -> b <> true
b:bool
H:b = false

b <> true
b:bool
H:b = false

false <> true
b:bool
H:b = false
H':false = true

False
discriminate H'. Qed.

Exercise: 1 star, standard, optional (iff_properties)

Using the above proof that is symmetric (iff_sym) as a guide, prove that it is also reflexive and transitive.

forall P : Prop, P <-> P

forall P : Prop, P <-> P
(* FILL IN HERE *) Admitted.

forall P Q R : Prop, P <-> Q -> Q <-> R -> P <-> R

forall P Q R : Prop, P <-> Q -> Q <-> R -> P <-> R
(* FILL IN HERE *) Admitted.

Exercise: 3 stars, standard (or_distributes_over_and)


forall P Q R : Prop, P \/ Q /\ R <-> (P \/ Q) /\ (P \/ R)

forall P Q R : Prop, P \/ Q /\ R <-> (P \/ Q) /\ (P \/ R)
(* FILL IN HERE *) Admitted.
Some of Coq's tactics treat iff statements specially, avoiding the need for some low-level proof-state manipulation. In particular, rewrite and reflexivity can be used with iff statements, not just equalities. To enable this behavior, we need to import a Coq library that supports it:
From Coq Require Import Setoids.Setoid.
Here is a simple example demonstrating how these tactics work with iff. First, let's prove a couple of basic iff equivalences...

forall n m : nat, n * m = 0 <-> n = 0 \/ m = 0

forall n m : nat, n * m = 0 <-> n = 0 \/ m = 0
n, m:nat

n * m = 0 -> n = 0 \/ m = 0
n, m:nat
n = 0 \/ m = 0 -> n * m = 0
n, m:nat

n * m = 0 -> n = 0 \/ m = 0
apply mult_eq_0.
n, m:nat

n = 0 \/ m = 0 -> n * m = 0
apply or_example. Qed.

forall P Q R : Prop, P \/ Q \/ R <-> (P \/ Q) \/ R

forall P Q R : Prop, P \/ Q \/ R <-> (P \/ Q) \/ R
P, Q, R:Prop

P \/ Q \/ R <-> (P \/ Q) \/ R
P, Q, R:Prop

P \/ Q \/ R -> (P \/ Q) \/ R
P, Q, R:Prop
(P \/ Q) \/ R -> P \/ Q \/ R
P, Q, R:Prop

P \/ Q \/ R -> (P \/ Q) \/ R
P, Q, R:Prop
H:P

(P \/ Q) \/ R
P, Q, R:Prop
H:Q
(P \/ Q) \/ R
P, Q, R:Prop
H:R
(P \/ Q) \/ R
P, Q, R:Prop
H:P

(P \/ Q) \/ R
P, Q, R:Prop
H:P

P \/ Q
P, Q, R:Prop
H:P

P
apply H.
P, Q, R:Prop
H:Q

(P \/ Q) \/ R
P, Q, R:Prop
H:Q

P \/ Q
P, Q, R:Prop
H:Q

Q
apply H.
P, Q, R:Prop
H:R

(P \/ Q) \/ R
P, Q, R:Prop
H:R

R
apply H.
P, Q, R:Prop

(P \/ Q) \/ R -> P \/ Q \/ R
P, Q, R:Prop
H:P

P \/ Q \/ R
P, Q, R:Prop
H:Q
P \/ Q \/ R
P, Q, R:Prop
H:R
P \/ Q \/ R
P, Q, R:Prop
H:P

P \/ Q \/ R
P, Q, R:Prop
H:P

P
apply H.
P, Q, R:Prop
H:Q

P \/ Q \/ R
P, Q, R:Prop
H:Q

Q \/ R
P, Q, R:Prop
H:Q

Q
apply H.
P, Q, R:Prop
H:R

P \/ Q \/ R
P, Q, R:Prop
H:R

Q \/ R
P, Q, R:Prop
H:R

R
apply H. Qed.
We can now use these facts with rewrite and reflexivity to give smooth proofs of statements involving equivalences. Here is a ternary version of the previous mult_0 result:

forall n m p : nat, n * m * p = 0 <-> n = 0 \/ m = 0 \/ p = 0

forall n m p : nat, n * m * p = 0 <-> n = 0 \/ m = 0 \/ p = 0
n, m, p:nat

n * m * p = 0 <-> n = 0 \/ m = 0 \/ p = 0
n, m, p:nat

n * m = 0 \/ p = 0 <-> n = 0 \/ m = 0 \/ p = 0
n, m, p:nat

(n = 0 \/ m = 0) \/ p = 0 <-> n = 0 \/ m = 0 \/ p = 0
n, m, p:nat

(n = 0 \/ m = 0) \/ p = 0 <-> (n = 0 \/ m = 0) \/ p = 0
reflexivity. Qed.
The apply tactic can also be used with . When given an equivalence as its argument, apply tries to guess which side of the equivalence to use.

forall n m : nat, n * m = 0 -> n = 0 \/ m = 0

forall n m : nat, n * m = 0 -> n = 0 \/ m = 0
n, m:nat
H:n * m = 0

n = 0 \/ m = 0
n, m:nat
H:n * m = 0

n * m = 0
apply H. Qed. (* ================================================================= *)

Existential Quantification

Another important logical connective is existential quantification. To say that there is some x of type T such that some property P holds of x, we write x : T, P. As with , the type annotation : T can be omitted if Coq is able to infer from the context what the type of x should be.
To prove a statement of the form x, P, we must show that P holds for some specific choice of value for x, known as the witness of the existential. This is done in two steps: First, we explicitly tell Coq which witness t we have in mind by invoking the tactic t. Then we prove that P holds after all occurrences of x are replaced by t.

exists n : nat, 4 = n + n

exists n : nat, 4 = n + n

4 = 2 + 2
reflexivity. Qed.
Conversely, if we have an existential hypothesis x, P in the context, we can destruct it to obtain a witness x and a hypothesis stating that P holds of x.

forall n : nat, (exists m : nat, n = 4 + m) -> exists o : nat, n = 2 + o

forall n : nat, (exists m : nat, n = 4 + m) -> exists o : nat, n = 2 + o
(* WORKED IN CLASS *)
n, m:nat
Hm:n = 4 + m

exists o : nat, n = 2 + o
n, m:nat
Hm:n = 4 + m

n = 2 + (2 + m)
apply Hm. Qed.

Exercise: 1 star, standard, recommended (dist_not_exists)

Prove that "P holds for all x" implies "there is no x for which P does not hold." (Hint: destruct H as [x E] works on existential assumptions!)

forall (X : Type) (P : X -> Prop), (forall x : X, P x) -> ~ (exists x : X, ~ P x)

forall (X : Type) (P : X -> Prop), (forall x : X, P x) -> ~ (exists x : X, ~ P x)
(* FILL IN HERE *) Admitted.

Exercise: 2 stars, standard (dist_exists_or)

Prove that existential quantification distributes over disjunction.

forall (X : Type) (P Q : X -> Prop), (exists x : X, P x \/ Q x) <-> (exists x : X, P x) \/ (exists x : X, Q x)

forall (X : Type) (P Q : X -> Prop), (exists x : X, P x \/ Q x) <-> (exists x : X, P x) \/ (exists x : X, Q x)
(* FILL IN HERE *) Admitted.
(* ################################################################# *)

Programming with Propositions

The logical connectives that we have seen provide a rich vocabulary for defining complex propositions from simpler ones. To illustrate, let's look at how to express the claim that an element x occurs in a list l. Notice that this property has a simple recursive structure:
We can translate this directly into a straightforward recursive function taking an element and a list and returning a proposition:
Fixpoint In {A : Type} (x : A) (l : list A) : Prop :=
  match l with
  | [] => False
  | x' :: l' => x' = x \/ In x l'
  end.
When In is applied to a concrete list, it expands into a concrete sequence of nested disjunctions.

In 4 [1; 2; 3; 4; 5]

In 4 [1; 2; 3; 4; 5]
(* WORKED IN CLASS *)

1 = 4 \/ 2 = 4 \/ 3 = 4 \/ 4 = 4 \/ 5 = 4 \/ False

2 = 4 \/ 3 = 4 \/ 4 = 4 \/ 5 = 4 \/ False

3 = 4 \/ 4 = 4 \/ 5 = 4 \/ False

4 = 4 \/ 5 = 4 \/ False

4 = 4
reflexivity. Qed.

forall n : nat, In n [2; 4] -> exists n' : nat, n = 2 * n'

forall n : nat, In n [2; 4] -> exists n' : nat, n = 2 * n'
(* WORKED IN CLASS *)

forall n : nat, 2 = n \/ 4 = n \/ False -> exists n' : nat, n = n' + (n' + 0)
n:nat
H:2 = n

exists n' : nat, n = n' + (n' + 0)
n:nat
H:4 = n
exists n' : nat, n = n' + (n' + 0)
n:nat
H:2 = n

exists n' : nat, n = n' + (n' + 0)
n:nat
H:2 = n

n = 1 + (1 + 0)
n:nat
H:2 = n

2 = 1 + (1 + 0)
reflexivity.
n:nat
H:4 = n

exists n' : nat, n = n' + (n' + 0)
n:nat
H:4 = n

n = 2 + (2 + 0)
n:nat
H:4 = n

4 = 2 + (2 + 0)
reflexivity. Qed.
(Notice the use of the empty pattern to discharge the last case en passant.)
We can also prove more generic, higher-level lemmas about In.
Note, in the next, how In starts out applied to a variable and only gets expanded when we do case analysis on this variable:

forall (A B : Type) (f : A -> B) (l : list A) (x : A), In x l -> In (f x) (map f l)

forall (A B : Type) (f : A -> B) (l : list A) (x : A), In x l -> In (f x) (map f l)
A, B:Type
f:A -> B
l:list A
x:A

In x l -> In (f x) (map f l)
A, B:Type
f:A -> B
x:A

In x [ ] -> In (f x) (map f [ ])
A, B:Type
f:A -> B
x':A
l':list A
x:A
IHl':In x l' -> In (f x) (map f l')
In x (x' :: l') -> In (f x) (map f (x' :: l'))
A, B:Type
f:A -> B
x:A

In x [ ] -> In (f x) (map f [ ])
A, B:Type
f:A -> B
x:A

False -> False
intros [].
A, B:Type
f:A -> B
x':A
l':list A
x:A
IHl':In x l' -> In (f x) (map f l')

In x (x' :: l') -> In (f x) (map f (x' :: l'))
A, B:Type
f:A -> B
x':A
l':list A
x:A
IHl':In x l' -> In (f x) (map f l')

x' = x \/ In x l' -> f x' = f x \/ In (f x) (map f l')
A, B:Type
f:A -> B
x':A
l':list A
x:A
IHl':In x l' -> In (f x) (map f l')
H:x' = x

f x' = f x \/ In (f x) (map f l')
A, B:Type
f:A -> B
x':A
l':list A
x:A
IHl':In x l' -> In (f x) (map f l')
H:In x l'
f x' = f x \/ In (f x) (map f l')
A, B:Type
f:A -> B
x':A
l':list A
x:A
IHl':In x l' -> In (f x) (map f l')
H:x' = x

f x' = f x \/ In (f x) (map f l')
A, B:Type
f:A -> B
x':A
l':list A
x:A
IHl':In x l' -> In (f x) (map f l')
H:x' = x

f x = f x \/ In (f x) (map f l')
A, B:Type
f:A -> B
x':A
l':list A
x:A
IHl':In x l' -> In (f x) (map f l')
H:x' = x

f x = f x
reflexivity.
A, B:Type
f:A -> B
x':A
l':list A
x:A
IHl':In x l' -> In (f x) (map f l')
H:In x l'

f x' = f x \/ In (f x) (map f l')
A, B:Type
f:A -> B
x':A
l':list A
x:A
IHl':In x l' -> In (f x) (map f l')
H:In x l'

In (f x) (map f l')
A, B:Type
f:A -> B
x':A
l':list A
x:A
IHl':In x l' -> In (f x) (map f l')
H:In x l'

In x l'
apply H. Qed.
This way of defining propositions recursively, though convenient in some cases, also has some drawbacks. In particular, it is subject to Coq's usual restrictions regarding the definition of recursive functions, e.g., the requirement that they be "obviously terminating." In the next chapter, we will see how to define propositions inductively, a different technique with its own set of strengths and limitations.

Exercise: 2 stars, standard (In_map_iff)


forall (A B : Type) (f : A -> B) (l : list A) (y : B), In y (map f l) <-> (exists x : A, f x = y /\ In x l)

forall (A B : Type) (f : A -> B) (l : list A) (y : B), In y (map f l) <-> (exists x : A, f x = y /\ In x l)
(* FILL IN HERE *) Admitted.

Exercise: 2 stars, standard (In_app_iff)


forall (A : Type) (l l' : list A) (a : A), In a (l ++ l') <-> In a l \/ In a l'

forall (A : Type) (l l' : list A) (a : A), In a (l ++ l') <-> In a l \/ In a l'
(* FILL IN HERE *) Admitted.

Exercise: 3 stars, standard, recommended (All)

Recall that functions returning propositions can be seen as properties of their arguments. For instance, if P has type nat Prop, then P n states that property P holds of n.
Drawing inspiration from In, write a recursive function All stating that some property P holds of all elements of a list l. To make sure your definition is correct, prove the All_In lemma below. (Of course, your definition should not just restate the left-hand side of All_In.)
All:forall T0 : Type, (T0 -> Prop) -> list T0 -> Prop
T:Type
P:T -> Prop
l:list T

Prop
Admitted.

forall (T : Type) (P : T -> Prop) (l : list T), (forall x : T, In x l -> P x) <-> All P l

forall (T : Type) (P : T -> Prop) (l : list T), (forall x : T, In x l -> P x) <-> All P l
(* FILL IN HERE *) Admitted.

Exercise: 3 stars, standard (combine_odd_even)

Complete the definition of the combine_odd_even function below. It takes as arguments two properties of numbers, Podd and Peven, and it should return a property P such that P n is equivalent to Podd n when n is odd and equivalent to Peven n otherwise.
Podd, Peven:nat -> Prop

nat -> Prop
Admitted.
To test your definition, prove the following facts:

forall (Podd Peven : nat -> Prop) (n : nat), (oddb n = true -> Podd n) -> (oddb n = false -> Peven n) -> combine_odd_even Podd Peven n

forall (Podd Peven : nat -> Prop) (n : nat), (oddb n = true -> Podd n) -> (oddb n = false -> Peven n) -> combine_odd_even Podd Peven n
(* FILL IN HERE *) Admitted.

forall (Podd Peven : nat -> Prop) (n : nat), combine_odd_even Podd Peven n -> oddb n = true -> Podd n

forall (Podd Peven : nat -> Prop) (n : nat), combine_odd_even Podd Peven n -> oddb n = true -> Podd n
(* FILL IN HERE *) Admitted.

forall (Podd Peven : nat -> Prop) (n : nat), combine_odd_even Podd Peven n -> oddb n = false -> Peven n

forall (Podd Peven : nat -> Prop) (n : nat), combine_odd_even Podd Peven n -> oddb n = false -> Peven n
(* FILL IN HERE *) Admitted.
(* ################################################################# *)

Applying Theorems to Arguments

One feature of Coq that distinguishes it from some other popular proof assistants (e.g., ACL2 and Isabelle) is that it treats proofs as first-class objects.
There is a great deal to be said about this, but it is not necessary to understand it all in detail in order to use Coq. This section gives just a taste, while a deeper exploration can be found in the optional chapters ProofObjects and IndPrinciples.
We have seen that we can use the Check command to ask Coq to print the type of an expression. We can also use Check to ask what theorem a particular identifier refers to.
plus_comm : forall n m : nat, n + m = m + n
Coq prints the statement of the plus_comm theorem in the same way that it prints the type of any term that we ask it to Check. Why?
The reason is that the identifier plus_comm actually refers to a proof object -- a data structure that represents a logical derivation establishing of the truth of the statement n m : nat, n + m = m + n. The type of this object is the statement of the theorem that it is a proof of.
Intuitively, this makes sense because the statement of a theorem tells us what we can use that theorem for, just as the type of a computational object tells us what we can do with that object -- e.g., if we have a term of type nat nat nat, we can give it two nats as arguments and get a nat back. Similarly, if we have an object of type n = m n + n = m + m and we provide it an "argument" of type n = m, we can derive n + n = m + m.
Operationally, this analogy goes even further: by applying a theorem, as if it were a function, to hypotheses with matching types, we can specialize its result without having to resort to intermediate assertions. For example, suppose we wanted to prove the following result:

forall x y z : nat, x + (y + z) = z + y + x
It appears at first sight that we ought to be able to prove this by rewriting with plus_comm twice to make the two sides match. The problem, however, is that the second rewrite will undo the effect of the first.

forall x y z : nat, x + (y + z) = z + y + x
(* WORKED IN CLASS *)
x, y, z:nat

x + (y + z) = z + y + x
x, y, z:nat

y + z + x = z + y + x
x, y, z:nat

x + (y + z) = z + y + x
(* We are back where we started... *) Abort.
One simple way of fixing this problem, using only tools that we already know, is to use assert to derive a specialized version of plus_comm that can be used to rewrite exactly where we want.

forall x y z : nat, x + (y + z) = z + y + x

forall x y z : nat, x + (y + z) = z + y + x
x, y, z:nat

x + (y + z) = z + y + x
x, y, z:nat

y + z + x = z + y + x
x, y, z:nat

y + z = z + y
x, y, z:nat
H:y + z = z + y
y + z + x = z + y + x
x, y, z:nat

y + z = z + y
x, y, z:nat

z + y = z + y
reflexivity.
x, y, z:nat
H:y + z = z + y

y + z + x = z + y + x
x, y, z:nat
H:y + z = z + y

z + y + x = z + y + x
reflexivity. Qed.
A more elegant alternative is to apply plus_comm directly to the arguments we want to instantiate it with, in much the same way as we apply a polymorphic function to a type argument.

forall x y z : nat, x + (y + z) = z + y + x

forall x y z : nat, x + (y + z) = z + y + x
x, y, z:nat

x + (y + z) = z + y + x
x, y, z:nat

y + z + x = z + y + x
x, y, z:nat

z + y + x = z + y + x
reflexivity. Qed.
Let us show another example of using a theorem or lemma like a function. The following theorem says: any list l containing some element must be nonempty.

forall (A : Type) (x : A) (l : list A), In x l -> l <> [ ]

forall (A : Type) (x : A) (l : list A), In x l -> l <> [ ]
A:Type
x:A
l:list A
H:In x l

l <> [ ]
A:Type
x:A
l:list A
H:In x l

l = [ ] -> False
A:Type
x:A
l:list A
H:In x l
Hl:l = [ ]

False
A:Type
x:A
H:In x [ ]
Hl:[ ] = [ ]

False
A:Type
x, x0:A
l:list A
H:In x (x0 :: l)
Hl:x0 :: l = [ ]
False
A:Type
x:A
H:In x [ ]
Hl:[ ] = [ ]

False
A:Type
x:A
H:False
Hl:[ ] = [ ]

False
destruct H.
A:Type
x, x0:A
l:list A
H:In x (x0 :: l)
Hl:x0 :: l = [ ]

False
discriminate Hl. Qed.
What makes this interesting is that one quantified variable (x) does not appear in the conclusion (l []).
We can use this lemma to prove the special case where x is 42. Naively, the tactic apply in_not_nil will fail because it cannot infer the value of x. There are several ways to work around that...

forall l : list nat, In 42 l -> l <> [ ]

forall l : list nat, In 42 l -> l <> [ ]
(* WORKED IN CLASS *)
l:list nat
H:In 42 l

l <> [ ]
Unable to find an instance for the variable x.
Abort. (* [apply ... with ...] *)

forall l : list nat, In 42 l -> l <> [ ]

forall l : list nat, In 42 l -> l <> [ ]
l:list nat
H:In 42 l

l <> [ ]
l:list nat
H:In 42 l

In 42 l
apply H. Qed. (* [apply ... in ...] *)

forall l : list nat, In 42 l -> l <> [ ]

forall l : list nat, In 42 l -> l <> [ ]
l:list nat
H:In 42 l

l <> [ ]
l:list nat
H:l <> [ ]

l <> [ ]
apply H. Qed. (* Explicitly apply the lemma to the value for [x]. *)

forall l : list nat, In 42 l -> l <> [ ]

forall l : list nat, In 42 l -> l <> [ ]
l:list nat
H:In 42 l

l <> [ ]
l:list nat
H:In 42 l

In 42 l
apply H. Qed. (* Explicitly apply the lemma to a hypothesis. *)

forall l : list nat, In 42 l -> l <> [ ]

forall l : list nat, In 42 l -> l <> [ ]
l:list nat
H:In 42 l

l <> [ ]
apply (in_not_nil _ _ _ H). Qed.
You can "use theorems as functions" in this way with almost all tactics that take a theorem name as an argument. Note also that theorem application uses the same inference mechanisms as function application; thus, it is possible, for example, to supply wildcards as arguments to be inferred, or to declare some hypotheses to a theorem as implicit by default. These features are illustrated in the proof below. (The details of how this proof works are not critical -- the goal here is just to illustrate what can be done.)

forall (n : nat) (ns : list nat), In n (map (fun m : nat => m * 0) ns) -> n = 0

forall (n : nat) (ns : list nat), In n (map (fun m : nat => m * 0) ns) -> n = 0
n:nat
ns:list nat
H:In n (map (fun m : nat => m * 0) ns)

n = 0
n:nat
ns:list nat
H:In n (map (fun m0 : nat => m0 * 0) ns)
m:nat
Hm:m * 0 = n

n = 0
n:nat
ns:list nat
H:In n (map (fun m0 : nat => m0 * 0) ns)
m:nat
Hm:0 = n

n = 0
n:nat
ns:list nat
H:In n (map (fun m0 : nat => m0 * 0) ns)
m:nat
Hm:0 = n

0 = 0
reflexivity. Qed.
We will see many more examples in later chapters.
(* ################################################################# *)

Coq vs. Set Theory

Coq's logical core, the Calculus of Inductive Constructions, differs in some important ways from other formal systems that are used by mathematicians to write down precise and rigorous proofs. For example, in the most popular foundation for paper-and-pencil mathematics, Zermelo-Fraenkel Set Theory (ZFC), a mathematical object can potentially be a member of many different sets; a term in Coq's logic, on the other hand, is a member of at most one type. This difference often leads to slightly different ways of capturing informal mathematical concepts, but these are, by and large, about equally natural and easy to work with. For example, instead of saying that a natural number n belongs to the set of even numbers, we would say in Coq that even n holds, where even : nat Prop is a property describing even numbers.
However, there are some cases where translating standard mathematical reasoning into Coq can be cumbersome or sometimes even impossible, unless we enrich the core logic with additional axioms.
We conclude this chapter with a brief discussion of some of the most significant differences between the two worlds.
(* ================================================================= *)

Functional Extensionality

The equality assertions that we have seen so far mostly have concerned elements of inductive types (nat, bool, etc.). But since Coq's equality operator is polymorphic, these are not the only possibilities -- in particular, we can write propositions claiming that two functions are equal to each other:

(fun x : nat => 3 + x) = (fun x : nat => Nat.pred 4 + x)

(fun x : nat => 3 + x) = (fun x : nat => Nat.pred 4 + x)
reflexivity. Qed.
In common mathematical practice, two functions f and g are considered equal if they produce the same outputs:
(forall x, f x = g x) -> f = g
This is known as the principle of functional extensionality.
Informally speaking, an "extensional property" is one that pertains to an object's observable behavior. Thus, functional extensionality simply means that a function's identity is completely determined by what we can observe from it -- i.e., in Coq terms, the results we obtain after applying it.
Functional extensionality is not part of Coq's built-in logic. This means that some "reasonable" propositions are not provable.

(fun x : nat => x + 1) = (fun x : nat => 1 + x)

(fun x : nat => x + 1) = (fun x : nat => 1 + x)
(* Stuck *) Abort.
However, we can add functional extensionality to Coq's core using the Axiom command.
Axiom functional_extensionality : forall {X Y: Type}
                                    {f g : X -> Y},
  (forall (x:X), f x = g x) -> f = g.
Using Axiom has the same effect as stating a theorem and skipping its proof using Admitted, but it alerts the reader that this isn't just something we're going to come back and fill in later!
We can now invoke functional extensionality in proofs:

(fun x : nat => x + 1) = (fun x : nat => 1 + x)

(fun x : nat => x + 1) = (fun x : nat => 1 + x)

forall x : nat, x + 1 = 1 + x
x:nat

x + 1 = 1 + x
apply plus_comm. Qed.
Naturally, we must be careful when adding new axioms into Coq's logic, as they may render it inconsistent -- that is, they may make it possible to prove every proposition, including False, 2+2=5, etc.!
Unfortunately, there is no simple way of telling whether an axiom is safe to add: hard work by highly-trained trained experts is generally required to establish the consistency of any particular combination of axioms.
Fortunately, it is known that adding functional extensionality, in particular, is consistent.
To check whether a particular proof relies on any additional axioms, use the Print Assumptions command.
Axioms: plus_comm : forall n m : nat, n + m = m + n functional_extensionality : forall (X Y : Type) (f g : X -> Y), (forall x : X, f x = g x) -> f = g

Exercise: 4 stars, standard (tr_rev_correct)

One problem with the definition of the list-reversing function rev that we have is that it performs a call to app on each step; running app takes time asymptotically linear in the size of the list, which means that rev has quadratic running time. We can improve this with the following definition:
Fixpoint rev_append {X} (l1 l2 : list X) : list X :=
  match l1 with
  | [] => l2
  | x :: l1' => rev_append l1' (x :: l2)
  end.

Definition tr_rev {X} (l : list X) : list X :=
  rev_append l [].
This version is said to be tail-recursive, because the recursive call to the function is the last operation that needs to be performed (i.e., we don't have to execute ++ after the recursive call); a decent compiler will generate very efficient code in this case. Prove that the two definitions are indeed equivalent.

forall X : Type, tr_rev = rev
(* FILL IN HERE *) Admitted.
(* ================================================================= *)

Propositions and Booleans

We've seen two different ways of expressing logical claims in Coq: with booleans (of type bool), and with propositions (of type Prop).
For instance, to claim that a number n is even, we can say either...
... that evenb n evaluates to true...

evenb 42 = true

evenb 42 = true
reflexivity. Qed.
... or that there exists some k such that n = double k.

exists k : nat, 42 = double k

exists k : nat, 42 = double k

42 = double 21
reflexivity. Qed.
Of course, it would be pretty strange if these two characterizations of evenness did not describe the same set of natural numbers! Fortunately, we can prove that they do...
We first need two helper lemmas.

forall k : nat, evenb (double k) = true

forall k : nat, evenb (double k) = true
k:nat

evenb (double k) = true

evenb (double 0) = true
k':nat
IHk':evenb (double k') = true
evenb (double (S k')) = true

evenb (double 0) = true
reflexivity.
k':nat
IHk':evenb (double k') = true

evenb (double (S k')) = true
k':nat
IHk':evenb (double k') = true

evenb (double k') = true
apply IHk'. Qed.

Exercise: 3 stars, standard (evenb_double_conv)


forall n : nat, exists k : nat, n = (if evenb n then double k else S (double k))

forall n : nat, exists k : nat, n = (if evenb n then double k else S (double k))
(* Hint: Use the [evenb_S] lemma from [Induction.v]. *) (* FILL IN HERE *) Admitted.

forall n : nat, evenb n = true <-> (exists k : nat, n = double k)

forall n : nat, evenb n = true <-> (exists k : nat, n = double k)
n:nat

evenb n = true <-> (exists k : nat, n = double k)
n:nat

evenb n = true -> exists k : nat, n = double k
n:nat
(exists k : nat, n = double k) -> evenb n = true
n:nat

evenb n = true -> exists k : nat, n = double k
n:nat
H:evenb n = true

exists k : nat, n = double k
n:nat
H:evenb n = true
k:nat
Hk:n = (if evenb n then double k else S (double k))

exists k0 : nat, n = double k0
n:nat
H:evenb n = true
k:nat
Hk:n = (if evenb n then double k else S (double k))

exists k0 : nat, (if evenb n then double k else S (double k)) = double k0
n:nat
H:evenb n = true
k:nat
Hk:n = (if evenb n then double k else S (double k))

exists k0 : nat, double k = double k0
n:nat
H:evenb n = true
k:nat
Hk:n = (if evenb n then double k else S (double k))

double k = double k
reflexivity.
n:nat

(exists k : nat, n = double k) -> evenb n = true
n, k:nat
Hk:n = double k

evenb n = true
n, k:nat
Hk:n = double k

evenb (double k) = true
apply evenb_double. Qed.
In view of this theorem, we say that the boolean computation evenb n is reflected in the truth of the proposition k, n = double k.
Similarly, to state that two numbers n and m are equal, we can say either Again, these two notions are equivalent.

forall n1 n2 : nat, (n1 =? n2) = true <-> n1 = n2

forall n1 n2 : nat, (n1 =? n2) = true <-> n1 = n2
n1, n2:nat

(n1 =? n2) = true <-> n1 = n2
n1, n2:nat

(n1 =? n2) = true -> n1 = n2
n1, n2:nat
n1 = n2 -> (n1 =? n2) = true
n1, n2:nat

(n1 =? n2) = true -> n1 = n2
apply eqb_true.
n1, n2:nat

n1 = n2 -> (n1 =? n2) = true
n1, n2:nat
H:n1 = n2

(n1 =? n2) = true
n1, n2:nat
H:n1 = n2

(n2 =? n2) = true
n1, n2:nat
H:n1 = n2

true = true
reflexivity. Qed.
However, even when the boolean and propositional formulations of a claim are equivalent from a purely logical perspective, they may not be equivalent operationally.
In the case of even numbers above, when proving the backwards direction of even_bool_prop (i.e., evenb_double, going from the propositional to the boolean claim), we used a simple induction on k. On the other hand, the converse (the evenb_double_conv exercise) required a clever generalization, since we can't directly prove (evenb n = true) ( k, n = double k).
For these examples, the propositional claims are more useful than their boolean counterparts, but this is not always the case. For instance, we cannot test whether a general proposition is true or not in a function definition; as a consequence, the following code fragment is rejected:
The term "n = 2" has type "Prop" which is not a (co-)inductive type.
Coq complains that n = 2 has type Prop, while it expects an element of bool (or some other inductive type with two elements). The reason for this error message has to do with the computational nature of Coq's core language, which is designed so that every function that it can express is computable and total. One reason for this is to allow the extraction of executable programs from Coq developments. As a consequence, Prop in Coq does not have a universal case analysis operation telling whether any given proposition is true or false, since such an operation would allow us to write non-computable functions.
Although general non-computable properties cannot be phrased as boolean computations, it is worth noting that even many computable properties are easier to express using Prop than bool, since recursive function definitions are subject to significant restrictions in Coq. For instance, the next chapter shows how to define the property that a regular expression matches a given string using Prop. Doing the same with bool would amount to writing a regular expression matcher, which would be more complicated, harder to understand, and harder to reason about.
Conversely, an important side benefit of stating facts using booleans is enabling some proof automation through computation with Coq terms, a technique known as proof by reflection. Consider the following statement:

exists k : nat, 1000 = double k
The most direct proof of this fact is to give the value of k explicitly.

exists k : nat, 1000 = double k

1000 = double 500
reflexivity. Qed.
On the other hand, the proof of the corresponding boolean statement is even simpler:

evenb 1000 = true

evenb 1000 = true
reflexivity. Qed.
What is interesting is that, since the two notions are equivalent, we can use the boolean formulation to prove the other one without mentioning the value 500 explicitly:

exists k : nat, 1000 = double k

exists k : nat, 1000 = double k

evenb 1000 = true
reflexivity. Qed.
Although we haven't gained much in terms of proof-script size in this case, larger proofs can often be made considerably simpler by the use of reflection. As an extreme example, the Coq proof of the famous 4-color theorem uses reflection to reduce the analysis of hundreds of different cases to a boolean computation.
Another notable difference is that the negation of a "boolean fact" is straightforward to state and prove: simply flip the expected boolean result.

evenb 1001 = false

evenb 1001 = false
(* WORKED IN CLASS *) reflexivity. Qed.
In contrast, propositional negation may be more difficult to grasp.

~ (exists k : nat, 1001 = double k)

~ (exists k : nat, 1001 = double k)
(* WORKED IN CLASS *)

evenb 1001 <> true

evenb 1001 = true -> False

false = true -> False
H:false = true

False
discriminate H. Qed.
Equality provides a complementary example: knowing that n =? m = true is generally of little direct help in the middle of a proof involving n and m; however, if we convert the statement to the equivalent form n = m, we can rewrite with it.

forall n m p : nat, (n =? m) = true -> (n + p =? m + p) = true

forall n m p : nat, (n =? m) = true -> (n + p =? m + p) = true
(* WORKED IN CLASS *)
n, m, p:nat
H:(n =? m) = true

(n + p =? m + p) = true
n, m, p:nat
H:n = m

(n + p =? m + p) = true
n, m, p:nat
H:n = m

(m + p =? m + p) = true
n, m, p:nat
H:n = m

m + p = m + p
reflexivity. Qed.
We won't cover reflection in much detail, but it serves as a good example showing the complementary strengths of booleans and general propositions.

Exercise: 2 stars, standard (logical_connectives)

The following lemmas relate the propositional connectives studied in this chapter to the corresponding boolean operations.

forall b1 b2 : bool, b1 && b2 = true <-> b1 = true /\ b2 = true

forall b1 b2 : bool, b1 && b2 = true <-> b1 = true /\ b2 = true
(* FILL IN HERE *) Admitted.

forall b1 b2 : bool, b1 || b2 = true <-> b1 = true \/ b2 = true

forall b1 b2 : bool, b1 || b2 = true <-> b1 = true \/ b2 = true
(* FILL IN HERE *) Admitted.

Exercise: 1 star, standard (eqb_neq)

The following theorem is an alternate "negative" formulation of eqb_eq that is more convenient in certain situations (we'll see examples in later chapters).

forall x y : nat, (x =? y) = false <-> x <> y

forall x y : nat, (x =? y) = false <-> x <> y
(* FILL IN HERE *) Admitted.

Exercise: 3 stars, standard (eqb_list)

Given a boolean operator eqb for testing equality of elements of some type A, we can define a function eqb_list for testing equality of lists with elements in A. Complete the definition of the eqb_list function below. To make sure that your definition is correct, prove the lemma eqb_list_true_iff.
eqb_list:forall A0 : Type, (A0 -> A0 -> bool) -> list A0 -> list A0 -> bool
A:Type
eqb:A -> A -> bool
l1, l2:list A

bool
Admitted.

forall (A : Type) (eqb : A -> A -> bool), (forall a1 a2 : A, eqb a1 a2 = true <-> a1 = a2) -> forall l1 l2 : list A, eqb_list eqb l1 l2 = true <-> l1 = l2

forall (A : Type) (eqb : A -> A -> bool), (forall a1 a2 : A, eqb a1 a2 = true <-> a1 = a2) -> forall l1 l2 : list A, eqb_list eqb l1 l2 = true <-> l1 = l2
(* FILL IN HERE *) Admitted.

Exercise: 2 stars, standard, recommended (All_forallb)

Recall the function forallb, from the exercise forall_exists_challenge in chapter Tactics:
Fixpoint forallb {X : Type} (test : X -> bool) (l : list X) : bool :=
  match l with
  | [] => true
  | x :: l' => andb (test x) (forallb test l')
  end.
Prove the theorem below, which relates forallb to the All property of the above exercise.

forall (X : Type) (test : X -> bool) (l : list X), forallb test l = true <-> All (fun x : X => test x = true) l

forall (X : Type) (test : X -> bool) (l : list X), forallb test l = true <-> All (fun x : X => test x = true) l
(* FILL IN HERE *) Admitted.
Are there any important properties of the function forallb which are not captured by this specification?
(* FILL IN HERE 

    [] *)

(* ================================================================= *)

Classical vs. Constructive Logic

We have seen that it is not possible to test whether or not a proposition P holds while defining a Coq function. You may be surprised to learn that a similar restriction applies to proofs! In other words, the following intuitive reasoning principle is not derivable in Coq:
Definition excluded_middle := forall P : Prop,
  P \/ ~ P.
To understand operationally why this is the case, recall that, to prove a statement of the form P Q, we use the left and right tactics, which effectively require knowing which side of the disjunction holds. But the universally quantified P in excluded_middle is an arbitrary proposition, which we know nothing about. We don't have enough information to choose which of left or right to apply, just as Coq doesn't have enough information to mechanically decide whether P holds or not inside a function.
However, if we happen to know that P is reflected in some boolean term b, then knowing whether it holds or not is trivial: we just have to check the value of b.

forall (P : Prop) (b : bool), P <-> b = true -> P \/ ~ P

forall (P : Prop) (b : bool), P <-> b = true -> P \/ ~ P
P:Prop
H:P <-> true = true

P \/ ~ P
P:Prop
H:P <-> false = true
P \/ ~ P
P:Prop
H:P <-> true = true

P \/ ~ P
P:Prop
H:P <-> true = true

P
P:Prop
H:P <-> true = true

true = true
reflexivity.
P:Prop
H:P <-> false = true

P \/ ~ P
P:Prop
H:P <-> false = true

~ P
P:Prop
H:P <-> false = true

false <> true
P:Prop
H:P <-> false = true
contra:false = true

False
discriminate contra. Qed.
In particular, the excluded middle is valid for equations n = m, between natural numbers n and m.

forall n m : nat, n = m \/ n <> m

forall n m : nat, n = m \/ n <> m
n, m:nat

n = m \/ n <> m
n, m:nat

n = m <-> (n =? m) = true
n, m:nat

(n =? m) = true <-> n = m
apply eqb_eq. Qed.
It may seem strange that the general excluded middle is not available by default in Coq; after all, any given claim must be either true or false. Nonetheless, there is an advantage in not assuming the excluded middle: statements in Coq can make stronger claims than the analogous statements in standard mathematics. Notably, if there is a Coq proof of x, P x, it is possible to explicitly exhibit a value of x for which we can prove P x -- in other words, every proof of existence is necessarily constructive.
Logics like Coq's, which do not assume the excluded middle, are referred to as constructive logics.
More conventional logical systems such as ZFC, in which the excluded middle does hold for arbitrary propositions, are referred to as classical.
The following example illustrates why assuming the excluded middle may lead to non-constructive proofs:
Claim: There exist irrational numbers a and b such that a ^ b is rational.
Proof: It is not difficult to show that sqrt 2 is irrational. If sqrt 2 ^ sqrt 2 is rational, it suffices to take a = b = sqrt 2 and we are done. Otherwise, sqrt 2 ^ sqrt 2 is irrational. In this case, we can take a = sqrt 2 ^ sqrt 2 and b = sqrt 2, since a ^ b = sqrt 2 ^ (sqrt 2 × sqrt 2) = sqrt 2 ^ 2 = 2.
Do you see what happened here? We used the excluded middle to consider separately the cases where sqrt 2 ^ sqrt 2 is rational and where it is not, without knowing which one actually holds! Because of that, we wind up knowing that such a and b exist but we cannot determine what their actual values are (at least, using this line of argument).
As useful as constructive logic is, it does have its limitations: There are many statements that can easily be proven in classical logic but that have much more complicated constructive proofs, and there are some that are known to have no constructive proof at all! Fortunately, like functional extensionality, the excluded middle is known to be compatible with Coq's logic, allowing us to add it safely as an axiom. However, we will not need to do so in this book: the results that we cover can be developed entirely within constructive logic at negligible extra cost.
It takes some practice to understand which proof techniques must be avoided in constructive reasoning, but arguments by contradiction, in particular, are infamous for leading to non-constructive proofs. Here's a typical example: suppose that we want to show that there exists x with some property P, i.e., such that P x. We start by assuming that our conclusion is false; that is, ¬ x, P x. From this premise, it is not hard to derive x, ¬ P x. If we manage to show that this intermediate fact results in a contradiction, we arrive at an existence proof without ever exhibiting a value of x for which P x holds!
The technical flaw here, from a constructive standpoint, is that we claimed to prove x, P x using a proof of ¬ ¬ ( x, P x). Allowing ourselves to remove double negations from arbitrary statements is equivalent to assuming the excluded middle, as shown in one of the exercises below. Thus, this line of reasoning cannot be encoded in Coq without assuming additional axioms.

Exercise: 3 stars, standard (excluded_middle_irrefutable)

Proving the consistency of Coq with the general excluded middle axiom requires complicated reasoning that cannot be carried out within Coq itself. However, the following theorem implies that it is always safe to assume a decidability axiom (i.e., an instance of excluded middle) for any particular Prop P. Why? Because we cannot prove the negation of such an axiom. If we could, we would have both ¬ (P ¬P) and ¬ ¬ (P ¬P) (since P implies ¬ ¬ P, by the exercise below), which would be a contradiction. But since we can't, it is safe to add P ¬P as an axiom.

forall P : Prop, ~ ~ (P \/ ~ P)

forall P : Prop, ~ ~ (P \/ ~ P)
(* FILL IN HERE *) Admitted.

Exercise: 3 stars, advanced (not_exists_dist)

It is a theorem of classical logic that the following two assertions are equivalent:
~ (exists x, ~ P x) forall x, P x
The dist_not_exists theorem above proves one side of this equivalence. Interestingly, the other direction cannot be proved in constructive logic. Your job is to show that it is implied by the excluded middle.

excluded_middle -> forall (X : Type) (P : X -> Prop), ~ (exists x : X, ~ P x) -> forall x : X, P x

excluded_middle -> forall (X : Type) (P : X -> Prop), ~ (exists x : X, ~ P x) -> forall x : X, P x
(* FILL IN HERE *) Admitted.

Exercise: 5 stars, standard, optional (classical_axioms)

For those who like a challenge, here is an exercise taken from the Coq'Art book by Bertot and Casteran (p. 123). Each of the following four statements, together with excluded_middle, can be considered as characterizing classical logic. We can't prove any of them in Coq, but we can consistently add any one of them as an axiom if we wish to work in classical logic.
Prove that all five propositions (these four plus excluded_middle) are equivalent.
Definition peirce := forall P Q: Prop,
  ((P->Q)->P)->P.

Definition double_negation_elimination := forall P:Prop,
  ~~P -> P.

Definition de_morgan_not_and_not := forall P Q:Prop,
  ~(~P /\ ~Q) -> P\/Q.

Definition implies_to_or := forall P Q:Prop,
  (P->Q) -> (~P\/Q).

(* FILL IN HERE 

    [] *)

(* Wed Jan 9 12:02:45 EST 2019 *)