<?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%2FStructural_and_well-founded_recursion</id>
	<title>Lean theorem prover/Foundations/Structural and well-founded recursion - 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%2FStructural_and_well-founded_recursion"/>
	<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Foundations/Structural_and_well-founded_recursion&amp;action=history"/>
	<updated>2026-10-21T11:13: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/Structural_and_well-founded_recursion&amp;diff=6778&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/Structural_and_well-founded_recursion&amp;diff=6778&amp;oldid=prev"/>
		<updated>2026-10-15T19:34:51Z</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:Structural and well-founded recursion}}&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:Structural and well-founded recursion}}&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/Functions that always finish|Lean theorem prover/Explainers/Induction, as the machine sees it}}&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/Functions that always finish|Lean theorem prover/Explainers/Induction, as the machine sees it}}&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;Lean lets a function be defined by calling itself, but Lean&amp;#039;s kernel knows nothing 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;Lean lets a function be defined by calling itself, but Lean&amp;#039;s kernel knows nothing 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/Structural_and_well-founded_recursion&amp;diff=6571&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/Structural_and_well-founded_recursion&amp;diff=6571&amp;oldid=prev"/>
		<updated>2026-10-14T18:00:59Z</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:Structural and well-founded recursion}}&lt;br /&gt;
{{Plebeian|Lean theorem prover/Explainers/Functions that always finish|Lean theorem prover/Explainers/Induction, as the machine sees it}}&lt;br /&gt;
&lt;br /&gt;
Lean lets a function be defined by calling itself, but Lean&amp;#039;s kernel knows nothing of&lt;br /&gt;
recursive definitions. Before a recursive definition reaches the Lean kernel, the elaborator&lt;br /&gt;
replaces the recursion by a non-recursive term built from recursors or from a well-founded&lt;br /&gt;
fixed-point combinator, and the fact that this translation succeeds is the proof that the&lt;br /&gt;
function terminates. This page explains why unrestricted recursion is not allowed, how&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;structural recursion&amp;#039;&amp;#039;&amp;#039; is compiled through the recursor, how &amp;#039;&amp;#039;&amp;#039;well-founded recursion&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
is compiled through &amp;lt;code&amp;gt;WellFounded.fix&amp;lt;/code&amp;gt;, what &amp;lt;code&amp;gt;termination_by&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;decreasing_by&amp;lt;/code&amp;gt; control, how &amp;lt;code&amp;gt;partial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;unsafe&amp;lt;/code&amp;gt;&lt;br /&gt;
definitions are kept from compromising the logic, and the induction principles Lean derives from a&lt;br /&gt;
recursive definition.&lt;br /&gt;
&lt;br /&gt;
== Why recursion must be checked ==&lt;br /&gt;
&lt;br /&gt;
If any recursive equation were accepted as a definition, the logic would be inconsistent. The&lt;br /&gt;
equation &amp;lt;code&amp;gt;f n = f n + 1&amp;lt;/code&amp;gt; would define a natural-number function with the absurd&lt;br /&gt;
property that a number equals its successor; and a function into the empty type&lt;br /&gt;
&amp;lt;code&amp;gt;Empty&amp;lt;/code&amp;gt; that simply calls itself would produce an element of a type with no&lt;br /&gt;
elements, from which anything follows. A proof that &amp;quot;P holds because P holds&amp;quot; would be&lt;br /&gt;
accepted.&amp;lt;ref name=&amp;quot;refman-rec&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 7.6, &amp;quot;Recursive Definitions&amp;quot;.&lt;br /&gt;
https://lean-lang.org/doc/reference/4.34.0/Definitions/Recursive-Definitions/&amp;lt;/ref&amp;gt; Lean&amp;#039;s&lt;br /&gt;
logic therefore treats every function as &amp;#039;&amp;#039;&amp;#039;total&amp;#039;&amp;#039;&amp;#039;: defined on every argument and&lt;br /&gt;
returning in finitely many steps.&amp;lt;ref name=&amp;quot;refman-fn&amp;quot;&amp;gt;&amp;#039;&amp;#039;The Lean Language Reference&amp;#039;&amp;#039;, for&lt;br /&gt;
Lean 4.34.0, lean-lang.org, 2026, section 4.1, &amp;quot;Functions&amp;quot;.&lt;br /&gt;
https://lean-lang.org/doc/reference/4.34.0/The-Type-System/Functions/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Termination is not checked by Lean&amp;#039;s kernel, which has no termination checker; it is&lt;br /&gt;
guaranteed because every recursive function is elaborated into uses of primitive&lt;br /&gt;
recursors, which cannot loop.&amp;lt;ref name=&amp;quot;refman-elab&amp;quot;&amp;gt;&amp;#039;&amp;#039;The Lean Language Reference&amp;#039;&amp;#039;, for&lt;br /&gt;
Lean 4.34.0, lean-lang.org, 2026, sections 2.3, &amp;quot;The Kernel&amp;quot;, and 2.4, &amp;quot;Elaboration&lt;br /&gt;
Results&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/Elaboration-and-Compilation/&amp;lt;/ref&amp;gt;&lt;br /&gt;
Elaboration proceeds in two phases. First the definition is elaborated as if the core&lt;br /&gt;
language had recursion, giving a &amp;#039;&amp;#039;&amp;#039;pre-definition&amp;#039;&amp;#039;&amp;#039;; the compiler generates code from&lt;br /&gt;
it unchanged. Then a termination analysis translates the pre-definition into a non-recursive&lt;br /&gt;
term for the Lean kernel. Without an explicit instruction the elaborator tries structural recursion&lt;br /&gt;
on each argument in turn, and then searches for a decreasing measure for well-founded&lt;br /&gt;
recursion.&amp;lt;ref name=&amp;quot;refman-rec&amp;quot; /&amp;gt; The reference manual also describes partial fixpoints and&lt;br /&gt;
predicates defined as least or greatest fixed points; this page does not treat them.&lt;br /&gt;
&lt;br /&gt;
== Structural recursion ==&lt;br /&gt;
&lt;br /&gt;
A definition is &amp;#039;&amp;#039;&amp;#039;structurally recursive&amp;#039;&amp;#039;&amp;#039; when every recursive call is on a strict&lt;br /&gt;
sub-term of one fixed argument, the &amp;#039;&amp;#039;&amp;#039;decreasing parameter&amp;#039;&amp;#039;&amp;#039;, as exposed by pattern&lt;br /&gt;
matching.&amp;lt;ref name=&amp;quot;refman-rec&amp;quot; /&amp;gt; The Fibonacci function is a standard example:&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 fib : Nat → Nat&lt;br /&gt;
  | 0 =&amp;gt; 0&lt;br /&gt;
  | 1 =&amp;gt; 1&lt;br /&gt;
  | n + 2 =&amp;gt; fib n + fib (n + 1)&lt;br /&gt;
&lt;br /&gt;
#print fib&lt;br /&gt;
example : fib 10 = 55 := rfl&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean 4.34.1 prints the term the Lean kernel received:&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;
def fib : Nat → Nat :=&lt;br /&gt;
fun x =&amp;gt; Nat.brecOn x fib._f&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is no self-reference. The recursion has become an application of&lt;br /&gt;
&amp;lt;code&amp;gt;Nat.brecOn&amp;lt;/code&amp;gt;, and the cases of the definition are in an auxiliary function&lt;br /&gt;
&amp;lt;code&amp;gt;fib._f&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;fib&amp;lt;/code&amp;gt; calls itself on &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;, two steps below its argument, so the plain&lt;br /&gt;
recursor, whose step function sees only the result for the immediate predecessor, does not fit&lt;br /&gt;
directly. The elaborator uses two constructions derived from the recursor instead. For a&lt;br /&gt;
motive &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Nat.below t&amp;lt;/code&amp;gt; is a table holding a value of&lt;br /&gt;
&amp;lt;code&amp;gt;C k&amp;lt;/code&amp;gt; for every &amp;lt;code&amp;gt;k&amp;lt;/code&amp;gt; smaller than &amp;lt;code&amp;gt;t&amp;lt;/code&amp;gt;, built as an iterated&lt;br /&gt;
pair; &amp;lt;code&amp;gt;Nat.brecOn&amp;lt;/code&amp;gt; is a recursor whose step function receives that whole table, so&lt;br /&gt;
it can use the result for any smaller argument. This is &amp;#039;&amp;#039;&amp;#039;course-of-values recursion&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
Lean generates &amp;lt;code&amp;gt;below&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;brecOn&amp;lt;/code&amp;gt; for every inductive type, following&lt;br /&gt;
McBride, Goguen and McKinna.&amp;lt;ref name=&amp;quot;refman-ind&amp;quot;&amp;gt;&amp;#039;&amp;#039;The Lean Language Reference&amp;#039;&amp;#039;, for Lean&lt;br /&gt;
4.34.0, lean-lang.org, 2026, section 4.4.3.3, &amp;quot;Constructions for Termination Checking&amp;quot;.&lt;br /&gt;
https://lean-lang.org/doc/reference/4.34.0/The-Type-System/Inductive-Types/&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;mgm&amp;quot;&amp;gt;Conor&lt;br /&gt;
McBride, Healfdene Goguen and James McKinna, &amp;quot;A Few Constructions on Constructors&amp;quot;, in&lt;br /&gt;
&amp;#039;&amp;#039;Types for Proofs and Programs&amp;#039;&amp;#039; (TYPES 2004), Lecture Notes in Computer Science 3839,&lt;br /&gt;
Springer, 2006, pp. 186–200. https://doi.org/10.1007/11617990_12&amp;lt;/ref&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;
#check @Nat.brecOn&lt;br /&gt;
#print fib._f&lt;br /&gt;
&amp;lt;/pre&amp;gt;&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;
@Nat.brecOn : {motive : Nat → Sort u_1} → (t : Nat) → ((t : Nat) → Nat.below t → motive t) → motive t&lt;br /&gt;
@[reducible] def fib._f : (x : Nat) → Nat.below x → Nat :=&lt;br /&gt;
fun x f =&amp;gt;&lt;br /&gt;
  (match (motive := (x : Nat) → Nat.below x → Nat) x with&lt;br /&gt;
    | 0 =&amp;gt; fun x =&amp;gt; 0&lt;br /&gt;
    | 1 =&amp;gt; fun x =&amp;gt; 1&lt;br /&gt;
    | n.succ.succ =&amp;gt; fun x =&amp;gt; x.2.1 + x.1)&lt;br /&gt;
    f&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the last case the two recursive calls have become two lookups in the table:&lt;br /&gt;
&amp;lt;code&amp;gt;x.1&amp;lt;/code&amp;gt; is the entry for &amp;lt;code&amp;gt;n + 1&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;x.2.1&amp;lt;/code&amp;gt; the entry for&lt;br /&gt;
&amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;. Because &amp;lt;code&amp;gt;brecOn&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;below&amp;lt;/code&amp;gt; are themselves defined from&lt;br /&gt;
&amp;lt;code&amp;gt;Nat.rec&amp;lt;/code&amp;gt;, the whole definition reduces by the ordinary rules of definitional&lt;br /&gt;
equality, which is why &amp;lt;code&amp;gt;fib 10 = 55&amp;lt;/code&amp;gt; holds by &amp;lt;code&amp;gt;rfl&amp;lt;/code&amp;gt;. Structurally&lt;br /&gt;
recursive functions compute inside Lean&amp;#039;s kernel, and their defining equations hold&lt;br /&gt;
definitionally.&amp;lt;ref name=&amp;quot;refman-elab&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The analysis is syntactic, so some terminating functions fail it. A function that tests&lt;br /&gt;
&amp;lt;code&amp;gt;n == 0&amp;lt;/code&amp;gt; and recurses on &amp;lt;code&amp;gt;n - 1&amp;lt;/code&amp;gt; terminates, but &amp;lt;code&amp;gt;n - 1&amp;lt;/code&amp;gt; is&lt;br /&gt;
not exposed as a sub-term by any pattern match, so it is not structural; such functions need&lt;br /&gt;
well-founded recursion.&amp;lt;ref name=&amp;quot;refman-rec&amp;quot; /&amp;gt; The clause&lt;br /&gt;
&amp;lt;code&amp;gt;termination_by structural x&amp;lt;/code&amp;gt; names the decreasing parameter explicitly and&lt;br /&gt;
forbids the fallback.&lt;br /&gt;
&lt;br /&gt;
The term built from &amp;lt;code&amp;gt;brecOn&amp;lt;/code&amp;gt; is not what runs. Compiled code is generated from the&lt;br /&gt;
pre-definition with ordinary recursion; the recursor-based term exists to justify&lt;br /&gt;
termination, not to be executed.&amp;lt;ref name=&amp;quot;refman-elab&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;refman-ind&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Well-founded recursion ==&lt;br /&gt;
&lt;br /&gt;
A relation &amp;lt;math&amp;gt;\prec&amp;lt;/math&amp;gt; is &amp;#039;&amp;#039;&amp;#039;well-founded&amp;#039;&amp;#039;&amp;#039; when there is no infinite descending chain&lt;br /&gt;
&amp;lt;math&amp;gt;x_0 \succ x_1 \succ x_2 \succ \cdots&amp;lt;/math&amp;gt;. Lean states this through the accessibility&lt;br /&gt;
predicate &amp;lt;code&amp;gt;Acc&amp;lt;/code&amp;gt;, an inductive proposition: &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt; is accessible when every&lt;br /&gt;
&amp;lt;code&amp;gt;y ≺ x&amp;lt;/code&amp;gt; is accessible, and a relation is well-founded when every element is&lt;br /&gt;
accessible.&amp;lt;ref name=&amp;quot;refman-rec&amp;quot; /&amp;gt; A function whose arguments decrease along a well-founded&lt;br /&gt;
relation at every recursive call can be defined with the fixed-point combinator&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;
#check @WellFounded.fix&lt;br /&gt;
&amp;lt;/pre&amp;gt;&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;
@WellFounded.fix : {α : Sort u_1} →&lt;br /&gt;
  {C : α → Sort u_2} → {r : α → α → Prop} → WellFounded r → ((x : α) → ((y : α) → r y x → C y) → C x) → (x : α) → C x&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Its step function receives the current argument &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt; and a function that may be&lt;br /&gt;
called only on arguments &amp;lt;code&amp;gt;y&amp;lt;/code&amp;gt; accompanied by a proof of &amp;lt;code&amp;gt;r y x&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;code&amp;gt;WellFounded.fix&amp;lt;/code&amp;gt; is defined through an auxiliary function,&lt;br /&gt;
&amp;lt;code&amp;gt;WellFounded.fixF&amp;lt;/code&amp;gt;, that takes the accessibility proof as an explicit argument:&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;
#print WellFounded.fixF&lt;br /&gt;
&amp;lt;/pre&amp;gt;&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;
def WellFounded.fixF.{u, v} : {α : Sort u} →&lt;br /&gt;
  {r : α → α → Prop} → {C : α → Sort v} → ((x : α) → ((y : α) → r y x → C y) → C x) → (x : α) → Acc r x → C x :=&lt;br /&gt;
fun {α} {r} {C} F x a =&amp;gt; Acc.rec (fun x₁ h ih =&amp;gt; F x₁ ih) a&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Its body is one application of &amp;lt;code&amp;gt;Acc.rec&amp;lt;/code&amp;gt;, the recursor of the accessibility&lt;br /&gt;
predicate. Well-founded recursion is therefore structural recursion again, on a proof that&lt;br /&gt;
the arguments decrease rather than on the data.&amp;lt;ref name=&amp;quot;refman-elab&amp;quot; /&amp;gt; A&lt;br /&gt;
function&amp;#039;s several arguments are packed into a single dependent pair, the relation is pulled&lt;br /&gt;
back from the measure with &amp;lt;code&amp;gt;invImage&amp;lt;/code&amp;gt;, and each recursive call is given its proof&lt;br /&gt;
of decrease.&amp;lt;ref name=&amp;quot;refman-rec&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The measure is given with &amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;termination_by&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039; and the proofs of decrease with&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;decreasing_by&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039;:&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 log2 (n : Nat) : Nat :=&lt;br /&gt;
  if h : n &amp;amp;lt; 2 then 0 else 1 + log2 (n / 2)&lt;br /&gt;
termination_by n&lt;br /&gt;
decreasing_by omega&lt;br /&gt;
&lt;br /&gt;
#eval log2 1024&lt;br /&gt;
#print log2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The evaluation prints &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;#print&amp;lt;/code&amp;gt; shows&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;
@[irreducible] def log2 : Nat → Nat :=&lt;br /&gt;
WellFounded.Nat.fix (fun x =&amp;gt; x) fun n a =&amp;gt; if h : n &amp;amp;lt; 2 then 0 else 1 + a (n / 2) ⋯&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The recursive call &amp;lt;code&amp;gt;log2 (n / 2)&amp;lt;/code&amp;gt; has become &amp;lt;code&amp;gt;a (n / 2) ⋯&amp;lt;/code&amp;gt;, where&lt;br /&gt;
&amp;lt;code&amp;gt;⋯&amp;lt;/code&amp;gt; stands for the proof, produced by &amp;lt;code&amp;gt;omega&amp;lt;/code&amp;gt;, that&lt;br /&gt;
&amp;lt;code&amp;gt;n / 2 &amp;amp;lt; n&amp;lt;/code&amp;gt; in the branch where &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt; is at least 2. Here the measure&lt;br /&gt;
is a natural number, and since Lean 4.27.0 such definitions use&lt;br /&gt;
&amp;lt;code&amp;gt;WellFounded.Nat.fix&amp;lt;/code&amp;gt;, a variant whose recursion runs on a natural-number &amp;quot;fuel&amp;quot;&lt;br /&gt;
argument initialised from the measure, which makes the definitions easier to&lt;br /&gt;
evaluate.&amp;lt;ref name=&amp;quot;rel427&amp;quot;&amp;gt;&amp;#039;&amp;#039;The Lean Language Reference&amp;#039;&amp;#039;, for Lean 4.34.0, lean-lang.org,&lt;br /&gt;
2026, release notes, &amp;quot;Lean 4.27.0&amp;quot;, section &amp;quot;Language&amp;quot;.&lt;br /&gt;
https://lean-lang.org/doc/reference/4.34.0/releases/v4.27.0/&amp;lt;/ref&amp;gt; For other measures, such&lt;br /&gt;
as a pair of numbers compared lexicographically, the elaborator produces a term built on&lt;br /&gt;
&amp;lt;code&amp;gt;WellFounded.fix&amp;lt;/code&amp;gt; directly. When &amp;lt;code&amp;gt;decreasing_by&amp;lt;/code&amp;gt; is omitted a default&lt;br /&gt;
tactic tries to prove each obligation.&amp;lt;ref name=&amp;quot;refman-rec&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;@[irreducible]&amp;lt;/code&amp;gt; attribute is the visible difference from structural&lt;br /&gt;
recursion. Definitions by well-founded recursion are irreducible by default, so the&lt;br /&gt;
elaborator will not unfold them while checking definitional equality, and an equation that&lt;br /&gt;
would follow by computation is not accepted by &amp;lt;code&amp;gt;rfl&amp;lt;/code&amp;gt;:&amp;lt;ref name=&amp;quot;refman-rec&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;lean lean-cont 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;
example : log2 8 = 3 := rfl&lt;br /&gt;
&amp;lt;/pre&amp;gt;&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;
Type mismatch&lt;br /&gt;
  rfl&lt;br /&gt;
has type&lt;br /&gt;
  ?m.7 = ?m.7&lt;br /&gt;
but is expected to have type&lt;br /&gt;
  log2 8 = 3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The equation is still true, and Lean proves the defining equation as a theorem,&lt;br /&gt;
&amp;lt;code&amp;gt;log2.eq_1&amp;lt;/code&amp;gt;, so that &amp;lt;code&amp;gt;simp [log2]&amp;lt;/code&amp;gt; can rewrite with it and prove the&lt;br /&gt;
example. Even when the reductions do hold definitionally, they may be slow in the&lt;br /&gt;
Lean kernel, which must unfold the proof of termination along with the definition. The reference&lt;br /&gt;
manual&amp;#039;s advice is to use structural recursion, where possible, for functions meant for use&lt;br /&gt;
in types or wherever definitional equality matters.&amp;lt;ref name=&amp;quot;refman-rec&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Functional induction ==&lt;br /&gt;
&lt;br /&gt;
A recursive definition determines an induction principle that follows its own case split and&lt;br /&gt;
recursive calls. Since Lean 4.8.0 the elaborator derives it automatically, as a theorem named&lt;br /&gt;
&amp;lt;code&amp;gt;f.induct&amp;lt;/code&amp;gt; for a recursive function &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt;.&amp;lt;ref name=&amp;quot;rel48&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, release notes, &amp;quot;Lean 4.8.0&amp;quot;&lt;br /&gt;
(functional induction principles) and &amp;quot;Lean 4.18.0&amp;quot; (the &amp;lt;code&amp;gt;fun_induction&amp;lt;/code&amp;gt; tactic).&lt;br /&gt;
https://lean-lang.org/doc/reference/4.34.0/releases/v4.8.0/ and&lt;br /&gt;
https://lean-lang.org/doc/reference/4.34.0/releases/v4.18.0/&amp;lt;/ref&amp;gt; It exists for the&lt;br /&gt;
structurally recursive &amp;lt;code&amp;gt;fib&amp;lt;/code&amp;gt; as well as for the well-founded&lt;br /&gt;
&amp;lt;code&amp;gt;log2&amp;lt;/code&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;
#check @fib.induct&lt;br /&gt;
#check @log2.induct&lt;br /&gt;
&lt;br /&gt;
theorem log2_le (n : Nat) : log2 n ≤ n := by&lt;br /&gt;
  fun_induction log2 n with&lt;br /&gt;
  | case1 n h =&amp;gt; simp&lt;br /&gt;
  | case2 n h ih =&amp;gt; omega&lt;br /&gt;
&amp;lt;/pre&amp;gt;&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;
fib.induct : ∀ (motive : Nat → Prop),&lt;br /&gt;
  motive 0 → motive 1 → (∀ (n : Nat), motive n → motive (n + 1) → motive n.succ.succ) → ∀ (a : Nat), motive a&lt;br /&gt;
log2.induct : ∀ (motive : Nat → Prop),&lt;br /&gt;
  (∀ (x : Nat), x &amp;amp;lt; 2 → motive x) → (∀ (x : Nat), ¬x &amp;amp;lt; 2 → motive (x / 2) → motive x) → ∀ (n : Nat), motive n&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each principle has one case for each branch of its function. For &amp;lt;code&amp;gt;fib&amp;lt;/code&amp;gt; the&lt;br /&gt;
recursive case has two induction hypotheses, one per recursive call: the two-step&lt;br /&gt;
induction that the definition needs, which ordinary induction on &amp;lt;code&amp;gt;Nat&amp;lt;/code&amp;gt; does not&lt;br /&gt;
supply directly. For &amp;lt;code&amp;gt;log2&amp;lt;/code&amp;gt; the recursive branch&lt;br /&gt;
carries an induction hypothesis for exactly the argument of the recursive call,&lt;br /&gt;
&amp;lt;code&amp;gt;x / 2&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;fun_induction&amp;lt;/code&amp;gt; tactic, added in Lean 4.18.0, applies it to&lt;br /&gt;
a goal about &amp;lt;code&amp;gt;log2 n&amp;lt;/code&amp;gt;.&amp;lt;ref name=&amp;quot;rel48&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Partial and unsafe definitions ==&lt;br /&gt;
&lt;br /&gt;
Two modifiers admit definitions that are not shown to terminate, and both prevent them from&lt;br /&gt;
compromising proofs.&amp;lt;ref name=&amp;quot;refman-rec&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A &amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;partial&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039; definition is checked by the Lean kernel for type-correctness as if&lt;br /&gt;
recursion were allowed, and then enters the logic as an &amp;#039;&amp;#039;&amp;#039;opaque constant&amp;#039;&amp;#039;&amp;#039;: a constant&lt;br /&gt;
with a type and no definition the Lean kernel may unfold. The compiler still produces ordinary&lt;br /&gt;
code for it.&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;
partial def collatz (n : Nat) : Nat :=&lt;br /&gt;
  if n ≤ 1 then 0 else 1 + collatz (if n % 2 = 0 then n / 2 else 3 * n + 1)&lt;br /&gt;
&lt;br /&gt;
#eval collatz 27&lt;br /&gt;
#print collatz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean prints &amp;lt;code&amp;gt;111&amp;lt;/code&amp;gt; and then &amp;lt;code&amp;gt;opaque collatz : Nat → Nat&amp;lt;/code&amp;gt;. Whether this&lt;br /&gt;
function terminates on every input is the open Collatz problem. A partial function may&lt;br /&gt;
appear in propositions and proofs, but its equational theory is very weak: no property of its&lt;br /&gt;
values that depends on its definition can be proved, because the logic sees no&lt;br /&gt;
definition.&amp;lt;ref name=&amp;quot;refman-rec&amp;quot; /&amp;gt; Even unfolding it fails:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;lean lean-cont 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;
example : collatz 1 = 0 := by unfold collatz; rfl&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean reports &amp;lt;code&amp;gt;Tactic `unfold` failed to unfold `collatz` in&amp;lt;/code&amp;gt; followed by the goal,&lt;br /&gt;
&amp;lt;code&amp;gt;collatz 1 = 0&amp;lt;/code&amp;gt;. For the same reason a partial function&amp;#039;s result type must be shown to be inhabited.&lt;br /&gt;
Otherwise a partial function into &amp;lt;code&amp;gt;Empty&amp;lt;/code&amp;gt; would be an opaque constant producing an&lt;br /&gt;
element of an empty type, and so a proof of anything:&amp;lt;ref name=&amp;quot;refman-rec&amp;quot; /&amp;gt;&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;
partial def loop (n : Nat) : Empty := loop (n + 1)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
is rejected: &amp;lt;code&amp;gt;failed to compile &amp;#039;partial&amp;#039; definition `loop`, could not prove that the&lt;br /&gt;
type Nat → Empty is nonempty&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
An &amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;unsafe&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039; definition has none of these restrictions. It may recurse freely,&lt;br /&gt;
its type need not be inhabited, and it may use operations, such as unchecked casts between&lt;br /&gt;
types, that break the equational theory. In exchange it may be used only by other&lt;br /&gt;
&amp;lt;code&amp;gt;unsafe&amp;lt;/code&amp;gt; definitions, and never in a theorem:&amp;lt;ref name=&amp;quot;refman-rec&amp;quot; /&amp;gt;&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;
unsafe def spin (n : Nat) : Empty := spin (n + 1)&lt;br /&gt;
&lt;br /&gt;
theorem oops : False := (spin 0).elim&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean reports &amp;lt;code&amp;gt;(kernel) invalid declaration, it uses unsafe declaration &amp;#039;spin&amp;#039;&amp;lt;/code&amp;gt;.&lt;br /&gt;
The prefix shows that the refusal is made by Lean&amp;#039;s kernel itself, so it does not depend on&lt;br /&gt;
the elaborator being correct.&lt;br /&gt;
&amp;lt;code&amp;gt;partial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;unsafe&amp;lt;/code&amp;gt; thus mark the boundary between Lean as a&lt;br /&gt;
programming language, where non-termination is a fact of life, and Lean as a logic, where it&lt;br /&gt;
would be a contradiction.&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/Foundations/Definitional equality|Definitional equality]] describes the&lt;br /&gt;
computation rules that structural recursion relies on and that irreducible definitions&lt;br /&gt;
withhold, and how Lean&amp;#039;s kernel decides them.&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>