Proof Workflow
Learn a repeatable process for building proofs: read the goal, introduce assumptions, simplify, and close with a finishing tactic.
Read the Goal First
Every proof starts with a goal. Before choosing a tactic, identify the shape of the goal and what it expects. The goal appears after the ⊢ symbol in the Infoview. Understanding the goal's structure—whether it's an implication, a universal statement, an equality, or a conjunction—determines which tactic to use.
Common goal shapes and their meanings:
P → Q: An implication—assume P, prove Q∀ x, P x: A universal—prove P for an arbitrary xa = b: An equality—show both sides are the sameP ∧ Q: A conjunction—prove both P and QP ∨ Q: A disjunction—prove at least one of P or Q
1example : Nat → Nat := by2 -- Goal: Nat → Nat3 -- This is a function type, so we introduce the input4 intro n5 -- Goal: Nat6 -- Now we just need to produce a Nat7 exact n + 1The Infoview updates after each tactic, showing how the goal changes. Watch it like a debugging panel—it tells you exactly what remains to prove.
Introduce, Then Simplify
Most goals become easier once you move assumptions into context and simplify the target. The general strategy is: first use intro to bring universals and implications into your hypothesis list, then use simp orrw to clean up the goal.
This "introduce then simplify" pattern handles the majority of proofs:
1-- Simple simplification2example (n : Nat) : n + 0 = n := by3 simp -- simp knows n + 0 = n45-- Reflexivity when both sides are identical6example (n : Nat) : n = n := by7 rfl -- Both sides compute to the same thingWhen you have hypotheses available, include them in your simplification:
1example (a b : Nat) (h : a = b) : a + 1 = b + 1 := by2 simp [h] -- Uses h to rewrite a to b, then simplifies34example (n : Nat) (h : n = 5) : n + 0 = 5 := by5 simp only [Nat.add_zero, h] -- Explicit about which lemmasClose with a Finisher
If the goal is exactly a hypothesis, use exact orassumption. If it’s a definitional equality, try rfl. These "finisher" tactics close the proof when only the final step remains.
exact requires you to specify exactly which term proves the goal.assumption searches your hypotheses automatically. Useexact when you know what you need; use assumptionwhen the answer is obviously in scope.
1-- exact: specify the proof term2example (P Q : Prop) (hp : P) : P := by3 exact hp45-- assumption: auto-search hypotheses6example (P Q : Prop) (hp : P) (hq : Q) : P := by7 assumption -- Finds hp automatically89-- rfl: definitional equality10example : (2 : Nat) = 2 := by11 rfl1213-- trivial: handles True and similar goals14example : True := by15 trivialIf none of these work, your goal likely needs further transformation. Go back to simplification or try rewriting with rw.
Pick the Right Tactic
A fast workflow is about choosing the simplest tactic that moves the goal forward. Here's a quick reference for common goal shapes:
| Goal Shape | Primary Tactic | What It Does |
|---|---|---|
| P → Q | intro | Assume P, prove Q |
| ∀ x, P x | intro | Let x be arbitrary |
| P ∧ Q | constructor | Split into two goals |
| P ∨ Q | left or right | Pick which to prove |
| a = b | rfl, rw, simp | Make sides equal |
| ∃ x, P x | use | Provide a witness |
When in doubt, try simp first. It often cleans up the goal enough that the next step becomes obvious.
simp early. It often turns a complicated goal into somethingrfl can close.Debugging Stuck Proofs
Even experienced users get stuck. Here's how to diagnose and fix common issues:
Check the Goal Carefully
Sometimes the goal looks right but has subtle differences—like implicit arguments or different universes. Hover over terms in the Infoview to see their full types.
Use simp? and exact?
These "?" tactics suggest what to use:
1example (n : Nat) : n + 0 = n := by2 simp? -- Suggests: Try this: simp only [Nat.add_zero]34example (P : Prop) (hp : P) : P := by5 exact? -- Suggests: Try this: exact hpBreak Complex Goals Apart
If the goal is overwhelming, use have to prove intermediate steps:
1example (a b c : Nat) : a + b + c = c + b + a := by2 have h1 : a + b = b + a := Nat.add_comm a b3 have h2 : b + a + c = c + (b + a) := by ring4 ring -- Now the goal is simplerUse intro and exact to prove the following:
1example (P Q : Prop) : P → Q → P := by2 intro hp hq3 exact hpUse constructor to prove a conjunction.
1example (P Q : Prop) (hp : P) (hq : Q) : P ∧ Q := by2 constructor3 · exact hp4 · exact hq