Jump to content

Propositional equality

From The Invariance Itself
Revision as of 18:01, 14 October 2026 by PMA Publisher (talk | contribs) (Published from the Principia Machina source)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Plain-language version: Two kinds of equality

Propositional equality is the proposition a = b. A proof of it is a term of that type, built and used like any other proof. It is distinct from definitional equality, which is a judgment the checker tests by computation and which no term records. Lean defines propositional equality as an inductive family with a single constructor. Symmetry, transitivity, substitution and congruence are all derived from its eliminator. Function extensionality is a theorem, proved from quotient types. Uniqueness of identity proofs holds with no axiom at all.

Equality as an inductive family

Lean's core library defines Eq as an inductive type in Prop with one constructor, Eq.refl.[1] Lean prints it so:

#print Eq
example : 2 + 2 = 4 := rfl
inductive Eq.{u_1} : {α : Sort u_1} → α → α → Prop
number of parameters: 2
constructors:
Eq.refl : ∀ {α : Sort u_1} (a : α), a = a

The two parameters are the type α and the left-hand side a. The right-hand side is an index: it varies between the type and the constructor's result, and the constructor fixes it to a. The constructor alone therefore proves only statements of the form a = a; every other equation needs an argument that ends in one. Written as rules, formation and introduction are

Γ⊢A:SortuΓ⊢a:AΓ⊢b:AΓ⊢a=b:PropΓ⊢a:AΓ⊢Eq.refla:a=a

The term rfl is Eq.refl with its argument left implicit. The example 2 + 2 = 4 := rfl is accepted because the checker finds 2 + 2 and 4 definitionally equal; rfl then has the type the statement asks for. Every proof by rfl is a definitional equality packaged as a propositional one. Not every propositional equality is definitional: most equations in mathematics need an argument, because no amount of computation turns one side into the other.

The eliminator

The recursor that every inductive type receives is, for Eq, the principle that makes equality useful.

set_option pp.proofs true in
#check @Eq.rec
@Eq.rec : {α : Sort u_2} →
  {a : α} → {motive : (a_1 : α) → a = a_1 → Sort u_1} → motive a (Eq.refl a) → {a_1 : α} → (t : a = a_1) → motive a_1 t

The motive, written C below, is a family over every right-hand side y and every proof that a = y. To produce an element of C b h it suffices to produce one at the constructor, C a (Eq.refl a):

Γ⊢C:Π(y:A).a=y→SortvΓ⊢c:Ca(Eq.refla)Γ⊢h:a=bΓ⊢Eq.recch:Cbh

with the computation rule

Eq.recc(Eq.refla)≡c

The motive may land in any universe, not only in Prop. A proof of an equation can therefore change the type of a piece of data. This is unusual for a proposition: Lean permits it only because Eq passes the test for subsingleton elimination, which is the subject of proof irrelevance and subsingleton elimination.[2]

Transport

Applying the eliminator with a motive that does not depend on the proof gives transport: from h : a = b and a term whose type mentions a, obtain the same term at b. Lean's core library defines Eq.subst and cast this way.[1] The triangle h ▸ e is a macro over Eq.rec and Eq.symm: it tries both orientations of h, and rewrites the expected type when there is one, otherwise the type of e.[3] With it the familiar laws of equality are one line each:

theorem symm' {α : Sort u} {a b : α} (h : a = b) : b = a :=
  h ▸ rfl

theorem trans' {α : Sort u} {a b c : α} (h₁ : a = b) (h₂ : b = c) : a = c :=
  h₂ ▸ h₁

theorem subst' {α : Sort u} {a b : α} (p : α → Prop) (h : a = b) (ha : p a) : p b :=
  h ▸ ha

theorem congrArg' {α : Sort u} {β : Sort v} {a₁ a₂ : α} (f : α → β) (h : a₁ = a₂) :
    f a₁ = f a₂ :=
  h ▸ rfl

def castAlong {α β : Type} (h : α = β) (x : α) : β :=
  h ▸ x

#print axioms trans'

The last command prints 'trans does not depend on any axioms. Nothing beyond the inductive definition is used. The definition castAlong is the case that needs the large motive: its result is data of type β, obtained from data of type α by a proof that the two types are equal.

Congruence

The theorem congrArg above is the first congruence principle: equal arguments give equal values. The core library adds congrFun (equal functions give equal values at one argument) and congr (both at once), each proved by transport in the same way. The library's documentation notes that tactics such as congr and simp use congrArg internally to apply equalities inside subterms.[1] congrArg and congr are stated for non-dependent functions. When the type of the result depends on the argument, f a₁ and f a₂ have different types, and the statement f a₁ = f a₂ cannot even be formed. That case needs a different relation.

Heterogeneous equality

Heterogeneous equality relates terms whose types are not known to be definitionally equal. It is a second inductive family, written a ≍ b in Lean 4.34.1:

#print HEq
#check fun (n m : Nat) (x : Fin (n + m)) (y : Fin (m + n)) => x ≍ y
#check @type_eq_of_heq
#check @eq_of_heq
inductive HEq.{u} : {α : Sort u} → α → {β : Sort u} → β → Prop
number of parameters: 2
constructors:
HEq.refl : ∀ {α : Sort u} (a : α), a ≍ a
fun n m x y => x ≍ y : (n m : Nat) → Fin (n + m) → Fin (m + n) → Prop
@type_eq_of_heq : ∀ {α β : Sort u_1} {a : α} {b : β}, a ≍ b → α = β
@eq_of_heq : ∀ {α : Sort u_1} {a a' : α}, a ≍ a' → a = a'

The statement x ≍ y is well formed even though Fin (n + m) and Fin (m + n) are equal only by a theorem about addition. The same statement with = is rejected:

#check fun (n m : Nat) (x : Fin (n + m)) (y : Fin (m + n)) => x = y

Lean reports Type mismatch: y has type Fin (m + n) but is expected to have type Fin (n + m). A proof of x ≍ y carries a proof that the types agree, which type_eq_of_heq extracts, and at a single type it collapses to ordinary equality by eq_of_heq. The core library's own documentation advises avoiding HEq where possible: the analogue of congr fails for it, since from f ≍ g and x ≍ y it does not follow that f x ≍ g y; the equality of types that HEq carries is often too weak.[1]

Function extensionality

Function extensionality says that functions which agree at every argument are equal. The eliminator of Eq offers no way to compare two lambda terms by their values. The Lean reference manual notes that function extensionality would have to be an axiom in Lean, were it not for quotient types, whose lifting operator has a definitional computation rule.[4] The proof in the core library forms the quotient of the function type by pointwise equality and applies each class to an argument:[1]

theorem funext' {α : Sort u} {β : α → Sort v} {f g : (x : α) → β x}
    (h : ∀ x, f x = g x) : f = g :=
  let eqv (f g : (x : α) → β x) : Prop := ∀ x, f x = g x
  let app (q : Quot eqv) (x : α) : β x := Quot.lift (fun f => f x) (fun _ _ h => h x) q
  congrArg app (Quot.sound h)

#print axioms funext'
#print axioms funext
'funext'' depends on axioms: [Quot.sound]
'funext' depends on axioms: [Quot.sound]

The axiom Quot.sound makes the classes of f and g equal, and congrArg carries that equality through app. The proof type-checks only because app (Quot.mk eqv f) reduces, by the computation rule for Quot.lift, to fun x => f x, which is f up to η. A merely propositional computation rule would not do: rewriting under the binder would already need function extensionality.[4] The axiom itself, and why it is one, are on the three axioms.

Uniqueness of identity proofs

Uniqueness of identity proofs (UIP) says that any two proofs of a = b are equal. Streicher's axiom K is the special case that every proof of a = a is Eq.refl a, and the two are equivalent.[5] In Lean both hold by definition:

theorem uip {α : Sort u} {a b : α} (h₁ h₂ : a = b) : h₁ = h₂ := rfl

theorem axiomK {α : Sort u} {a : α} (C : α → Sort v) (h : a = a) (x : C a) :
    h ▸ x = x := rfl

#print axioms uip
#print axioms axiomK

Both report that they do not depend on any axioms. The first is definitional proof irrelevance: a = b is a proposition, so any two of its proofs are definitionally equal. The second is what Carneiro calls K-like reduction: for a subsingleton eliminator, proof irrelevance lets the major premise be replaced by the constructor, after which the ordinary computation rule applies. For Eq this means that transport along h : a = a reduces to the identity, whatever h is.[6] Carneiro lists proof irrelevance and axiom K among the axioms commonly added to Coq, and observes that they hold in Lean with no axioms.[6]

Homotopy type theory takes the opposite course. It reads a proof of equality as a path, keeps proofs of equality relevant, and treats UIP as a property some types have rather than an axiom.[5] Its univalence axiom identifies equivalent types. The two-element type then has a non-trivial self-equality, the swap, so the universe is not a set, and univalence is inconsistent with UIP.[5][6] Because Lean's UIP is part of definitional equality rather than an axiom that could be left out, univalence cannot be added to Lean without making it inconsistent.

Next

Quotient types treats the construction that the proof of function extensionality used.

References

  1. ↑ 1.0 1.1 1.2 1.3 1.4 Lean 4 source, file src/Init/Prelude.lean, version 4.34.1: the definitions of Eq, HEq, cast, congrArg, congr, congrFun and funext, with their documentation comments. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Init/Prelude.lean
  2. ↑ The Lean Language Reference, version 4.34.0, §4.4 "Inductive Types", subsection "Subsingleton Elimination" (the recursor of Eq). https://lean-lang.org/doc/reference/4.34.0/The-Type-System/Inductive-Types/#subsingleton-elimination
  3. ↑ Lean 4 source, file src/Lean/Parser/Term.lean, version 4.34.1: the documentation comment of the h ▸ e syntax. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/Parser/Term.lean
  4. ↑ 4.0 4.1 The Lean Language Reference, version 4.34.0, §4.5.6 "Quotients and Function Extensionality". https://lean-lang.org/doc/reference/4.34.0/The-Type-System/Quotients/#quotient-funext
  5. ↑ 5.0 5.1 5.2 The Univalent Foundations Program, Homotopy Type Theory: Univalent Foundations of Mathematics, Institute for Advanced Study, 2013; Notes to Chapter 1, Example 3.1.9 and §7.2. https://homotopytypetheory.org/book/
  6. ↑ 6.0 6.1 6.2 Mario Carneiro, The Type Theory of Lean, Master's thesis, Carnegie Mellon University, 2019; p. 4 (UIP and univalence), p. 12 (K-like reduction), p. 15 (proof irrelevance and axiom K in Lean and Coq). https://github.com/digama0/lean-type-theory/releases/tag/v1.0