(*|
==========================
Coq cheatsheet and gotchas
==========================
.. coq:: none
|*)
Require Import Arith Lia.
(*|
Coq resources
-------------
- For help on standard Coq tactics, consult `Coq's reference manual `__, starting from the `indices `__. The manual can be overwhelming, so it's best used for looking up fine details.
Useful commands
---------------
Coq comes with many predefined types, functions, and theorems (“objects”). The most important commands to help you discover them are `Check`, `About`, `Print`, `Search`, and `Compute`. Try the following examples:
`Check` gives the type of any term, even with holes:
.. coq:: unfold
|*)
Check (1 + _).
Check (fun b => match b with true => 0 | false => 1 end).
(*|
`About` gives general information about an object:
.. coq:: unfold
|*)
About bool.
About nat.
(*|
`Print` displays the definition of an object:
.. coq:: unfold
|*)
Print bool.
Print Nat.add.
(*|
`Search` finds objects. Its syntax is very flexible:
- Find functions of type `nat -> nat -> bool`.
.. coq::
|*)
Search (nat -> nat -> bool). (* .unfold *)
(*|
- Find theorems about `||` in module `Nat`.
.. coq::
|*)
Search "||" inside Nat. (* .unfold *)
(*|
Find theorems about subtraction and equality whose name contains `_distr`.
|*)
Search eq "-" "_distr". (* .unfold *)
(*|
Search for a lemma proving the symmetry of `=`.
|*)
Search (?x = ?y -> ?y = ?x). (* .unfold *)
(*|
If you are puzzled by a notation, the `Locate` command can help:
|*)
Locate "*". (* .unfold *)
(*|
To evaluate an expression, use `Compute`:
|*)
Compute (2 * 3, 4 + 4, 0 - 2 + 2, pred (S (S (S 0)))). (* .unfold *)
(*|
Syntax recap
------------
To define a function inline, use `fun`:
|*)
Check (fun x => x + 1). (* .unfold *)
Check (fun x: bool => xorb x x). (* .unfold *)
(*|
To perform a case analysis on a value, use `match`:
|*)
Check (fun b (x y: nat) =>
match b with
| true => x
| false => y
end). (* .unfold *)
Check (fun (n: nat) =>
match n with
| 0 => 1
| S n => n
end). (* .unfold *)
(*|
In Coq, `if` is just short for `match`:
|*)
Check (fun (b: bool) (x y: nat) =>
if b then x else y). (* .unfold *)
(*|
To define a global object, use `Definition` or `Lemma` (`Theorem` is an alias of `Lemma`):
|*)
Definition choose (b: bool) (x y: nat) :=
if b then x else y.
Compute (choose true 6 512). (* .unfold *)
Lemma plus_commutes :
forall x, x = x + 0 + 0.
Proof.
intros.
Search (_ + 0).
rewrite Nat.add_0_r.
rewrite Nat.add_0_r.
reflexivity.
Qed.
(*|
Recursive functions use the keyword `Fixpoint`:
|*)
Fixpoint do_n_times
(ntimes: nat) (step: nat -> nat) (start_from: nat) :=
match ntimes with
| 0 => start_from
| S ntimes' => step (do_n_times ntimes' step start_from)
end.
Compute (6, do_n_times 12 (fun x => x + 65) 42). (* .unfold *)
(*|
You can use bullets or braces to structure your proofs:
|*)
Lemma both_zero:
forall x y z: nat, x + y + z = 0 -> x = 0 /\ y = 0 /\ z = 0.
Proof.
destruct x.
- destruct y.
{ intros z Heq; simpl in *.
rewrite Heq; split.
- reflexivity.
- split; reflexivity. }
{ intros z Heq.
simpl in *.
congruence. }
- intros y z Heq.
simpl in *.
congruence.
Qed.
(*|
A few gotchas
-------------
Natural numbers saturate at 0:
|*)
Compute (3 - 5 + 3). (* .unfold *)
(*|
The order in which you perform induction on variables matters: if `x` comes before `y` and you do induction on `y`, your induction hypothesis will not be general enough.
|*)
Lemma add_comm:
forall x y: nat, x + y = y + x.
Proof.
induction y.
- induction x.
+ reflexivity.
+ simpl in *.
rewrite IHx.
reflexivity.
- simpl. (* .unfold *)
(*|
Here, `IHy` is valid only for one specific `y`.
|*)
Abort.
Lemma add_comm:
forall x y: nat, x + y = y + x.
Proof.
induction x.
- induction y.
+ reflexivity.
+ simpl in *.
rewrite <- IHy.
reflexivity.
- intros; simpl. (* .unfold *)
(*|
Here, `IHx` starts with `forall y`.
|*)
Abort.
(*|
Here's an example where this subtlety matters:
|*)
Fixpoint factorial (n: nat) :=
match n with
| O => 1
| S n' => n * factorial n'
end.
Fixpoint factorial_acc (n: nat) (acc: nat) :=
match n with
| O => acc
| S n' => factorial_acc n' (n * acc)
end.
(*|
First attempt, but our lemma is too weak:
|*)
Lemma factorial_acc_correct:
forall n, factorial n = factorial_acc n 1.
Proof.
induction n.
- simpl.
reflexivity.
- simpl.
Search (_ * 1).
rewrite Nat.mul_1_r. (* .unfold *)
(*|
Stuck! We have no way to simplify `factorial_acc n (S n)`.
|*)
Abort.
(*|
Second attempt: a generalized lemma, but we put the `acc` first, so induction will not generalize it.
|*)
Lemma factorial_acc_correct:
forall acc n, factorial n * acc = factorial_acc n acc.
Proof.
induction n.
- simpl.
rewrite Nat.add_0_r.
reflexivity.
- simpl.
Fail rewrite <- IHn. (* .unfold *)
(*|
Stuck! IHn is too weak.
|*)
Abort.
(*|
Third time's the charm! Note how we ordered `n` and `acc`.
|*)
Lemma factorial_acc_correct:
forall n acc, factorial n * acc = factorial_acc n acc.
Proof.
induction n.
- intros.
simpl.
rewrite Nat.add_0_r.
reflexivity.
- intros.
simpl. (* .unfold *)
(*|
IHn is strong enough now!
|*)
rewrite <- IHn.
lia.
Qed.