have & let — Intermediate Results
have and let introduce intermediate results into your proof. They help break complex proofs into manageable steps.
have: Proving an Intermediate Fact
have h : T := ... proves something of typeT and names it h:
lean
1example (n : Nat) (h : n > 0) : n * 2 > 0 := by2 have pos : n > 0 := h3 -- pos : n > 0 is now in context4 omega56-- More useful: proving something new7example (a b : Nat) (ha : a > 5) (hb : b > 3) : a + b > 8 := by8 have hab : a + b > 5 + 3 := by omega9 omegahave with Tactics
Use have h : T := by ... to prove the intermediate result with tactics:
lean
1example (P Q R : Prop) (hp : P) (hpq : P → Q) (hqr : Q → R) : R := by2 have hq : Q := by3 apply hpq4 exact hp5 have hr : R := by6 apply hqr7 exact hq8 exact hr910-- Or more concisely:11example (P Q R : Prop) (hp : P) (hpq : P → Q) (hqr : Q → R) : R := by12 have hq : Q := hpq hp13 exact hqr hqKey Takeaway
have creates a named intermediate result. It's for proofs—the value is opaque and only its type matters.let: Introducing a Definition
let introduces a local definition where the value is visible (not opaque):
lean
1example : 10 = 5 + 5 := by2 let x := 53 -- x : Nat := 5 (value is visible)4 rfl56example (n : Nat) : n + n = 2 * n := by7 let m := n + n8 -- m : Nat := n + n9 show m = 2 * n10 ringhave vs let
lean
1-- have: value is opaque (for proofs)2example (h : 2 + 2 = 4) : True := by3 have proof : 2 + 2 = 4 := h4 -- proof is just "something of type 2 + 2 = 4"5 trivial67-- let: value is transparent (for computation)8example : (5 + 5) * 2 = 20 := by9 let ten := 5 + 510 -- ten is definitionally equal to 1011 rfl -- works because ten unfolds to 10ℹ
Use
have for proofs and intermediate propositions. Use let for computational values you want to reuse.have this
have : T := ... without a name creates a hypothesis called this:
lean
1example (n : Nat) (h : n > 5) : n > 0 := by2 have : n > 5 := h3 -- this : n > 54 omega56-- Useful for quick intermediate steps7example (a b : Nat) : (a + b) * (a + b) = a*a + 2*a*b + b*b := by8 have : (a + b) * (a + b) = (a + b)^2 := by ring9 ringType Inference
Lean can often infer the type:
lean
1example (P Q : Prop) (hp : P) (hpq : P → Q) : Q := by2 have hq := hpq hp -- Type inferred as Q3 exact hq45example : ∃ n : Nat, n > 10 := by6 let x := 427 have h := show x > 10 by omega8 exact ⟨x, h⟩Structuring Complex Proofs
lean
1theorem sqrt_two_irrational (p q : Nat) (hq : q ≠ 0) 2 (h : p * p = 2 * q * q) : False := by3 -- Step 1: Show p must be even4 have hp_even : 2 ∣ p := by5 sorry6 -- Step 2: Let p = 2k7 have ⟨k, hk⟩ := hp_even8 -- Step 3: Show q must be even9 have hq_even : 2 ∣ q := by10 sorry11 -- Step 4: Contradiction (infinite descent)12 sorryDeep Dive: have with Pattern Matching
You can destructure as you introduce:
lean
1example (h : ∃ n : Nat, n > 5 ∧ n < 10) : True := by2 have ⟨n, hn_gt, hn_lt⟩ := h3 -- n : Nat4 -- hn_gt : n > 55 -- hn_lt : n < 106 trivial78example (P Q : Prop) (h : P ∧ Q) : Q ∧ P := by9 have ⟨hp, hq⟩ := h10 exact ⟨hq, hp⟩suffices: Backward have
suffices is like havebut works backward:
lean
1example (n : Nat) : n + n ≥ n := by2 suffices h : n ≤ n + n by omega3 -- Now we prove: n ≤ n + n4 omega56-- Equivalent to:7example (n : Nat) : n + n ≥ n := by8 have h : n ≤ n + n := by omega9 omegaℹ
suffices h : S by tac means "it suffices to prove S; here's how S implies the goal (by tac), and now I'll prove S."Examples
Building Up a Proof
lean
1example (a b c : Nat) (h1 : a ≤ b) (h2 : b ≤ c) : a ≤ c := by2 have hab : a ≤ b := h13 have hbc : b ≤ c := h24 exact Nat.le_trans hab hbcNaming Complex Expressions
lean
1example (f : Nat → Nat) (h : ∀ n, f n = n + 1) : f (f 0) = 2 := by2 let x := f 03 have hx : x = 1 := by simp [h]4 have hfx : f x = 2 := by simp [h, hx]5 simp [hfx]Proof with Intermediate Lemma
lean
1example : ∀ n : Nat, n = 0 ∨ n > 0 := by2 intro n3 have h := Nat.eq_zero_or_pos n4 -- h : n = 0 ∨ 0 < n5 exact h