<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://invarians.org/index.php?action=history&amp;feed=atom&amp;title=Lean_theorem_prover%2FFoundations%2FDefinitional_equality</id>
	<title>Lean theorem prover/Foundations/Definitional equality - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://invarians.org/index.php?action=history&amp;feed=atom&amp;title=Lean_theorem_prover%2FFoundations%2FDefinitional_equality"/>
	<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Foundations/Definitional_equality&amp;action=history"/>
	<updated>2026-10-21T09:16:57Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.46.2</generator>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/Foundations/Definitional_equality&amp;diff=6779&amp;oldid=prev</id>
		<title>PMA Publisher: Published from the Principia Machina source</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Foundations/Definitional_equality&amp;diff=6779&amp;oldid=prev"/>
		<updated>2026-10-15T19:34:53Z</updated>

		<summary type="html">&lt;p&gt;Published from the Principia Machina source&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw-interface=&quot;&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 19:34, 15 October 2026&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l1&quot;&gt;Line 1:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;{{DISPLAYTITLE:Definitional equality}}&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;{{DISPLAYTITLE:Definitional equality}}&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;{{Plebeian|Lean theorem prover/Explainers/Two kinds of equality|Lean theorem prover/Explainers/Computation inside proofs}}&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;{{Plebeian|Lean theorem prover/Explainers/Two kinds of equality|Lean theorem prover/Explainers/Computation inside proofs}}&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;{{Lean theorem prover map}}&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Two terms are &amp;#039;&amp;#039;&amp;#039;definitionally equal&amp;#039;&amp;#039;&amp;#039; when they are equal by computation and unfolding of&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Two terms are &amp;#039;&amp;#039;&amp;#039;definitionally equal&amp;#039;&amp;#039;&amp;#039; when they are equal by computation and unfolding of&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>PMA Publisher</name></author>
	</entry>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/Foundations/Definitional_equality&amp;diff=6572&amp;oldid=prev</id>
		<title>PMA Publisher: Published from the Principia Machina source</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Foundations/Definitional_equality&amp;diff=6572&amp;oldid=prev"/>
		<updated>2026-10-14T18:01:00Z</updated>

		<summary type="html">&lt;p&gt;Published from the Principia Machina source&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{DISPLAYTITLE:Definitional equality}}&lt;br /&gt;
{{Plebeian|Lean theorem prover/Explainers/Two kinds of equality|Lean theorem prover/Explainers/Computation inside proofs}}&lt;br /&gt;
&lt;br /&gt;
Two terms are &amp;#039;&amp;#039;&amp;#039;definitionally equal&amp;#039;&amp;#039;&amp;#039; when they are equal by computation and unfolding of&lt;br /&gt;
definitions, without any proof. Definitional equality is not a proposition inside Lean. It is&lt;br /&gt;
a judgment of the theory, and Lean&amp;#039;s kernel decides it, as far as it can, whenever it checks&lt;br /&gt;
a type. It is how computation enters proofs: a goal that holds by calculation is closed by&lt;br /&gt;
&amp;lt;code&amp;gt;rfl&amp;lt;/code&amp;gt;, because the two sides are definitionally equal. This page lists the rules&lt;br /&gt;
that generate the relation, shows how natural-number literals are handled, describes how the&lt;br /&gt;
Lean kernel decides it, and states the theoretical limits: in Lean&amp;#039;s full theory the relation&lt;br /&gt;
is undecidable, and the Lean kernel decides a slightly smaller one.&lt;br /&gt;
&lt;br /&gt;
== The judgment and its use ==&lt;br /&gt;
&lt;br /&gt;
The judgment &amp;lt;math&amp;gt;\Gamma \vdash e \equiv e&amp;#039;&amp;lt;/math&amp;gt; says that &amp;lt;math&amp;gt;e&amp;lt;/math&amp;gt; and&lt;br /&gt;
&amp;lt;math&amp;gt;e&amp;#039;&amp;lt;/math&amp;gt; are definitionally equal in the context &amp;lt;math&amp;gt;\Gamma&amp;lt;/math&amp;gt;. In the ideal&lt;br /&gt;
presentation it is an equivalence relation, closed under every term former, and generated&lt;br /&gt;
by the rules below.&amp;lt;ref name=&amp;quot;carneiro2019&amp;quot;&amp;gt;Mario Carneiro, &amp;#039;&amp;#039;The Type Theory of Lean&amp;#039;&amp;#039;, MSc&lt;br /&gt;
thesis, Carnegie Mellon University, 2019.&lt;br /&gt;
https://github.com/digama0/lean-type-theory/releases/tag/v1.0&amp;lt;/ref&amp;gt; It does its work&lt;br /&gt;
through the conversion rule of&lt;br /&gt;
[[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]]:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{\Gamma \vdash e : A \qquad \Gamma \vdash A \equiv B}{\Gamma \vdash e : B}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A term of one type also has every definitionally equal type. In particular, a proof of&lt;br /&gt;
&amp;lt;code&amp;gt;a = a&amp;lt;/code&amp;gt;, which is what &amp;lt;code&amp;gt;rfl&amp;lt;/code&amp;gt; is, is also a proof of &amp;lt;code&amp;gt;a = b&amp;lt;/code&amp;gt;&lt;br /&gt;
whenever &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; are definitionally equal. Because the relation&lt;br /&gt;
includes reduction, types can be the result of computation.&amp;lt;ref name=&amp;quot;refman-ts&amp;quot;&amp;gt;&amp;#039;&amp;#039;The Lean&lt;br /&gt;
Language Reference&amp;#039;&amp;#039;, for Lean 4.34.0, lean-lang.org, 2026, chapter 4, &amp;quot;The Type System&amp;quot;.&lt;br /&gt;
https://lean-lang.org/doc/reference/4.34.0/The-Type-System/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Reduction rules ==&lt;br /&gt;
&lt;br /&gt;
Four reductions generate most of the relation. Each is named by a Greek letter by long&lt;br /&gt;
convention.&amp;lt;ref name=&amp;quot;refman-ts&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;carneiro2019&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Beta&amp;#039;&amp;#039;&amp;#039;: applying an abstraction substitutes the argument, &amp;lt;math&amp;gt;(\lambda x : A.\, e)\,a \equiv e[a/x]&amp;lt;/math&amp;gt;.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Delta&amp;#039;&amp;#039;&amp;#039;: a defined constant equals its definition, with universe parameters instantiated, &amp;lt;math&amp;gt;c \equiv v&amp;lt;/math&amp;gt; for &amp;lt;math&amp;gt;\mathrm{def}\ c := v&amp;lt;/math&amp;gt;.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Iota&amp;#039;&amp;#039;&amp;#039;: a recursor applied to a constructor reduces to the corresponding minor premise, as described on [[Lean theorem prover/Foundations/Inductive types and recursors|Inductive types and recursors]]. A projection applied to a constructor application reduces in the same way, and so does the lifting of a function through a quotient, applied to an element of the quotient ([[Lean theorem prover/Foundations/Quotient types|Quotient types]]).&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Zeta&amp;#039;&amp;#039;&amp;#039;: a local definition equals its body with the value substituted, &amp;lt;math&amp;gt;(\mathrm{let}\ x := v;\ e) \equiv e[v/x]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Each holds by &amp;lt;code&amp;gt;rfl&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;lean&amp;quot; style=&amp;quot;background: #f8f9fa; border: 1px solid #c8ccd1; padding: 0.6em; margin: 0.3em 0; font-size: 0.85em; line-height: 1.35; overflow-x: auto; white-space: pre;&amp;quot;&amp;gt;&lt;br /&gt;
def sq (n : Nat) : Nat := n * n&lt;br /&gt;
&lt;br /&gt;
example : (fun x : Nat =&amp;gt; x + 1) 2 = 2 + 1 := rfl                              -- beta&lt;br /&gt;
example : sq 3 = 3 * 3 := rfl                                                   -- delta&lt;br /&gt;
example : Nat.rec (motive := fun _ =&amp;gt; Bool) true (fun _ b =&amp;gt; !b) 3 = false := rfl -- iota&lt;br /&gt;
example : (let x := 5; x + x) = 5 + 5 := rfl                                    -- zeta&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The third line computes by recursion: the recursor flips a Boolean three times, starting&lt;br /&gt;
from &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Extensionality rules ==&lt;br /&gt;
&lt;br /&gt;
Three further rules are not reductions of the left side to the right but identifications of&lt;br /&gt;
terms that cannot be told apart.&amp;lt;ref name=&amp;quot;refman-ts&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Eta for functions&amp;#039;&amp;#039;&amp;#039;: &amp;lt;math&amp;gt;\lambda x : A.\, f\,x \equiv f&amp;lt;/math&amp;gt;. A function is equal to the abstraction of its own application.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Eta for structures&amp;#039;&amp;#039;&amp;#039;: for a value &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; of a structure type, a non-recursive type with no indices and exactly one constructor &amp;lt;math&amp;gt;\mathrm{mk}&amp;lt;/math&amp;gt;, with fields &amp;lt;math&amp;gt;1, \ldots, n&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;s \equiv \mathrm{mk}\;(s.1)\;\ldots\;(s.n)&amp;lt;/math&amp;gt;. This rule is new in the Lean 4 kernel.&amp;lt;ref name=&amp;quot;lean4lean&amp;quot;&amp;gt;Mario Carneiro, &amp;quot;Lean4Lean: Verifying a Typechecker for Lean, in Lean&amp;quot;, in &amp;#039;&amp;#039;31st International Conference on Types for Proofs and Programs (TYPES 2025)&amp;#039;&amp;#039;, LIPIcs vol. 384, pp. 2:1–2:23, 2026. https://doi.org/10.4230/LIPIcs.TYPES.2025.2 (read in the version arXiv:2403.14064v2)&amp;lt;/ref&amp;gt;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Proof irrelevance&amp;#039;&amp;#039;&amp;#039;: any two proofs of the same proposition are definitionally equal.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{\Gamma \vdash p : \mathrm{Prop} \qquad \Gamma \vdash h : p \qquad \Gamma \vdash h&amp;#039; : p}{\Gamma \vdash h \equiv h&amp;#039;}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;lean lean-cont&amp;quot; style=&amp;quot;background: #f8f9fa; border: 1px solid #c8ccd1; padding: 0.6em; margin: 0.3em 0; font-size: 0.85em; line-height: 1.35; overflow-x: auto; white-space: pre;&amp;quot;&amp;gt;&lt;br /&gt;
example (f : Nat → Nat) : (fun x =&amp;gt; f x) = f := rfl          -- eta, functions&lt;br /&gt;
example (p : Nat × Bool) : (p.1, p.2) = p := rfl              -- eta, structures&lt;br /&gt;
example (p : Prop) (h₁ h₂ : p) : h₁ = h₂ := rfl               -- proof irrelevance&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All three are accepted. None of these rules makes functions equal because they agree on all&lt;br /&gt;
arguments; that is the theorem &amp;lt;code&amp;gt;funext&amp;lt;/code&amp;gt;, a propositional equality.&amp;lt;ref name=&amp;quot;refman-fn&amp;quot;&amp;gt;&amp;#039;&amp;#039;The&lt;br /&gt;
Lean Language Reference&amp;#039;&amp;#039;, for Lean 4.34.0, lean-lang.org, 2026, section 4.1.3,&lt;br /&gt;
&amp;quot;Extensionality&amp;quot;.&lt;br /&gt;
https://lean-lang.org/doc/reference/4.34.0/The-Type-System/Functions/&amp;lt;/ref&amp;gt; Proof&lt;br /&gt;
irrelevance is the rule with the largest consequences, taken up in&lt;br /&gt;
[[Lean theorem prover/Foundations/Proof irrelevance and subsingleton elimination|Proof irrelevance and subsingleton elimination]] and, below, as one source of undecidability.&lt;br /&gt;
&lt;br /&gt;
== Natural-number literals ==&lt;br /&gt;
&lt;br /&gt;
In the logic, &amp;lt;code&amp;gt;Nat&amp;lt;/code&amp;gt; is the inductive type with constructors &amp;lt;code&amp;gt;zero&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;succ&amp;lt;/code&amp;gt;, so the number 1000 is &amp;lt;code&amp;gt;succ&amp;lt;/code&amp;gt; applied a thousand times to&lt;br /&gt;
&amp;lt;code&amp;gt;zero&amp;lt;/code&amp;gt;, and addition defined by recursion would take time proportional to the&lt;br /&gt;
size of its arguments. Lean&amp;#039;s kernel does not compute this way. Natural-number literals are a&lt;br /&gt;
separate kind of term, stored as arbitrary-precision integers, and basic functions such as&lt;br /&gt;
addition, multiplication and comparison are evaluated on them by an arbitrary-precision&lt;br /&gt;
arithmetic library, usually GMP, instead of by unfolding their&lt;br /&gt;
definitions.&amp;lt;ref name=&amp;quot;refman-nat&amp;quot;&amp;gt;&amp;#039;&amp;#039;The Lean Language Reference&amp;#039;&amp;#039;, for Lean 4.34.0,&lt;br /&gt;
lean-lang.org, 2026, section 20.1, &amp;quot;Natural Numbers&amp;quot;.&lt;br /&gt;
https://lean-lang.org/doc/reference/4.34.0/Basic-Types/Natural-Numbers/&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;bailey&amp;quot;&amp;gt;Christopher&lt;br /&gt;
A. Bailey, with contributions from the Lean community, &amp;#039;&amp;#039;Type Checking in Lean 4&amp;#039;&amp;#039; (online&lt;br /&gt;
book), chapters &amp;quot;Weak and strong reduction&amp;quot;, &amp;quot;Definitional Equality&amp;quot; and &amp;quot;Reduction&amp;quot;.&lt;br /&gt;
https://ammkrn.github.io/type_checking_in_lean4/&amp;lt;/ref&amp;gt; When iota reduction needs to&lt;br /&gt;
see a constructor, a literal is presented as &amp;lt;code&amp;gt;zero&amp;lt;/code&amp;gt; or as &amp;lt;code&amp;gt;succ&amp;lt;/code&amp;gt;&lt;br /&gt;
applied to the literal one smaller, and literals compare equal to the corresponding&lt;br /&gt;
constructor terms, so the two forms remain interchangeable.&amp;lt;ref name=&amp;quot;bailey&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;lean lean-cont&amp;quot; style=&amp;quot;background: #f8f9fa; border: 1px solid #c8ccd1; padding: 0.6em; margin: 0.3em 0; font-size: 0.85em; line-height: 1.35; overflow-x: auto; white-space: pre;&amp;quot;&amp;gt;&lt;br /&gt;
theorem big_mul :&lt;br /&gt;
    123456789123456789 * 987654321987654321 = 121932631356500531347203169112635269 := rfl&lt;br /&gt;
theorem pow_mod : 2 ^ 200 % 7 = 4 := by decide&lt;br /&gt;
&lt;br /&gt;
#print axioms big_mul&lt;br /&gt;
#print axioms pow_mod&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Both theorems are accepted, and Lean prints&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;#039;big_mul&amp;#039; does not depend on any axioms&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;#039;pow_mod&amp;#039; does not depend on any axioms&amp;lt;/code&amp;gt;. The 36-digit product was confirmed by&lt;br /&gt;
computation, not by an axiom. The price is trust: the arithmetic primitives are part of the&lt;br /&gt;
Lean kernel, and the reference manual notes that if they did not agree with the definitions of the&lt;br /&gt;
functions they replace, soundness could be undermined.&amp;lt;ref name=&amp;quot;refman-nat&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== How the Lean kernel decides it ==&lt;br /&gt;
&lt;br /&gt;
The Lean kernel decides definitional equality by an algorithm that applies the rules lazily,&lt;br /&gt;
reducing only as far as it must.&amp;lt;ref name=&amp;quot;bailey&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;lean4lean&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Weak head normal form.&amp;#039;&amp;#039;&amp;#039; The basic operation reduces a term at its head only, never&lt;br /&gt;
under a binder that has no argument applied to it, until no beta, iota, zeta, projection or&lt;br /&gt;
delta step applies at the head. The result is the term&amp;#039;s &amp;#039;&amp;#039;&amp;#039;weak head normal form&amp;#039;&amp;#039;&amp;#039;: a&lt;br /&gt;
sort, a function type, an abstraction, a literal, a constructor application, or an&lt;br /&gt;
application whose head is a variable or a constant that cannot be unfolded or reduced&lt;br /&gt;
further.&amp;lt;ref name=&amp;quot;bailey&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Cheap tests.&amp;#039;&amp;#039;&amp;#039; Several tests need little or no reduction: identical terms, sorts with&lt;br /&gt;
equal levels, the same constant at equal universe levels, and, by proof irrelevance, two&lt;br /&gt;
terms whose types are the same proposition. Applications, binders and function types are&lt;br /&gt;
compared component by component.&amp;lt;ref name=&amp;quot;bailey&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Lazy delta.&amp;#039;&amp;#039;&amp;#039; When both sides are headed by definitions, Lean&amp;#039;s kernel does not unfold&lt;br /&gt;
both completely, which would be much less efficient. It unfolds step by step, choosing which side to unfold by a &amp;#039;&amp;#039;&amp;#039;reducibility hint&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
stored with every definition: &amp;lt;code&amp;gt;opaque&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;abbrev&amp;lt;/code&amp;gt;, or&lt;br /&gt;
&amp;lt;code&amp;gt;regular&amp;lt;/code&amp;gt; with a &amp;#039;&amp;#039;&amp;#039;definitional height&amp;#039;&amp;#039;&amp;#039;, one more than the greatest height of&lt;br /&gt;
the &amp;lt;code&amp;gt;regular&amp;lt;/code&amp;gt; definitions its value mentions. Lean can show both the hints and the rule that uses them:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;lean&amp;quot; style=&amp;quot;background: #f8f9fa; border: 1px solid #c8ccd1; padding: 0.6em; margin: 0.3em 0; font-size: 0.85em; line-height: 1.35; overflow-x: auto; white-space: pre;&amp;quot;&amp;gt;&lt;br /&gt;
import Lean&lt;br /&gt;
open Lean Meta&lt;br /&gt;
&lt;br /&gt;
def sq (n : Nat) : Nat := n * n&lt;br /&gt;
def quad (n : Nat) : Nat := sq (sq n)&lt;br /&gt;
abbrev Sq := sq&lt;br /&gt;
&lt;br /&gt;
def showHints : ReducibilityHints → String&lt;br /&gt;
  | .opaque =&amp;gt; &amp;quot;opaque&amp;quot;&lt;br /&gt;
  | .abbrev =&amp;gt; &amp;quot;abbrev&amp;quot;&lt;br /&gt;
  | .regular h =&amp;gt; s!&amp;quot;regular {h}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#eval show MetaM Unit from do&lt;br /&gt;
  for n in [``Nat.mul, ``sq, ``quad, ``Sq] do&lt;br /&gt;
    let some (.defnInfo d) := (← getEnv).find? n | IO.println s!&amp;quot;{n}: not a definition&amp;quot;&lt;br /&gt;
    IO.println s!&amp;quot;{n}: {showHints d.hints}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#eval show MetaM Unit from do&lt;br /&gt;
  IO.println ((← findDocString? (← getEnv) ``ReducibilityHints).getD &amp;quot;none&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first command prints &amp;lt;code&amp;gt;Nat.mul: regular 2&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;sq: regular 4&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;quad: regular 5&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Sq: abbrev&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;quad&amp;lt;/code&amp;gt; is one higher&lt;br /&gt;
than &amp;lt;code&amp;gt;sq&amp;lt;/code&amp;gt;, which it mentions. The second prints the documentation that Lean 4.34.1&lt;br /&gt;
carries for the hints; two passages of it read:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;lean-output&amp;quot; style=&amp;quot;background: #ffffff; border: 1px dashed #a2a9b1; padding: 0.6em; margin: 0.3em 0; font-size: 0.85em; line-height: 1.35; overflow-x: auto; white-space: pre;&amp;quot;&amp;gt;&lt;br /&gt;
* If `f` and `g` have the **same hint kind**:&lt;br /&gt;
  - Both `.opaque` or both `.abbrev`: unfold both.&lt;br /&gt;
  - Both `.regular`: unfold the one with the **greater** height first. If their heights are equal&lt;br /&gt;
    (in particular, if `f` and `g` are the same definition), first try to compare their arguments&lt;br /&gt;
    for definitional equality (short-circuiting the unfolding if they match), then unfold both.&lt;br /&gt;
* If `f` and `g` have **different hint kinds**: unfold the one that is *not* `.opaque`, preferring to&lt;br /&gt;
  unfold `.abbrev` over `.regular`.&lt;br /&gt;
...&lt;br /&gt;
The hints only affect performance — they control the order in which definitions are unfolded, but&lt;br /&gt;
never prevent the kernel from unfolding a definition during type checking.&lt;br /&gt;
&lt;br /&gt;
The `ReducibilityHints` are not related to the `@[reducible]`/`@[irreducible]`/`@[semireducible]`&lt;br /&gt;
attributes. Those attributes are used by the elaborator to control which definitions tactics like&lt;br /&gt;
`simp`, `rfl`, and `dsimp` will unfold; they do not affect the kernel.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Unfolding the higher definition first brings it down towards the lower one, which it is&lt;br /&gt;
built from.&amp;lt;ref name=&amp;quot;bailey&amp;quot; /&amp;gt; Because the attributes do not reach the Lean kernel, a definition marked &amp;lt;code&amp;gt;@[irreducible]&amp;lt;/code&amp;gt;, such as one defined&lt;br /&gt;
by well-founded recursion&lt;br /&gt;
([[Lean theorem prover/Foundations/Structural and well-founded recursion|Structural and well-founded recursion]]), is still unfolded by the Lean kernel when a proof requires it.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Extensionality.&amp;#039;&amp;#039;&amp;#039; When one side is an abstraction and the other is not, Lean&amp;#039;s kernel&lt;br /&gt;
eta-expands the other side; when one side is a structure constructor application, it&lt;br /&gt;
compares the other side field by field through projections. Failures of the congruence step&lt;br /&gt;
are cached, which matters for performance.&amp;lt;ref name=&amp;quot;bailey&amp;quot; /&amp;gt; Lean&amp;#039;s kernel also has depth&lt;br /&gt;
and time limits on some of its operations, so many pathological checks stop with an error&lt;br /&gt;
instead of running for ever.&amp;lt;ref name=&amp;quot;lean4lean&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Undecidability ==&lt;br /&gt;
&lt;br /&gt;
Carneiro models what Lean&amp;#039;s kernel checks as an &amp;#039;&amp;#039;&amp;#039;algorithmic definitional equality&amp;#039;&amp;#039;&amp;#039;,&lt;br /&gt;
written &amp;lt;math&amp;gt;\Leftrightarrow&amp;lt;/math&amp;gt;, and shows that it is sound: for two terms of the same&lt;br /&gt;
type, &amp;lt;math&amp;gt;e \Leftrightarrow e&amp;#039;&amp;lt;/math&amp;gt; implies &amp;lt;math&amp;gt;e \equiv e&amp;#039;&amp;lt;/math&amp;gt;.&amp;lt;ref name=&amp;quot;carneiro2019&amp;quot; /&amp;gt;&lt;br /&gt;
It is not complete, and in Lean&amp;#039;s full theory no algorithm could be.&lt;br /&gt;
&lt;br /&gt;
Carneiro proved in 2019 that definitional equality in Lean&amp;#039;s theory is&lt;br /&gt;
undecidable;&amp;lt;ref name=&amp;quot;carneiro2019&amp;quot; /&amp;gt; Abel and Coquand cite his proof, for the&lt;br /&gt;
accessibility predicate, and draw the consequence that typing is undecidable&lt;br /&gt;
too.&amp;lt;ref name=&amp;quot;abelcoquand&amp;quot; /&amp;gt; The argument uses &amp;lt;code&amp;gt;Acc&amp;lt;/code&amp;gt;, the inductive proposition behind well-founded recursion. Proof irrelevance&lt;br /&gt;
makes any proof &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt; of &amp;lt;math&amp;gt;\mathrm{Acc}\;x&amp;lt;/math&amp;gt; definitionally equal to&lt;br /&gt;
&amp;lt;math&amp;gt;\mathrm{intro}\;x\;(\mathrm{inv}\;a)&amp;lt;/math&amp;gt;, a proof built from the constructor, where&lt;br /&gt;
&amp;lt;math&amp;gt;\mathrm{inv}\;a&amp;lt;/math&amp;gt; extracts from &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt; the accessibility of every element&lt;br /&gt;
below &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; in the relation. Since &amp;lt;code&amp;gt;Acc&amp;lt;/code&amp;gt; has subsingleton elimination, a function into data can be&lt;br /&gt;
defined by recursion on such a proof, and the replacement unlocks one step of iota reduction.&lt;br /&gt;
Carneiro defines a function &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; that, at each step &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, continues while a decidable&lt;br /&gt;
property &amp;lt;math&amp;gt;P\;n&amp;lt;/math&amp;gt; holds and returns a fixed value when it fails, and takes&lt;br /&gt;
&amp;lt;math&amp;gt;P\;n&amp;lt;/math&amp;gt; to say that a given Turing machine has not halted after &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
steps, with the relation &amp;lt;math&amp;gt;&amp;gt;&amp;lt;/math&amp;gt; on the natural numbers. No proof that 0 is&lt;br /&gt;
accessible for &amp;lt;math&amp;gt;&amp;gt;&amp;lt;/math&amp;gt; can exist, but definitional equality must be decided in&lt;br /&gt;
every context, including one that assumes such a proof &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;. In that context the&lt;br /&gt;
chain&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;f\;0\;a \equiv f\;1\;a_1 \equiv f\;2\;a_2 \equiv \cdots&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in which &amp;lt;math&amp;gt;a_0 = a&amp;lt;/math&amp;gt; and each &amp;lt;math&amp;gt;a_{n+1}&amp;lt;/math&amp;gt; is the proof that&lt;br /&gt;
&amp;lt;math&amp;gt;n+1&amp;lt;/math&amp;gt; is accessible which &amp;lt;math&amp;gt;\mathrm{inv}&amp;lt;/math&amp;gt; extracts from&lt;br /&gt;
&amp;lt;math&amp;gt;a_n&amp;lt;/math&amp;gt;, reaches the fixed value exactly when the machine halts. A decision procedure for&lt;br /&gt;
definitional equality would therefore solve the halting problem.&lt;br /&gt;
&lt;br /&gt;
The algorithmic relation is therefore strictly smaller, and it is not transitive. In the&lt;br /&gt;
chain above it accepts&lt;br /&gt;
&amp;lt;math&amp;gt;f\;0\;a \Leftrightarrow f\;0\;(\mathrm{intro}\;0\;(\mathrm{inv}\;a))&amp;lt;/math&amp;gt; by proof&lt;br /&gt;
irrelevance, and&lt;br /&gt;
&amp;lt;math&amp;gt;f\;0\;(\mathrm{intro}\;0\;(\mathrm{inv}\;a)) \Leftrightarrow f\;1\;a_1&amp;lt;/math&amp;gt; by&lt;br /&gt;
reduction, when &amp;lt;math&amp;gt;P\;0&amp;lt;/math&amp;gt; holds, but it does not accept the composite &amp;lt;math&amp;gt;f\;0\;a \Leftrightarrow f\;1\;a_1&amp;lt;/math&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;f\;0\;a&amp;lt;/math&amp;gt; is already in normal form, so the algorithm has nothing to reduce, and the&lt;br /&gt;
intermediate term is a creative choice it does not make. Carneiro gives a second source of non-transitivity, quotients of&lt;br /&gt;
propositions, and shows that with the algorithmic relation in the conversion rule, typing&lt;br /&gt;
loses &amp;#039;&amp;#039;&amp;#039;subject reduction&amp;#039;&amp;#039;&amp;#039;: a term can type-check while a term it reduces to does&lt;br /&gt;
not.&amp;lt;ref name=&amp;quot;carneiro2019&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Normalisation fails too. Abel and Coquand showed that a type theory with an impredicative&lt;br /&gt;
universe of propositions and a proof-irrelevant equality whose elimination does not inspect&lt;br /&gt;
the proof has terms with no normal form. Their counterexample, a version of the&lt;br /&gt;
self-application &amp;lt;math&amp;gt;\Omega&amp;lt;/math&amp;gt;, runs in Lean 3.4.2, and using propositional&lt;br /&gt;
extensionality they gave a closed term, depending on Lean&amp;#039;s standard axioms, that has no weak&lt;br /&gt;
head normal form at all.&amp;lt;ref name=&amp;quot;abelcoquand&amp;quot;&amp;gt;Andreas Abel and Thierry Coquand, &amp;quot;Failure&lt;br /&gt;
of Normalization in Impredicative Type Theory with Proof-Irrelevant Propositional Equality&amp;quot;,&lt;br /&gt;
&amp;#039;&amp;#039;Logical Methods in Computer Science&amp;#039;&amp;#039; 16(2), 2020.&lt;br /&gt;
https://doi.org/10.23638/LMCS-16(2:14)2020&amp;lt;/ref&amp;gt; Carneiro reproduces it in Lean 4, with a&lt;br /&gt;
variant that makes a definitional-equality check on ordinary data fail to&lt;br /&gt;
terminate.&amp;lt;ref name=&amp;quot;lean4lean&amp;quot; /&amp;gt; Lean 4.34.1 accepts the three definitions&lt;br /&gt;
below; asking for the normal form of &amp;lt;code&amp;gt;Om&amp;lt;/code&amp;gt; does not finish:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;lean lean-fails&amp;quot; style=&amp;quot;background: #f8f9fa; border: 1px solid #c8ccd1; padding: 0.6em; margin: 0.3em 0; font-size: 0.85em; line-height: 1.35; overflow-x: auto; white-space: pre;&amp;quot;&amp;gt;&lt;br /&gt;
set_option linter.defProp false&lt;br /&gt;
def True&amp;#039; : Prop := ∀ p : Prop, p → p&lt;br /&gt;
&lt;br /&gt;
def om : True&amp;#039; := fun A a =&amp;gt;&lt;br /&gt;
  @cast (True&amp;#039; → True&amp;#039;) A&lt;br /&gt;
    (propext ⟨fun _ =&amp;gt; a, fun _ =&amp;gt; id⟩)&lt;br /&gt;
    (fun z =&amp;gt; z (True&amp;#039; → True&amp;#039;) id z)&lt;br /&gt;
&lt;br /&gt;
def Om : True&amp;#039; := om (True&amp;#039; → True&amp;#039;) id om&lt;br /&gt;
&lt;br /&gt;
#reduce (proofs := true) Om&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean stops with &amp;lt;code&amp;gt;maximum recursion depth has been reached&amp;lt;/code&amp;gt;. A recursion limit is&lt;br /&gt;
not itself a proof of non-termination; that &amp;lt;code&amp;gt;Om&amp;lt;/code&amp;gt; has no normal form is Abel and&lt;br /&gt;
Coquand&amp;#039;s theorem.&lt;br /&gt;
&lt;br /&gt;
The reference manual states the position plainly. Lean&amp;#039;s type theory lacks subject&lt;br /&gt;
reduction, its definitional equality is not necessarily transitive, and the type checker can&lt;br /&gt;
be made to run for ever. The sources are the ones described above: subsingleton elimination&lt;br /&gt;
and quotients of propositions, combined with definitional proof irrelevance, for the first two&lt;br /&gt;
properties;&amp;lt;ref name=&amp;quot;carneiro2019&amp;quot; /&amp;gt; an impredicative universe of propositions with proof&lt;br /&gt;
irrelevance and propositional extensionality for the third.&amp;lt;ref name=&amp;quot;abelcoquand&amp;quot; /&amp;gt; The&lt;br /&gt;
manual reports that failures of transitivity are exceedingly rare in practice, that, as far as&lt;br /&gt;
its authors know, non-termination has not occurred except in code written to provoke it, and&lt;br /&gt;
that logical soundness is not affected.&amp;lt;ref name=&amp;quot;refman-kernel&amp;quot;&amp;gt;&amp;#039;&amp;#039;The Lean Language Reference&amp;#039;&amp;#039;, for Lean 4.34.0,&lt;br /&gt;
lean-lang.org, 2026, section 2.3, &amp;quot;The Kernel&amp;quot;.&lt;br /&gt;
https://lean-lang.org/doc/reference/4.34.0/Elaboration-and-Compilation/&amp;lt;/ref&amp;gt; The last point&lt;br /&gt;
is the one that matters for checking proofs. These properties make Lean&amp;#039;s kernel incomplete,&lt;br /&gt;
not unsound: their typical effect is a true equality that the Lean kernel cannot confirm in one step,&lt;br /&gt;
which can often be proved instead as a chain of propositional equalities, since&lt;br /&gt;
propositional equality is transitive.&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/Foundations/Propositional equality|Propositional equality]] treats&lt;br /&gt;
equality as a proposition, &amp;lt;code&amp;gt;a = b&amp;lt;/code&amp;gt;, with its own rules, and its relation to the&lt;br /&gt;
definitional equality described here.&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>PMA Publisher</name></author>
	</entry>
</feed>