Coq3110An Introduction to Coq for CS 3110
This material is based on an online textbook by Benjamin Pierce
et al. titled "Software Foundations":
http://www.cis.upenn.edu/~bcpierce/sf/
Inductive Types
- Days of the week
- Boolean
- Natural numbers
Inductive day : Type :=
| monday : day
| tuesday : day
| wednesday : day
| thursday : day
| friday : day
| saturday : day
| sunday : day.
A function 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.
Check checks the type of an expression.
Check next_weekday.
(* ===> next_weekday : day -> day *)
Computation
Eval compute in (next_weekday friday).
(* ==> monday : day *)
Eval compute in (next_weekday (next_weekday saturday)).
(* ==> tuesday : day *)
Example test_next_weekday:
(next_weekday (next_weekday saturday)) = tuesday.
A proof script giving evidence for the claim:
Proof. reflexivity. Qed.
reflexivity is a tactic that is built into Coq.
In essence, it applies Coq's computational rules
(i.e., dynamic semantics) to both side of the = sign.
Then it compares to see whether both sides reduced
to the same value. If so, that counts as evidence
that the equality holds.
Extraction into OCaml
Extraction day.
(* type day =
| Monday
... *)
Extraction next_weekday.
(* let next_weekday = function
| Monday -> Tuesday
... *)
Inductive bool : Type :=
| true : bool
| false : bool.
Booleans are also provided in Coq's standard library, but
we are defining from scratch, just to see how it's done.
We can code these up with using any built-in boolean operators.
Functions on booleans
Definition negb (b:bool) : bool :=
match b with
| true ⇒ false
| false ⇒ true
end.
Coq has an if expression that we could use
instead of pattern matching.
Definition andb (b1:bool) (b2:bool) : bool :=
if b1 then b2 else false.
Definition orb (b1:bool) (b2:bool) : bool :=
if b1 then true else b2.
Example test_orb1: (orb true false) = true.
Proof. reflexivity. Qed.
Example test_orb2: (orb false false) = false.
Proof. reflexivity. Qed.
Example test_orb3: (orb false true) = true.
Proof. reflexivity. Qed.
Example test_orb4: (orb true true) = true.
Proof. reflexivity. Qed.
The natural numbers in unary representation:
Inductive nat : Type :=
| O : nat
| S : nat → nat.
The clauses of this definition can be read:
Add one:
- O is a natural number (note that this is the letter "O," not the numeral "0").
- S is a "constructor" that takes a natural number and yields another one — that is, if n is a natural number, then S n is too.
Two functions on numbers
Definition succ (n : nat) : nat :=
S n.
Subtract one:
(* requires: n >= 1 *)
Definition pred (n : nat) : nat :=
match n with
| O ⇒ O
| S n' ⇒ n'
end.
Syntactic sugar for numbers
Check (S (S (S (S O)))).
(* ===> 4 *)
Eval compute in (pred 4).
(* ===> 3 *)
Fixpoint evenb (n:nat) : bool :=
match n with
| O ⇒ true
| S O ⇒ false
| S (S n') ⇒ evenb n'
end.
We can define oddb in terms of evenb:
Definition oddb (n:nat) : bool :=
negb (evenb n).
Example test_oddb1: (oddb 1) = true.
Proof. reflexivity. Qed.
Example test_oddb2: (oddb 4) = false.
Proof. reflexivity. Qed.
Fixpoint plus (n : nat) (m : nat) : nat :=
match n with
| O ⇒ m
| S n' ⇒ S (plus n' m)
end.
When two arguments have the same type, we can list
them together. (n m : nat) means the same
as (n : nat) (m : nat).
Fixpoint mult (n m : nat) : nat :=
match n with
| O ⇒ O
| S n' ⇒ plus m (mult n' m)
end.
Fixpoint minus (n m:nat) : nat :=
match n, m with
| O , _ ⇒ O
| S _ , O ⇒ n
| S n', S m' ⇒ minus n' m'
end.
Fixpoint factorial (n:nat) : nat :=
match n with
| O ⇒ 1
| S n' ⇒ mult n (factorial n')
end.
Example test_factorial1: (factorial 3) = 6.
Proof. reflexivity. Qed.
Example test_factorial2: (factorial 5) = (mult 10 12).
Proof. reflexivity. Qed.
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).
Theorem plus_O_n : ∀ n : nat, 0 + n = n.
Proof. reflexivity. Qed.
Logic
- Inductive definitions
- ∀ (universal quantification)
- → (implication)
- that's it!
Propositions
Check (3 = 3).
(* ===> Prop *)
Here is an example of an unprovable proposition:
Check (∀ (n:nat), n = 2).
(* ===> Prop *)
Values of type Prop
- true and false inhabit bool.
- 0, 1, ... inhabit nat.
- what inhabits Prop?
- e.g., 0×3 = 0 inhabits Prop.
- what inhabits the type 0×3 = 0?
Proofs
Lemma silly : 0 × 3 = 0.
Proof. reflexivity. Qed.
Print silly.
(* ===> silly = eq_refl : 0 * 3 = 0 *)
(Here, the eq_refl proof object provides evidence for the equality.
We'll come back to how it does that...)
We could even have written the proof object ourselves:
Constructing proof objects
Definition silly' : 0 × 3 = 0 :=
eq_refl.
Print silly'.
Print silly.
(* ===> silly' = eq_refl : 0 * 3 = 0 *)
(* ===> silly = eq_refl : 0 * 3 = 0 *)
These mean the same thing:
- Lemma name : prop. Proof. tactics Qed.
- Definition name : prop := proof object .
Another Proof Object
Print plus_O_n.
(* ===> plus_O_n =
fun n : nat
=> eq_refl
: forall n : nat, 0 + n = n *)
This proof object is a function that takes in n and
returns a proof object eq_refl.
We read name = expr : type the same, whether the type is
Prop or Type.
Reading Coq
Print andb.
(* ===> andb =
fun b1 b2 : bool
=> if b1 then b2 else false
: bool -> bool -> bool *)
Print plus_O_n.
(* ===> plus_O_n =
fun n : nat
=> eq_refl
: forall n : nat, 0 + n = n *)
Coq unifies the notions of
Same connectives we saw in IQC:
These are the built-in connectives in Coq.
Coq treats both connectives the same way:
The introduction rules in IQC corresponds to the intros tactic in Coq.
The intros tactic moves one or more
quantifiers or hypotheses from the goal to a "context" of current
assumptions.
- types with formulas, and
- programs with proofs.
Coq's Connectives
- Implication ⇒
- Universal quantification ∀
- Conjunction ∧
- Disjunction ∨
- True and False
- Negation ¬
- Existential quantification ∃
- Equality =
Implies and forall
- The proof object for P → Q is a function that takes evidence for P as input and produces evidence for Q as output.
- The proof object for ∀ x, P is a function that takes x as input and produces evidence for P as output.
Implies and forall intro
Lemma imp_intro : (1 + 1) = 2 → 0 × 3 = 0.
Proof. intros H. reflexivity. Qed.
Print imp_intro.
(* ===> imp_intro =
fun _ : 1 + 1 = 2 => eq_refl
: 1 + 1 = 2 -> 0 * 3 = 0 *)
The proof object takes in evidence for 1+1=2, discards
that evidence, and returns evidence for 0×3=0.
Lemma forall_intro : ∀ (n:nat), n = n.
Proof. intros n. reflexivity. Qed.
Print forall_intro.
(* ===> forall_intro =
fun n : nat => eq_refl
: forall n : nat, n = n *)
The proof object takes in n, and returns
evidence for n=n.
The elimination rules for these connectives
in IQC correspond to the apply tactic in Coq.
Implies and forall elim
Lemma imp_elim : ∀ (P Q : Prop), P → (P→Q) → Q.
Proof.
intros P Q. intros HP HPimpQ.
apply HPimpQ. assumption.
Qed.
Print imp_elim.
(* ===> imp_elim = fun (P Q : Prop) (HP : P)
(HPimpQ : P -> Q)
=> HPimpQ HP
: forall P Q : Prop,
P -> (P -> Q) -> Q *)
Note:
- The assumption tactic corresponds to the IQC assumption rule.
- The proof object applies a function. Implication elimination is really function application!
Lemma forall_elim : (∀ (n:nat), n=0) → 1=0.
Proof. intros H. apply H with (n:=1). Qed.
Print forall_elim.
(* ===> forall_elim =
fun H : forall n : nat, n = 0 => H 1
: (forall n : nat, n = 0) -> 1 = 0 *)
Conjunction
Inductive and (P Q : Prop) : Prop :=
conj : P → Q → (and P Q).
Notation "P ∧ Q" := (and P Q) : type_scope.
Theorem and_intro :
(0 = 0) ∧ (4 = mult 2 2).
Proof.
apply conj. reflexivity. reflexivity. Qed.
Print and_intro.
(* ===> and_intro =
conj (0 = 0) (4 = 2 * 2)
eq_refl eq_refl
: 0 = 0 /\ 4 = 2 * 2 *)
And elim
Theorem and_elim : ∀ P Q : Prop,
P ∧ Q → P.
Proof.
intros P Q H.
inversion H as [HP HQ].
apply HP.
Qed.
Theorem and_commut : ∀ P Q : Prop,
P ∧ Q → Q ∧ P.
Proof.
intros P Q H.
inversion H as [HP HQ].
apply conj.
apply HQ.
apply HP.
Qed.
Writing tactics is the "assembly language" programming of Coq.
There are automated tactics that find proofs for us!
Theorem and_commut' : ∀ P Q : Prop,
P ∧ Q → Q ∧ P.
Proof. firstorder. Qed.
Inductive or (P Q : Prop) : Prop :=
| or_introl : P → or P Q
| or_intror : Q → or P Q.
Notation "P ∨ Q" := (or P Q) : type_scope.
Check or_introl.
(* ===> forall P Q : Prop, P -> P \/ Q *)
Check or_intror.
(* ===> forall P Q : Prop, Q -> P \/ Q *)
Theorem or_commut : ∀ P Q : Prop,
P ∨ Q → Q ∨ P.
Proof.
intros P Q H.
inversion H as [HP | HQ].
apply or_intror. apply HP.
apply or_introl. apply HQ.
Qed.
P ∨ Q → Q ∨ P.
Proof.
intros P Q H.
inversion H as [HP | HQ].
apply or_intror. apply HP.
apply or_introl. apply HQ.
Qed.
We could even write down an explicit proof object
for or_commut without using tactics to construct it:
Definition or_commut' : ∀ P Q,
P ∨ Q → Q ∨ P
:=
fun (P Q : Prop) (H : P ∨ Q) ⇒
match H with
| or_introl HP ⇒ or_intror Q P HP
| or_intror HQ ⇒ or_introl Q P HQ
end.
Or we could let Coq find the proof.
Theorem or_commut'' : ∀ P Q : Prop,
P ∨ Q → Q ∨ P.
Proof. firstorder. Qed.
Inductive True : Prop :=
I : True.
False has no constructors. Intuition:
False is a proposition for which there is no way
to give evidence.
Inductive False : Prop := .
Theorem True_is_provable : True.
Proof. apply I. Qed.
Once we have False as an assumption, the contradiction
tactic lets us conclude whatever we want. That corresponds
to IQC's false elim.
Theorem False_implies_nonsense :
False → 2 + 2 = 5.
Proof.
intros. contradiction.
Qed.
Theorem exfalso : ∀ (P:Prop),
False → P.
Proof.
intros. contradiction.
Qed.
Negation
Definition not (P:Prop) := P → False.
Notation "¬ x" := (not x) : type_scope.
Theorem not_False : ¬ False.
Proof. unfold not. apply exfalso. Qed.
Theorem contradiction_implies_anything :
∀ P Q : Prop, (P ∧ ¬P) → Q.
Proof. firstorder. Qed.
Inductive ex (X:Type) (P : X→Prop) : Prop :=
ex_intro : ∀ (witness:X), P witness → ex X P.
To give evidence we must actually name a witness
a specific value x — and
then give evidence for P x.
Notation "'exists' x , p" := (ex _ (fun x ⇒ p))
(at level 200, x ident, right associativity) : type_scope.
Notation "'exists' x : X , p" := (ex _ (fun x:X ⇒ p))
(at level 200, x ident, right associativity) : type_scope.
Example exists_example_1 :
∃ n, n + (n × n) = 6.
Proof.
apply ex_intro with (witness:=2).
reflexivity.
Qed.
Note that we explicitly give the witness.
We'll omit exists elimination, though it also is in Coq.
A proof we did in IQC
Theorem dist_exists_or : ∀ (X:Type) (P Q : X → Prop),
(∃ x, P x ∨ Q x) ↔ (∃ x, P x) ∨ (∃ x, Q x).
Proof.
firstorder.
Qed.
The equality relation is definable, not built-in
to the language.
Inductive eq {X:Type} : X → X → Prop :=
refl_equal : ∀ x, eq x x.
Notation "x = y" := (eq x y)
(at level 70, no associativity) : type_scope.
Lemma four: 2 + 2 = 1 + 3.
Proof.
apply refl_equal.
Qed.
reflexivity is essentially just apply refl_equal.
Excluded middle
Note that some theorems that are true in classical logic are not provable in Coq's (constructive) logic. E.g., let's look at how this proof gets stuck...Theorem excluded_middle : ∀ P : Prop,
P ∨ ¬P.
Proof.
intros P. unfold not.
(* We either have to go left or right... *)
left. (* But now what? We don't have evidence for P. *)
Undo.
right. intros HP. (* And now we don't have evidence for False. *)
Abort.
Proofs from IPC and IQC
Theorem lec19thm1 : ∀ (A B : Prop),
A → (B → A).
Proof. firstorder. Qed.
Theorem lec19thm2 : ∀ (A B : Prop),
A → (B → (A ∧ B)).
Proof. firstorder. Qed.
Theorem lec19thm3 : ∀ (A B : Prop),
(A ∨ B) → (B ∨ A).
Proof. firstorder. Qed.
Theorem rec18thm1 : ∀ (A B : Prop),
(A ∧ B) → A.
Proof. firstorder. Qed.
Theorem rec18thm2 : ∀ (A B : Prop),
(A ∧ B) → (B ∧ A).
Proof. firstorder. Qed.
Theorem rec18thm3 : ∀ (A B C : Prop),
(A → B) → ((B→C) → (A→C)).
Proof. firstorder. Qed.
Theorem rec18thm4 : ∀ (S C O : Prop),
((S→C) ∧ O ∧ ((O->~C) ∧ (C->~O))) → ¬S.
Proof. firstorder. Qed.
Theorem lec21thm1 : ∀ (Q R : Type → Prop),
(∀ x, R(x) ∧ Q(x)) → (∀ x, R(x)) ∧ (∀ x, Q(x)).
Proof. firstorder. Qed.
Theorem lec21thm2 : ∀ (Q R : Type → Prop),
(∃ x, Q(x) ∨ R(x)) → (∃ x, R(x)) ∨ (∃ x, Q(x)).
Proof. firstorder. Qed.
Theorem rec19thm1 : ∀ (A B : Prop),
((A → B) ∧ ¬B) → ¬A.
Proof. firstorder. Qed.
Theorem rec19thm2 : ∀ (A B : Prop),
(A → (B ∨ (A → B))) → (A → B).
Proof. firstorder. Qed.
Theorem rec19thm3 : ∀ (A B : Prop),
~((~A ∨ ¬B) ∧ (A ∧ B)).
Proof. firstorder. Qed.
Theorem rec19thm4 : ∀ (P Q : Type → Prop),
(∀ (x y : Type), (P(x) → Q(y))) ∧ (∃ x, P(x))
→ (∃ y, Q(y)).
Proof. firstorder. Qed.
Theorem rec19thm5 : ∀ (P Q : Type → Prop),
(∀ x, P(x)) → (∀ x, Q(x)) → (∀ x, (P(x) ↔ Q(x))).
Proof. firstorder. Qed.