4.2. Basic Tactics
The basic tactics of this lecture are intro, apply, exact, assumption, sorry, clear and rename. They are basic because each performs a single elementary transformation of the proof state and because none depends on a particular connective, quantifier or theory. Almost every tactic proof uses them.
The tactic intro moves the leading ∀-bound variable, or the leading assumption of an implication, from the conclusion into the local context, under a chosen name. Given a provable goal it always produces a provable goal.
The tactic apply matches the conclusion of the goal with the conclusion of a theorem or hypothesis, up to computation, and adds its unresolved arguments and premises as new goals. It can turn a provable goal into an unprovable one. The tactic exact closes the goal with a term that proves it. When both close the goal, exact states the intention more clearly. The tactic assumption searches the local context for a hypothesis that matches the conclusion.
Lean inserts the parameters written to the left of the colon into the local context of the initial goal, so the proofs below need no intro.
namespace Backward
theorem fst_of_two_props_params (a b : Prop)
(ha : a) (hb : b) : a := a:Propb:Propha:ahb:b⊢ a
All goals completed! 🐙
theorem fst_of_two_props_exact (a b : Prop)
(ha : a) (hb : b) : a := a:Propb:Propha:ahb:b⊢ a
All goals completed! 🐙
theorem fst_of_two_props_assumption (a b : Prop)
(ha : a) (hb : b) : a := a:Propb:Propha:ahb:b⊢ a
All goals completed! 🐙
end Backward
The tactic sorry closes any goal without proving it, exactly as the term sorry did in Lecture 3, and Lean flags every use. The example below shows how apply turns a provable goal into an unprovable one. The conclusion a ∨ b follows from the hypothesis hb by the rule Or.inr, but apply Or.inl commits to the left disjunct and leaves the goal a, which no hypothesis proves.
example (a b : Prop) (hb : b) : a ∨ b := a:Propb:Prophb:b⊢ a ∨ b
a:Propb:Prophb:b⊢ a
a:Propb:Prophb:b⊢ a
All goals completed! 🐙
With the rule Or.inr the proof closes the goal.
example (a b : Prop) (hb : b) : a ∨ b := a:Propb:Prophb:b⊢ a ∨ b
a:Propb:Prophb:b⊢ b
All goals completed! 🐙
Two tactics clean the local context. The tactic clear drops the variables or hypotheses you name, and Lean only checks that nothing else depends on them, not that the proof can still go through, so clear can turn a provable goal into an unprovable one. The tactic rename renames a hypothesis, selected by its proposition.
namespace Backward
theorem cleanup_example (a b c : Prop) (ha : a) (hb : b)
(hab : a → b) (hbc : b → c) : c := a:Propb:Propc:Propha:ahb:bhab:a → bhbc:b → c⊢ c
b:Propc:Prophb:bhbc:b → c⊢ c
b:Propc:Prophb:bhbc:b → c⊢ b
b:Prophb:b⊢ b
b:Proph:b⊢ b
All goals completed! 🐙
end Backward
4.2.1. Examples
The examples below exercise intro, apply, exact, assumption, sorry, clear and rename, and distinguish the tactics that preserve provability from those that can lose it.
Example 1. intro on a ∀-goal moves the bound variable into the context. The trace shows the goal before and after.
example : ∀ n : ℕ, add n 0 = n := ⊢ ∀ (n : ℕ), add n 0 = n
⊢ ∀ (n : ℕ), add n 0 = n
n:ℕ⊢ add n 0 = n
n:ℕ⊢ add n 0 = n
All goals completed! 🐙
Example 2. One intro with several names abbreviates several intros. The two scripts prove the same theorem.
example : ∀ a b : Prop, a → a := ⊢ ∀ (a b : Prop), a → a
a:Propb:Propha:a⊢ a
All goals completed! 🐙
example : ∀ a b : Prop, a → a := ⊢ ∀ (a b : Prop), a → a
a:Prop⊢ ∀ (b : Prop), a → a
a:Propb:Prop⊢ a → a
a:Propb:Propha:a⊢ a
All goals completed! 🐙
Example 3. Parameters to the left of the colon need no intro, since Lean inserts them into the local context of the initial goal.
example : ∀ a : Prop, a → a := ⊢ ∀ (a : Prop), a → a
a:Propha:a⊢ a
All goals completed! 🐙
example (a : Prop) (ha : a) : a := a:Propha:a⊢ a
All goals completed! 🐙
Example 4. exact h and apply h close the same goal, and exact says more.
example (a b : Prop) (hab : a → b) (ha : a) : b := a:Propb:Prophab:a → bha:a⊢ b
All goals completed! 🐙
example (a b : Prop) (hab : a → b) (ha : a) : b := a:Propb:Prophab:a → bha:a⊢ b
All goals completed! 🐙
Example 5. assumption closes the goal without naming the hypothesis.
example (a b c : Prop) (ha : a) (hb : b) (hc : c) : b := a:Propb:Propc:Propha:ahb:bhc:c⊢ b
All goals completed! 🐙
Example 6. Two applys in sequence apply two implications backwards.
example (a b c : Prop) (hab : a → b) (hbc : b → c)
(ha : a) : c := a:Propb:Propc:Prophab:a → bhbc:b → cha:a⊢ c
a:Propb:Propc:Prophab:a → bhbc:b → cha:a⊢ b
a:Propb:Propc:Prophab:a → bhbc:b → cha:a⊢ a
All goals completed! 🐙
Example 7. apply can lose a provable goal. Choosing the wrong disjunct leaves a conclusion no hypothesis proves, and only sorry closes it.
example (a b : Prop) (ha : a) : a ∨ b := a:Propb:Propha:a⊢ a ∨ b
a:Propb:Propha:a⊢ b
All goals completed! 🐙
Example 8. sorry closes any goal, and #print axioms reports the use of sorryAx, as in Lecture 3.
namespace Backward
theorem unproved (a : Prop) : a := a:Prop⊢ a
All goals completed! 🐙
end Backward
#print axioms Backward.unproved
Example 9. clear removes a hypothesis and a variable the proof does not use.
example (a b : Prop) (ha : a) (hb : b) : b := a:Propb:Propha:ahb:b⊢ b
b:Prophb:b⊢ b
All goals completed! 🐙
Example 10. rename renames a hypothesis, selected by its proposition.
example (a b : Prop) (h : a ∧ b) : a ∧ b := a:Propb:Proph:a ∧ b⊢ a ∧ b
a:Propb:Prophab:a ∧ b⊢ a ∧ b
All goals completed! 🐙