1.8. Proving with Tactics
Writing proof terms by hand becomes impractical as proofs grow. A tactic is a command that transforms the proof state, the goal together with the hypotheses in scope, one step at a time. The keyword by enters tactic mode, and Lean elaborates the tactic sequence into a proof term, so a tactic proof and a term proof yield the same underlying object.
The tactic exact closes a goal with a term that proves it, which recovers the term-mode proof above.
example (P : Prop) (h : P) : P := P:Proph:P⊢ P
All goals completed! 🐙
Tactics reason in two directions. A backward step reduces the goal to simpler subgoals, and a forward step derives new hypotheses from those in scope. Each connective comes with tactics that introduce it, proving a goal of that shape, and tactics that eliminate it, using a hypothesis of that shape. We take the connectives in turn.
1.8.1. Implication
The tactic intro introduces an implication. To prove P → Q, assume P under a chosen name and prove Q.
example (P Q : Prop) (hQ : Q) : P → Q := P:PropQ:ProphQ:Q⊢ P → Q
P:PropQ:ProphQ:Q_hP:P⊢ Q
All goals completed! 🐙
The tactic exact closes the goal with a term that proves it. To use an implication, apply it to a proof of its antecedent. A hypothesis hPQ of type P → Q is a function from proofs of P to proofs of Q, so hPQ hP proves Q. This is the rule of modus ponens.
example (P Q : Prop) (hPQ : P → Q) (hP : P) : Q := hPQ hP
The tactic apply uses the same rule in the backward direction. Applying hPQ to the goal Q leaves P as the new goal.
example (P Q : Prop) (hPQ : P → Q) (hP : P) : Q := P:PropQ:ProphPQ:P → QhP:P⊢ Q
P:PropQ:ProphPQ:P → QhP:P⊢ P
All goals completed! 🐙
The tactic have reasons forward, adding a new hypothesis derived from the current ones, and show states the current goal explicitly. Both make proofs read like structured mathematical arguments.
example (P Q R : Prop) (hPQ : P → Q) (hQR : Q → R)
(hP : P) : R := P:PropQ:PropR:ProphPQ:P → QhQR:Q → RhP:P⊢ R
P:PropQ:PropR:ProphPQ:P → QhQR:Q → RhP:PhQ:Q⊢ R
P:PropQ:PropR:ProphPQ:P → QhQR:Q → RhP:PhQ:Q⊢ R
All goals completed! 🐙
1.8.2. Conjunction
To prove P ∧ Q, prove both parts. The tactic constructor splits the goal in two, and the bullet · delimits the proof of each.
example (P Q : Prop) (h : P ∧ Q) : Q ∧ P := P:PropQ:Proph:P ∧ Q⊢ Q ∧ P
P:PropQ:Proph:P ∧ Q⊢ QP:PropQ:Proph:P ∧ Q⊢ P
P:PropQ:Proph:P ∧ Q⊢ Q All goals completed! 🐙
P:PropQ:Proph:P ∧ Q⊢ P All goals completed! 🐙
To use a conjunction, project its parts with .left and .right. The anonymous constructor ⟨_, _⟩ builds the pair directly, giving a term-style proof.
example (P Q : Prop) (h : P ∧ Q) : Q ∧ P :=
⟨h.right, h.left⟩
1.8.3. Disjunction
To prove P ∨ Q, choose a side. Or.inl proves it from P, and Or.inr proves it from Q. To use a disjunction, reason by cases. The tactic cases produces one goal per disjunct.
example (P Q : Prop) (h : P ∨ Q) : Q ∨ P := P:PropQ:Proph:P ∨ Q⊢ Q ∨ P
cases h with
P:PropQ:ProphP:P⊢ Q ∨ P All goals completed! 🐙
P:PropQ:ProphQ:Q⊢ Q ∨ P All goals completed! 🐙
1.8.4. Negation
In Lean, ¬P is defined as P → False, where False is the proposition with no proof. A proof of ¬P is a function that turns any proof of P into a proof of False.
example (P : Prop) (hP : P) (hnP : ¬P) : False := hnP hP
Every tactic for implication therefore works for negation. The contrapositive direction below needs only intro and application.
theorem contrapositive (P Q : Prop) (hPQ : P → Q) :
¬Q → ¬P := P:PropQ:ProphPQ:P → Q⊢ ¬Q → ¬P
P:PropQ:ProphPQ:P → QhnQ:¬QhP:P⊢ False
All goals completed! 🐙
Introducing double negation is equally direct.
example (P : Prop) (hP : P) : ¬¬P := fun hnP => hnP hP
The second De Morgan law combines the rules seen so far. The tactic constructor also introduces a biconditional, splitting it into the two implications.
theorem deMorgan_or (P Q : Prop) : ¬(P ∨ Q) ↔ ¬P ∧ ¬Q := P:PropQ:Prop⊢ ¬(P ∨ Q) ↔ ¬P ∧ ¬Q
P:PropQ:Prop⊢ ¬(P ∨ Q) → ¬P ∧ ¬QP:PropQ:Prop⊢ ¬P ∧ ¬Q → ¬(P ∨ Q)
P:PropQ:Prop⊢ ¬(P ∨ Q) → ¬P ∧ ¬Q P:PropQ:Proph:¬(P ∨ Q)⊢ ¬P ∧ ¬Q
P:PropQ:Proph:¬(P ∨ Q)⊢ ¬PP:PropQ:Proph:¬(P ∨ Q)⊢ ¬Q
P:PropQ:Proph:¬(P ∨ Q)⊢ ¬P P:PropQ:Proph:¬(P ∨ Q)hP:P⊢ False
All goals completed! 🐙
P:PropQ:Proph:¬(P ∨ Q)⊢ ¬Q P:PropQ:Proph:¬(P ∨ Q)hQ:Q⊢ False
All goals completed! 🐙
P:PropQ:Prop⊢ ¬P ∧ ¬Q → ¬(P ∨ Q) P:PropQ:Proph:¬P ∧ ¬QhPQ:P ∨ Q⊢ False
cases hPQ with
P:PropQ:Proph:¬P ∧ ¬QhP:P⊢ False All goals completed! 🐙
P:PropQ:Proph:¬P ∧ ¬QhQ:Q⊢ False All goals completed! 🐙
1.8.5. Classical Reasoning
The rules used so far are constructive. Two principles of classical logic do not follow from them, the law of excluded middle and the elimination of double negation. Lean provides both in the Classical namespace.
#check Classical.em
Classical.byContradiction proves P from a proof that ¬P is impossible. With it, double negation elimination is one application away.
theorem not_not_elim (P : Prop) (h : ¬¬P) : P := P:Proph:¬¬P⊢ P
P:Proph:¬¬P⊢ ¬P → False
P:Proph:¬¬PhnP:¬P⊢ False
All goals completed! 🐙
The first De Morgan law requires classical reasoning. A case analysis on Classical.em P decides which disjunct to prove.
theorem deMorgan_and (P Q : Prop) : ¬(P ∧ Q) → ¬P ∨ ¬Q := P:PropQ:Prop⊢ ¬(P ∧ Q) → ¬P ∨ ¬Q
P:PropQ:Proph:¬(P ∧ Q)⊢ ¬P ∨ ¬Q
cases Classical.em P with
P:PropQ:Proph:¬(P ∧ Q)hP:P⊢ ¬P ∨ ¬Q All goals completed! 🐙
P:PropQ:Proph:¬(P ∧ Q)hnP:¬P⊢ ¬P ∨ ¬Q All goals completed! 🐙
1.8.6. Examples
The proofs below prove those same ten theorems again, now with tactics. Each can be read alongside the proof term of the previous section.
Example 1. Implication is reflexive.
example (P : Prop) : P → P := P:Prop⊢ P → P
P:Proph:P⊢ P
All goals completed! 🐙
Example 2. A conjunction entails each conjunct.
example (P Q : Prop) : P ∧ Q → P := P:PropQ:Prop⊢ P ∧ Q → P
P:PropQ:Proph:P ∧ Q⊢ P
All goals completed! 🐙
Example 3. A disjunct entails the disjunction.
example (P Q : Prop) : P → P ∨ Q := P:PropQ:Prop⊢ P → P ∨ Q
P:PropQ:Proph:P⊢ P ∨ Q
All goals completed! 🐙
Example 4. Anything follows from absurdity.
example (P : Prop) : False → P := P:Prop⊢ False → P
P:Proph:False⊢ P
All goals completed! 🐙
Example 5. Modus ponens, packaged as a single implication.
example (P Q : Prop) : (P → Q) ∧ P → Q := P:PropQ:Prop⊢ (P → Q) ∧ P → Q
P:PropQ:Proph:(P → Q) ∧ P⊢ Q
P:PropQ:Proph:(P → Q) ∧ P⊢ P
All goals completed! 🐙
Example 6. Disjunction commutes.
example (P Q : Prop) : P ∨ Q → Q ∨ P := P:PropQ:Prop⊢ P ∨ Q → Q ∨ P
P:PropQ:Proph:P ∨ Q⊢ Q ∨ P
cases h with
P:PropQ:ProphP:P⊢ Q ∨ P All goals completed! 🐙
P:PropQ:ProphQ:Q⊢ Q ∨ P All goals completed! 🐙
Example 7. Double negation introduction.
example (P : Prop) : P → ¬¬P := P:Prop⊢ P → ¬¬P
P:ProphP:PhnP:¬P⊢ False
All goals completed! 🐙
Example 8. Contraposition.
example (P Q : Prop) : (P → Q) → (¬Q → ¬P) := P:PropQ:Prop⊢ (P → Q) → ¬Q → ¬P
P:PropQ:ProphPQ:P → QhnQ:¬QhP:P⊢ False
All goals completed! 🐙
Example 9. Double negation elimination, which needs classical reasoning.
example (P : Prop) : ¬¬P → P := P:Prop⊢ ¬¬P → P
P:Proph:¬¬P⊢ P
P:Proph:¬¬P⊢ ¬P → False
P:Proph:¬¬PhnP:¬P⊢ False
All goals completed! 🐙
Example 10. Currying turns a conjunctive hypothesis into nested implications.
example (P Q R : Prop) : (P ∧ Q → R) → (P → (Q → R)) := P:PropQ:PropR:Prop⊢ (P ∧ Q → R) → P → Q → R
P:PropQ:PropR:Proph:P ∧ Q → RhP:PhQ:Q⊢ R
All goals completed! 🐙