An existential statement says that some object exists with a given property.
An existential statement says that some object exists with a given property. In Lean, a proof of Exists P contains two pieces of data: a witness and a proof that the witness satisfies the predicate.
The usual mathematical notation:
∃ x, P xmeans:
Exists (fun x => P x)Problem
You want to prove or use a statement of the form:
∃ x : α, P xTo prove it, provide a witness x and then prove P x. To use it, unpack the witness and its proof.
Solution
Use use to provide a witness.
theorem exists_nat_example : ∃ n : Nat, n = 3 := by
use 3After use 3, the goal becomes:
⊢ 3 = 3Lean closes it by reflexivity.
A more explicit version is:
theorem exists_nat_example_explicit : ∃ n : Nat, n = 3 := by
use 3
rflProviding a Witness with a Nontrivial Proof
The witness fixes the remaining goal.
theorem exists_even_example : ∃ n : Nat, n + n = 6 := by
use 3After use 3, Lean checks:
⊢ 3 + 3 = 6This reduces by computation.
For a proof that needs a library theorem:
theorem exists_add_zero (a : Nat) : ∃ n : Nat, a + n = a := by
use 0
simpThe witness is 0. The remaining goal is:
⊢ a + 0 = awhich simp proves.
Constructing Existentials Directly
The constructor for existential statements is Exists.intro.
theorem exists_intro_term : ∃ n : Nat, n = 3 :=
Exists.intro 3 rflThe first argument is the witness. The second argument is the proof that the witness satisfies the predicate.
For:
∃ n : Nat, n = 3the witness is:
3and the proof is:
rfl : 3 = 3Using an Existential Hypothesis
If you have:
h : ∃ x : α, P xthen you can extract a witness and its property proof by case analysis.
theorem exists_use_example
(h : ∃ n : Nat, n = 3) :
∃ m : Nat, m + 1 = 4 := by
cases h with
| intro n hn =>
use n
rw [hn]After cases h, Lean gives:
n : Nat
hn : n = 3
⊢ ∃ m : Nat, m + 1 = 4The proof uses the same witness n, then rewrites n to 3.
Destructuring with rcases
For existential hypotheses, rcases gives compact destructuring.
theorem exists_use_rcases
(h : ∃ n : Nat, n = 3) :
∃ m : Nat, m + 1 = 4 := by
rcases h with ⟨n, hn⟩
use n
rw [hn]The pattern:
⟨n, hn⟩extracts the witness n and the proof hn.
Existentials with Multiple Conditions
Existential predicates often contain conjunctions.
theorem exists_with_and : ∃ n : Nat, n = 3 ∧ n + 1 = 4 := by
use 3
constructor
· rfl
· rflAfter use 3, the goal is:
⊢ 3 = 3 ∧ 3 + 1 = 4Then constructor splits the conjunction.
Using Existentials with Conjunctions
When an existential contains a conjunction, unpack both layers.
theorem exists_and_use
(h : ∃ n : Nat, n = 3 ∧ n + 1 = 4) :
∃ n : Nat, n + 1 = 4 := by
rcases h with ⟨n, hn_eq, hn_add⟩
use n
exact hn_addThe pattern:
⟨n, hn_eq, hn_add⟩is shorthand for unpacking:
⟨n, ⟨hn_eq, hn_add⟩⟩The first component is the witness. The remaining components are proofs from the conjunction.
Changing the Witness
Sometimes the output witness differs from the input witness.
theorem exists_successor
(h : ∃ n : Nat, n = 3) :
∃ m : Nat, m = 4 := by
rcases h with ⟨n, hn⟩
use n + 1
rw [hn]After rewriting n to 3, the goal becomes:
⊢ 3 + 1 = 4which is solved by computation.
Existentials Over Arbitrary Types
Existentials are not limited to natural numbers.
theorem exists_self
(α : Type)
(a : α) :
∃ x : α, x = a := by
use aThe witness is the given value a.
A predicate version:
theorem exists_from_predicate
(α : Type)
(P : α -> Prop)
(a : α)
(ha : P a) :
∃ x : α, P x := by
use aAfter use a, the goal is exactly P a, which is already available as ha. Lean can close it, but an explicit version is clearer:
theorem exists_from_predicate_explicit
(α : Type)
(P : α -> Prop)
(a : α)
(ha : P a) :
∃ x : α, P x := by
use a
exact haExistentials and Equality Transport
A common pattern is to unpack an existential, rewrite with an equality, and rebuild another existential.
theorem exists_transport
(P : Nat -> Prop)
(h : ∃ n : Nat, n = 3 ∧ P n) :
P 3 := by
rcases h with ⟨n, hn_eq, hnP⟩
rw [← hn_eq]
exact hnPHere hn_eq : n = 3. The goal is P 3, while the available proof is hnP : P n. Rewriting backward changes P 3 to P n.
Nested Existentials
Multiple existential quantifiers are nested.
theorem exists_pair_example :
∃ n : Nat, ∃ m : Nat, n = m := by
use 3
use 3This means:
∃ n : Nat, (∃ m : Nat, n = m)To unpack:
theorem exists_pair_use
(h : ∃ n : Nat, ∃ m : Nat, n = m) :
∃ k : Nat, k = k := by
rcases h with ⟨n, m, hnm⟩
use nThe pattern ⟨n, m, hnm⟩ unpacks both existential layers.
Existentials and apply
You can construct an existential with apply Exists.intro.
theorem exists_apply_intro : ∃ n : Nat, n = 5 := by
apply Exists.intro 5
rflThis is more verbose than use, but it exposes the constructor.
Common Patterns
To prove:
⊢ ∃ x : α, P xuse:
use athen prove:
⊢ P aTo use:
h : ∃ x : α, P xuse:
rcases h with ⟨x, hx⟩or:
cases h with
| intro x hx => ...To prove an existential with several properties:
use a
constructorTo unpack nested existential and conjunction data:
rcases h with ⟨x, hx₁, hx₂⟩Common Pitfalls
Do not try to prove an existential without choosing a witness. Lean needs a concrete term for the quantified variable.
Do not assume the witness has a particular name. After unpacking an existential, choose names that reflect how the witness will be used.
Do not forget that ∃ x, P x ∧ Q x contains a witness and then a conjunction of proofs. You must unpack both layers when needed.
Do not rewrite in the wrong direction when moving a property from the witness to a known value.
Takeaway
An existential proof is a witness plus evidence. To prove ∃ x, P x, provide a witness and prove the predicate for that witness. To use ∃ x, P x, unpack the witness and the proof, then continue with those concrete objects in the local context.