Lean theorem prover/Foundations/Proof irrelevance and subsingleton elimination: Difference between revisions
Published from the Principia Machina source |
Published from the Principia Machina source |
||
| Line 1: | Line 1: | ||
{{DISPLAYTITLE:Proof irrelevance and subsingleton elimination}} | {{DISPLAYTITLE:Proof irrelevance and subsingleton elimination}} | ||
{{Plebeian|Lean theorem prover/Explainers/Two kinds of equality}} | {{Plebeian|Lean theorem prover/Explainers/Two kinds of equality}} | ||
{{Lean theorem prover map}} | |||
Two rules govern how proofs behave in Lean. '''Definitional proof irrelevance''' makes any | Two rules govern how proofs behave in Lean. '''Definitional proof irrelevance''' makes any | ||
Latest revision as of 19:35, 15 October 2026
| Lean theorem prover: map |
|---|
| Reading the edition Three levels of reading Glossary Notation Chronology |
| Reading by level Start here: What a proof assistant does The type theory: Terms, types and judgments How Lean works: Elaboration The history: Automath The applications: Research mathematics |
| Sources Sources Bibliography Further reading |
| Related The move to Lean |
Two rules govern how proofs behave in Lean. Definitional proof irrelevance makes any two proofs of the same proposition definitionally equal. Restricted elimination allows a proof to be taken apart to produce data only when the proposition is a subsingleton, one that by its shape can have at most one proof. The first rule says that the content of a proof never matters; the second is what keeps that consistent. This page states both rules, lists which propositions pass the test, explains why the test is needed, and sets out the cost: together with the accessibility predicate, the two rules make Lean's definitional equality undecidable.
Definitional proof irrelevance
Carneiro's presentation of Lean's type theory includes the rule[1]
It is a rule of definitional equality, so the checker applies it during conversion, without
any proof term. The reference manual lists it among the defining properties of
Prop, beside the erasure of propositions from compiled code.[2]
example (p : Prop) (h₁ h₂ : p) : h₁ = h₂ := rfl
example (h₁ h₂ : 0 < 5) : (⟨5, h₁⟩ : {n : Nat // 0 < n}) = ⟨5, h₂⟩ := rfl
example (α : Type) (h₁ h₂ : Nonempty α) : Classical.choice h₁ = Classical.choice h₂ := rfl
All three are accepted. The second shows the practical use: elements of a subtype are equal as soon as their values are, whatever proofs they carry. The third shows that global choice returns one element per type, not one per proof. Carneiro, writing in 2019, notes that Coq then had proof irrelevance only as an axiom asserting a propositional equality, and calls Lean's definitional version "a major departure for the theory".[1]
Why elimination must be restricted
Suppose a program could inspect which constructor built a proof of a disjunction, and so
return true on Or.inl trivial : True ∨ True and false
on Or.inr trivial. Those two proofs have the same type, so proof irrelevance
makes them definitionally equal, the two results would be definitionally equal, and
true = false would follow by rfl. One of the two rules has to
give way. Lean keeps proof irrelevance and forbids the inspection: having been given a
proof, a program must not be able to tell which proof it received.[3]
Lean refuses the function:
def which (h : True ∨ True) : Bool := match h with | .inl _ => true | .inr _ => false
The message begins Tactic `cases` failed with a nested error: and continues
Tactic `induction` failed: recursor `Or.casesOn` can only eliminate into `Prop`.
The restriction is visible in the recursors themselves. The motive of Or.rec
and of Exists.rec returns Prop, while the motives of
True.rec, False.rec and And.rec return an arbitrary
Sort u_1:
#check @True.rec #check @False.rec #check @And.rec #check @Or.rec #check @Exists.rec
@True.rec : {motive : True → Sort u_1} → motive True.intro → (t : True) → motive t
False.rec : (motive : False → Sort u_1) → (t : False) → motive t
@And.rec : {a b : Prop} → {motive : a ∧ b → Sort u_1} → ((left : a) → (right : b) → motive ⋯) → (t : a ∧ b) → motive t
@Or.rec : ∀ {a b : Prop} {motive : a ∨ b → Prop},
(∀ (h : a), motive ⋯) → (∀ (h : b), motive ⋯) → ∀ (t : a ∨ b), motive t
@Exists.rec : ∀ {α : Sort u_1} {p : α → Prop} {motive : Exists p → Prop},
(∀ (w : α) (h : p w), motive ⋯) → ∀ (t : Exists p), motive t
The rule
An inductive type in Prop may be eliminated into any universe, which is
large elimination, when it is a syntactic subsingleton. The reference manual states
the test as two conditions: there is at most one constructor, and every argument of that
constructor either has a proposition as its type or is a parameter or an index of the
type.[3] Carneiro's formulation is that there is at most one constructor
and every non-recursive argument of it either has a proposition as its type or appears
directly in the constructor's output type.[1] Otherwise the motive of the recursor must return
Prop. The test is deliberately conservative: it does not ask for a proof that
the proposition has at most one proof, only for a shape that guarantees it.[3]
The standard cases:
Truehas one constructor with no arguments, andFalsehas none. Fromh : False,h.elimproduces an element of any type.[3]Andhas one constructor whose arguments are proofs.[3]Eqhas one constructor,Eq.refl a, whose argument is fixed by the type's parameters. This is why a proof of an equation can rewrite the type of data, the operation called transport on propositional equality.[3]Acc, the accessibility predicate, has one constructorAcc.intro x h. Its argumentxappears in the result typeAcc r xand its argumenthis a proof, so it too eliminates into any universe. Carneiro singles it out as the source of proof by well-founded recursion.[1]
Or fails because it has two constructors. Exists and
Nonempty fail because their constructor stores a witness that is neither a
proof nor part of the type. Their proofs therefore cannot yield the witness as data; that
requires Classical.choose, as on
classical logic from choice.
Where the witness is wanted as data, the subtype {x // p x}, which lives in
Type, carries it.
def fromFalse (h : False) : Nat := h.elim
def castAlong {α β : Type} (h : α = β) (x : α) : β := h ▸ x
def bothThen {p q : Prop} (h : p ∧ q) (f : p → q → Nat) : Nat :=
match h with
| ⟨hp, hq⟩ => f hp hq
set_option pp.proofs true in
#check @Acc.rec
@Acc.rec : {α : Sort u_2} →
{r : α → α → Prop} →
{motive : (a : α) → Acc r a → Sort u_1} →
((x : α) →
(h : ∀ (y : α), r y x → Acc r y) → ((y : α) → (a : r y x) → motive y (h y a)) → motive x (Acc.intro x h)) →
{a : α} → (t : Acc r a) → motive a t
For subsingletons the checker also applies an extra reduction, which Carneiro calls K-like
reduction: by proof irrelevance the major premise may be replaced by the constructor, and
the ordinary computation rule then fires. It applies only when every argument of the
constructor can be read off the type, which is the reason for the shape of the
test.[1] For Eq it makes transport along any proof of
a = a reduce to the identity.
The cost: definitional equality is undecidable
Proof irrelevance and the large eliminator of Acc together break the
decidability of definitional equality. Carneiro's argument runs as follows.[1]
From a proof a : Acc r x one can project, with the eliminator, a function
giving accessibility of every smaller element; call it a.inv. Rebuilding with
the constructor gives a proof of the same proposition, so by proof irrelevance
a and Acc.intro x a.inv are definitionally equal:
example {α : Sort u} {r : α → α → Prop} {x : α} (a : Acc r x) :
a = Acc.intro x (fun _ h => a.inv h) := rfl
That step turns any proof, even an opaque variable, into a constructor on which the
recursor can compute. Now take a decidable predicate on the natural
numbers, such as "machine runs for at least steps without
halting", and a function defined by recursion on Acc for the
relation , which at returns a fixed value if
fails and otherwise calls itself at . The relation
on the natural numbers is not well founded, so a hypothesis
is unprovable, but definitional equality is
judged in every context, inconsistent ones included. In that context each use of the
equation above lets take one more step of the search. If
fails for some , the search ends and is
definitionally equal to the fixed value; if holds everywhere, every term
definitionally equal to still contains a call of .
Deciding that one definitional equality would decide whether halts.
Lean's checker cannot implement an undecidable relation. It implements a decidable approximation, which Carneiro calls algorithmic equality, and the two must differ: the chain of equalities above holds step by step, but the checker, which does not perform the "creative" re-expansion of a normal term, does not relate its two ends. Algorithmic equality is therefore not transitive.[1] The reference manual records the same fact: definitional equality as Lean checks it is reflexive and symmetric, but not transitive.[4] Carneiro also shows that, measured against the algorithmic relation, typing fails subject reduction: a term can be well typed and reduce to one that the checker rejects.[1]
None of this lets the checker accept a false theorem. Algorithmic equality implies the
ideal definitional equality for well-typed terms, so whatever the checker accepts is
derivable in the theory; Carneiro uses exactly this step in his consistency proof. The
defect is incompleteness, not unsoundness.[1]
Abel and Coquand later showed a related failure: with an impredicative Prop
and proof-irrelevant equality, reduction need not terminate at all.[5]
That result, and why the checker remains sound regardless, are treated on
consistency and the metatheory.
Abel and Coquand also note the other design: Agda and Coq had recently gained a proof-irrelevant universe
of strict propositions in which equality can be defined but cannot be eliminated into types
that are not themselves strict propositions, and under that restriction normalisation and
decidable type checking have been proved for the predicative case.[5]
Next
Consistency and the metatheory asks what is known about the soundness of the whole system.
References
- ↑ 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 Mario Carneiro, The Type Theory of Lean, Master's thesis, Carnegie Mellon University, 2019; §2.2 (pp. 6–7), §2.6.2 (pp. 10–11), §2.6.4 (p. 12), §2.8 (p. 15), §3.1 (pp. 16–17), Lemma 3.4 (pp. 18–19) and Corollary 6.8 (p. 41). https://github.com/digama0/lean-type-theory/releases/tag/v1.0
- ↑ The Lean Language Reference, version 4.34.0, §4.2 "Propositions". https://lean-lang.org/doc/reference/4.34.0/The-Type-System/Propositions/
- ↑ 3.0 3.1 3.2 3.3 3.4 3.5 The Lean Language Reference, version 4.34.0, §4.4 "Inductive Types", subsection "Subsingleton Elimination". https://lean-lang.org/doc/reference/4.34.0/The-Type-System/Inductive-Types/#subsingleton-elimination
- ↑ The Lean Language Reference, version 4.34.0, §4 "The Type System" (definitional equality). https://lean-lang.org/doc/reference/4.34.0/The-Type-System/
- ↑ 5.0 5.1 Andreas Abel and Thierry Coquand, "Failure of normalization in impredicative type theory with proof-irrelevant propositional equality", Logical Methods in Computer Science 16(2) (2020), paper 14. https://doi.org/10.23638/LMCS-16(2:14)2020