<?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%2FSystem%2FThe_compiler_and_runtime</id>
	<title>Lean theorem prover/System/The compiler and runtime - 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%2FSystem%2FThe_compiler_and_runtime"/>
	<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/System/The_compiler_and_runtime&amp;action=history"/>
	<updated>2026-10-21T09:17:53Z</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/System/The_compiler_and_runtime&amp;diff=6794&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/System/The_compiler_and_runtime&amp;diff=6794&amp;oldid=prev"/>
		<updated>2026-10-15T19:35:16Z</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:35, 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:The compiler and runtime}}&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:The compiler and runtime}}&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/Programs and proofs in one language}}&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/Programs and proofs in one language}}&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;A Lean definition is used in two ways. The Lean kernel checks it as a term of the type theory,&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;A Lean definition is used in two ways. The Lean kernel checks it as a term of the type theory,&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/System/The_compiler_and_runtime&amp;diff=6587&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/System/The_compiler_and_runtime&amp;diff=6587&amp;oldid=prev"/>
		<updated>2026-10-14T18:01:09Z</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:The compiler and runtime}}&lt;br /&gt;
{{Plebeian|Lean theorem prover/Explainers/Programs and proofs in one language}}&lt;br /&gt;
&lt;br /&gt;
A Lean definition is used in two ways. The Lean kernel checks it as a term of the type theory,&lt;br /&gt;
and the compiler turns it into machine code that runs. The two paths start from the same&lt;br /&gt;
definition and, except in the cases described at the end of this page, do not meet again.&lt;br /&gt;
This page follows the second path in Lean 4.34.1: from a definition through the compiler&amp;#039;s&lt;br /&gt;
intermediate representations to C, the run-time system&amp;#039;s reference counting and its updates&lt;br /&gt;
in place, the attributes that let compiled code differ from the definition the Lean kernel&lt;br /&gt;
sees, and what all of this adds to what has to be trusted.&lt;br /&gt;
&lt;br /&gt;
== Two consumers of one definition ==&lt;br /&gt;
&lt;br /&gt;
When a definition is elaborated, the result goes two ways. The compiler receives it with its&lt;br /&gt;
recursion intact; the Lean kernel receives a version in which recursion has been expressed&lt;br /&gt;
through recursors or well-founded recursion and can be checked.&amp;lt;ref name=&amp;quot;rm-ec&amp;quot;&amp;gt;&amp;quot;Elaboration and Compilation&amp;quot;, a chapter of &amp;#039;&amp;#039;The Lean Language Reference&amp;#039;&amp;#039; (edition covering Lean 4.34.0), sections &amp;quot;Elaboration Results&amp;quot; and &amp;quot;Compilation&amp;quot;. [https://lean-lang.org/doc/reference/4.34.0/Elaboration-and-Compilation/ lean-lang.org/doc/reference/4.34.0/Elaboration-and-Compilation/]&amp;lt;/ref&amp;gt;&lt;br /&gt;
Before generating code, the compiler erases proofs, which have no run-time&lt;br /&gt;
content.&amp;lt;ref name=&amp;quot;cade&amp;quot;&amp;gt;Leonardo de Moura and Sebastian Ullrich, &amp;quot;The Lean 4 Theorem Prover and Programming Language (System Description)&amp;quot;, in &amp;#039;&amp;#039;Automated Deduction: CADE 28&amp;#039;&amp;#039;, Lecture Notes in Computer Science 12699, Springer, 2021, pp. 625–635, section 3. doi:[https://doi.org/10.1007/978-3-030-79876-5_37 10.1007/978-3-030-79876-5_37]; author&amp;#039;s copy [https://lean-lang.org/papers/lean4.pdf lean-lang.org/papers/lean4.pdf].&amp;lt;/ref&amp;gt;&lt;br /&gt;
The compiled code is never shown to the Lean kernel. A theorem about a function is a theorem&lt;br /&gt;
about the definition; that the machine code computes the same function is a property of the&lt;br /&gt;
compiler, not something the Lean kernel has checked.&lt;br /&gt;
&lt;br /&gt;
== From definitions to C ==&lt;br /&gt;
&lt;br /&gt;
Lean&amp;#039;s notes for version 4.22.0, of 14 August 2025, state that &amp;quot;the old compiler has been&lt;br /&gt;
replaced by the new compiler&amp;quot;.&amp;lt;ref name=&amp;quot;rn422&amp;quot;&amp;gt;&amp;quot;Lean 4.22.0&amp;quot;, in &amp;quot;Release Notes&amp;quot;, &amp;#039;&amp;#039;The Lean Language Reference&amp;#039;&amp;#039; (edition covering Lean 4.34.0), Highlights, &amp;quot;New compiler&amp;quot;. [https://lean-lang.org/doc/reference/4.34.0/releases/v4.22.0/ lean-lang.org/doc/reference/4.34.0/releases/v4.22.0/]&amp;lt;/ref&amp;gt;&lt;br /&gt;
In 4.34.1 that compiler, written in Lean, is the one in use. It works in stages:&lt;br /&gt;
&lt;br /&gt;
# The elaborated definition is translated into &amp;#039;&amp;#039;&amp;#039;LCNF&amp;#039;&amp;#039;&amp;#039;, the Lean Compiler Normal Form, a representation in A-normal form in which every intermediate result is bound to a name.&amp;lt;ref name=&amp;quot;lcnf&amp;quot;&amp;gt;Module documentation of &amp;lt;code&amp;gt;Lean.Compiler.LCNF.Basic&amp;lt;/code&amp;gt;, &amp;quot;Lean Compiler Normal Form (LCNF)&amp;quot;, Lean API documentation. [https://lean-lang.org/doc/api/Lean/Compiler/LCNF/Basic.html lean-lang.org/doc/api/Lean/Compiler/LCNF/Basic.html]&amp;lt;/ref&amp;gt;&lt;br /&gt;
# Later passes, still over LCNF, make allocation, reference-count updates and memory reuse explicit instructions. The result is also translated into the compiler&amp;#039;s &amp;#039;&amp;#039;&amp;#039;IR&amp;#039;&amp;#039;&amp;#039;, the form that Lean prints on request (below).&amp;lt;ref name=&amp;quot;src-compiler&amp;quot;&amp;gt;Lean 4 source code, version 4.34.1 (2026), directory &amp;lt;code&amp;gt;src/Lean/Compiler/LCNF&amp;lt;/code&amp;gt;: in &amp;lt;code&amp;gt;Passes.lean&amp;lt;/code&amp;gt; the passes of the impure phase (&amp;lt;code&amp;gt;insertResetReuse&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;inferBorrow&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;explicitBoxing&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;explicitRc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;expandResetReuse&amp;lt;/code&amp;gt;), in &amp;lt;code&amp;gt;Main.lean&amp;lt;/code&amp;gt; the translation of their result to IR (&amp;lt;code&amp;gt;IR.toIR&amp;lt;/code&amp;gt;), and &amp;lt;code&amp;gt;EmitC.lean&amp;lt;/code&amp;gt;, which emits C. Apache License 2.0. https://github.com/leanprover/lean4/tree/v4.34.1/src/Lean/Compiler/LCNF&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;rm-rc&amp;quot;&amp;gt;&amp;quot;Reference Counting&amp;quot;, section 12.2 of &amp;#039;&amp;#039;The Lean Language Reference&amp;#039;&amp;#039; (edition covering Lean 4.34.0), including 12.2.2 &amp;quot;Compiler IR&amp;quot;. [https://lean-lang.org/doc/reference/4.34.0/Run-Time-Code/Reference-Counting/ lean-lang.org/doc/reference/4.34.0/Run-Time-Code/Reference-Counting/]&amp;lt;/ref&amp;gt;&lt;br /&gt;
# The same result is emitted as C. Each Lean module becomes a C file, which a C compiler shipped with Lean compiles to native code.&amp;lt;ref name=&amp;quot;src-compiler&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;rm-ec&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When Lean evaluates code while processing a file, as &amp;lt;code&amp;gt;#eval&amp;lt;/code&amp;gt; does, an&lt;br /&gt;
interpreter runs the IR, and switches to native code for any function that has been&lt;br /&gt;
compiled ahead of time, which includes the standard library.&amp;lt;ref name=&amp;quot;cade&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;rm-ec&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The IR of a definition can be printed. This function adds one to every element of a list.&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;
set_option trace.compiler.ir.result true in&lt;br /&gt;
def incAll : List Nat → List Nat&lt;br /&gt;
  | [] =&amp;gt; []&lt;br /&gt;
  | x :: xs =&amp;gt; (x + 1) :: incAll xs&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean 4.34.1 prints:&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;[Compiler.IR] [result]&lt;br /&gt;
    def incAll (x_1 : tobj) : tobj :=&lt;br /&gt;
      case x_1 : tobj of&lt;br /&gt;
      List.nil →&lt;br /&gt;
        ret x_1&lt;br /&gt;
      List.cons →&lt;br /&gt;
        let x_2 : tobj := proj[0] x_1;&lt;br /&gt;
        let x_3 : tobj := proj[1] x_1;&lt;br /&gt;
        block_4 (x_5 : tobj) (x_6 : u8) :=&lt;br /&gt;
          let x_7 : tagged := 1;&lt;br /&gt;
          let x_8 : tobj := Nat.add x_2 x_7;&lt;br /&gt;
          dec x_2;&lt;br /&gt;
          let x_9 : tobj := incAll x_3;&lt;br /&gt;
          block_10 (x_11 : obj) :=&lt;br /&gt;
            ret x_11;&lt;br /&gt;
          case x_6 : u8 of&lt;br /&gt;
          Bool.false →&lt;br /&gt;
            set x_5[1] := x_9;&lt;br /&gt;
            set x_5[0] := x_8;&lt;br /&gt;
            jmp block_10 x_5&lt;br /&gt;
          Bool.true →&lt;br /&gt;
            let x_12 : obj := ctor_1[List.cons] x_8 x_9;&lt;br /&gt;
            jmp block_10 x_12;&lt;br /&gt;
        let x_13 : u8 := isShared x_1;&lt;br /&gt;
        case x_13 : u8 of&lt;br /&gt;
        Bool.false →&lt;br /&gt;
          jmp block_4 x_1 x_13&lt;br /&gt;
        Bool.true →&lt;br /&gt;
          inc x_3;&lt;br /&gt;
          inc x_2;&lt;br /&gt;
          dec x_1;&lt;br /&gt;
          jmp block_4 ◾ x_13&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The same definition, given to &amp;lt;code&amp;gt;lean -c&amp;lt;/code&amp;gt;, yields a C function. In an excerpt, the&lt;br /&gt;
test, the call to the C implementation of addition and the two ways of producing the new&lt;br /&gt;
cell 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;v_isSharedCheck_13_ = !lean_is_exclusive(v_x_1_);&lt;br /&gt;
…&lt;br /&gt;
v___x_8_ = lean_nat_add(v_head_2_, v___x_7_);&lt;br /&gt;
…&lt;br /&gt;
if (v_isShared_6_ == 0)&lt;br /&gt;
{&lt;br /&gt;
lean_ctor_set(v___x_5_, 1, v___x_9_);&lt;br /&gt;
lean_ctor_set(v___x_5_, 0, v___x_8_);&lt;br /&gt;
…&lt;br /&gt;
v_reuseFailAlloc_12_ = lean_alloc_ctor(1, 2, 0);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Reference counting and update in place ==&lt;br /&gt;
&lt;br /&gt;
Lean manages memory by &amp;#039;&amp;#039;&amp;#039;reference counting&amp;#039;&amp;#039;&amp;#039;. Every object on the heap carries a count of&lt;br /&gt;
the references to it; the count rises when a reference is copied and falls when one is&lt;br /&gt;
dropped, and an object whose count reaches zero is freed at once.&amp;lt;ref name=&amp;quot;rm-rc&amp;quot; /&amp;gt; The&lt;br /&gt;
traditional objection to reference counting in functional languages is its cost.&lt;br /&gt;
Ullrich and de Moura&amp;#039;s answer is that an exact count is also information: it says whether a&lt;br /&gt;
value is &amp;#039;&amp;#039;&amp;#039;shared&amp;#039;&amp;#039;&amp;#039;, and a value that is not shared may be changed in place without any&lt;br /&gt;
observer being able to tell.&amp;lt;ref name=&amp;quot;beans&amp;quot;&amp;gt;Sebastian Ullrich and Leonardo de Moura, &amp;quot;Counting Immutable Beans: Reference Counting Optimized for Purely Functional Programming&amp;quot;, in &amp;#039;&amp;#039;Proceedings of the 31st Symposium on Implementation and Application of Functional Languages (IFL 2019)&amp;#039;&amp;#039;, ACM, 2019, article 3, pp. 1–12. doi:[https://doi.org/10.1145/3412932.3412935 10.1145/3412932.3412935]; preprint [https://arxiv.org/abs/1908.05647 arXiv:1908.05647].&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The IR above shows the mechanism. &amp;lt;code&amp;gt;isShared x_1&amp;lt;/code&amp;gt; tests the count of the incoming&lt;br /&gt;
list cell. If the cell is not shared, the branch &amp;lt;code&amp;gt;Bool.false&amp;lt;/code&amp;gt; overwrites its two&lt;br /&gt;
fields with &amp;lt;code&amp;gt;set&amp;lt;/code&amp;gt; and returns the same cell: the old list is updated in place.&lt;br /&gt;
If it is shared, &amp;lt;code&amp;gt;ctor_1[List.cons]&amp;lt;/code&amp;gt; allocates a new cell and the old one is left&lt;br /&gt;
for its other owners. In the paper this pair of steps is a &amp;lt;code&amp;gt;reset&amp;lt;/code&amp;gt; instruction,&lt;br /&gt;
which drops an unshared value&amp;#039;s references to its fields but keeps its cell, followed by&lt;br /&gt;
&amp;lt;code&amp;gt;reuse&amp;lt;/code&amp;gt;, which places the new constructor in that cell. The authors observe that&lt;br /&gt;
many objects die just before an object of the same kind is created, which they call the&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;resurrection hypothesis&amp;#039;&amp;#039;&amp;#039;, and that a function such as &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; applied to an&lt;br /&gt;
unshared list therefore allocates no memory at all.&amp;lt;ref name=&amp;quot;beans&amp;quot; /&amp;gt; In the Lean 4 system&lt;br /&gt;
description this is presented as a programming style, &amp;#039;&amp;#039;&amp;#039;functional but in place&amp;#039;&amp;#039;&amp;#039;: code&lt;br /&gt;
is written as pure functions, and runs with destructive updates wherever values are not&lt;br /&gt;
shared.&amp;lt;ref name=&amp;quot;cade&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Arrays and strings follow the same rule. Their primitive operations modify the value in place&lt;br /&gt;
when they hold the only reference, and copy it otherwise.&amp;lt;ref name=&amp;quot;rm-rc&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;beans&amp;quot; /&amp;gt;&lt;br /&gt;
Two further techniques keep the cost down. &amp;#039;&amp;#039;&amp;#039;Borrowed&amp;#039;&amp;#039;&amp;#039; parameters, which a function uses&lt;br /&gt;
without consuming, need no count updates, and the compiler infers many of them; and values&lt;br /&gt;
reachable from only one thread use cheaper, unsynchronised count updates. Reference counting&lt;br /&gt;
cannot reclaim cycles, but the part of Lean that can be reasoned about cannot create&lt;br /&gt;
cyclic data, so the runtime has no cycle collector.&amp;lt;ref name=&amp;quot;rm-rc&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;beans&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Code that differs from its definition ==&lt;br /&gt;
&lt;br /&gt;
Two attributes let the code that runs differ from the definition that the Lean kernel checks.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;@[extern &amp;quot;sym&amp;quot;]&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039; binds a definition to a C symbol: compiled code calls the C&lt;br /&gt;
function &amp;lt;code&amp;gt;sym&amp;lt;/code&amp;gt; instead of code generated from the definition.&amp;lt;ref name=&amp;quot;rm-ffi&amp;quot;&amp;gt;&amp;quot;Foreign Function Interface&amp;quot;, section 12.4 of &amp;#039;&amp;#039;The Lean Language Reference&amp;#039;&amp;#039; (edition covering Lean 4.34.0). [https://lean-lang.org/doc/reference/4.34.0/Run-Time-Code/Foreign-Function-Interface/ lean-lang.org/doc/reference/4.34.0/Run-Time-Code/Foreign-Function-Interface/]&amp;lt;/ref&amp;gt;&lt;br /&gt;
Addition of natural numbers is an example. The definition of &amp;lt;code&amp;gt;Nat.add&amp;lt;/code&amp;gt;, the one&lt;br /&gt;
theorems are about, is by recursion on the unary representation (zero and successor);&lt;br /&gt;
compiled code calls &amp;lt;code&amp;gt;lean_nat_add&amp;lt;/code&amp;gt;, as in the C above. At run time a natural&lt;br /&gt;
number is either a small value stored directly in the machine word or a pointer to a&lt;br /&gt;
multi-precision number.&amp;lt;ref name=&amp;quot;rm-ffi&amp;quot; /&amp;gt; Lean reports the binding:&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&lt;br /&gt;
&lt;br /&gt;
#eval show CoreM (Option String) from do&lt;br /&gt;
  return getExternNameFor (← getEnv) `c ``Nat.add&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This prints &amp;lt;code&amp;gt;some &amp;quot;lean_nat_add&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;@[implemented_by f]&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039; replaces a definition by another Lean function&lt;br /&gt;
&amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; in compiled code. Lean&amp;#039;s own documentation of the attribute states that &amp;quot;the&lt;br /&gt;
provided implementation is not checked to be equivalent to the original&lt;br /&gt;
definition&amp;quot;.&amp;lt;ref name=&amp;quot;impl&amp;quot;&amp;gt;Documentation of &amp;lt;code&amp;gt;Lean.Compiler.implementedByAttr&amp;lt;/code&amp;gt;, Lean API documentation. [https://lean-lang.org/doc/api/Lean/Compiler/ImplementedByAttr.html lean-lang.org/doc/api/Lean/Compiler/ImplementedByAttr.html]&amp;lt;/ref&amp;gt;&lt;br /&gt;
Nothing prevents a wrong one.&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 alwaysZero (_ : Nat) : Nat := 0&lt;br /&gt;
&lt;br /&gt;
@[implemented_by alwaysZero]&lt;br /&gt;
def ident (n : Nat) : Nat := n&lt;br /&gt;
&lt;br /&gt;
#eval ident 5&lt;br /&gt;
&lt;br /&gt;
theorem ident_five : ident 5 = 5 := rfl&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;#eval&amp;lt;/code&amp;gt; prints &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;, and the theorem that &amp;lt;code&amp;gt;ident 5 = 5&amp;lt;/code&amp;gt; is&lt;br /&gt;
accepted. Both are correct by their own lights: &amp;lt;code&amp;gt;#eval&amp;lt;/code&amp;gt; ran the code the compiler&lt;br /&gt;
was told to use, and the Lean kernel checked the definition. The most common uses, according to&lt;br /&gt;
the same documentation, are to give an efficient unsafe implementation of a function whose&lt;br /&gt;
definition is simple to reason about, and to make an unsafe function callable from safe&lt;br /&gt;
code.&amp;lt;ref name=&amp;quot;impl&amp;quot; /&amp;gt; A safer variant,&lt;br /&gt;
&amp;lt;code&amp;gt;@[csimp]&amp;lt;/code&amp;gt;, makes the same substitution only on the strength of a proved&lt;br /&gt;
equation between the two functions.&amp;lt;ref name=&amp;quot;impl&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== What it adds to what has to be trusted ==&lt;br /&gt;
&lt;br /&gt;
For a proof, ordinarily nothing. Apart from one deprecated primitive,&lt;br /&gt;
&amp;lt;code&amp;gt;Lean.reduceBool&amp;lt;/code&amp;gt;, whose use &amp;lt;code&amp;gt;#print axioms&amp;lt;/code&amp;gt; reports as the axiom&lt;br /&gt;
&amp;lt;code&amp;gt;Lean.trustCompiler&amp;lt;/code&amp;gt;, the Lean kernel never runs compiled code,&amp;lt;ref name=&amp;quot;src-core&amp;quot;&amp;gt;Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Init/Core.lean&amp;lt;/code&amp;gt;: the documentation of &amp;lt;code&amp;gt;Lean.reduceBool&amp;lt;/code&amp;gt; (&amp;quot;When the kernel tries to reduce a term &amp;lt;code&amp;gt;Lean.reduceBool c&amp;lt;/code&amp;gt;, it will invoke the Lean interpreter to evaluate &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&amp;quot;), deprecated since 2026-02-01, and of &amp;lt;code&amp;gt;Lean.trustCompiler&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Lean.ofReduceBool&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Init/Core.lean&amp;lt;/ref&amp;gt; so neither the&lt;br /&gt;
compiler nor any &amp;lt;code&amp;gt;@[extern]&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;@[implemented_by]&amp;lt;/code&amp;gt; annotation is&lt;br /&gt;
consulted when a theorem is checked. The theorem &amp;lt;code&amp;gt;ident_five&amp;lt;/code&amp;gt; above holds whatever&lt;br /&gt;
the compiled code does.&lt;br /&gt;
&lt;br /&gt;
For a program, everything above is trusted: the compiler, the C compiler, the runtime, and the&lt;br /&gt;
claim behind every &amp;lt;code&amp;gt;@[extern]&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;@[implemented_by]&amp;lt;/code&amp;gt; that the code&lt;br /&gt;
computes what the definition says. A proof about a function is a proof about the definition.&lt;br /&gt;
&lt;br /&gt;
The two meet in one place. Some tactics, such as &amp;lt;code&amp;gt;decide +native&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;bv_decide&amp;lt;/code&amp;gt;, prove a statement by running compiled code and admitting its result.&lt;br /&gt;
Such a proof depends on the compiler and on every &amp;lt;code&amp;gt;@[extern]&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;@[implemented_by]&amp;lt;/code&amp;gt; on the path,&lt;br /&gt;
and can be wrong when the compiled code disagrees with the definition. Since Lean 4.29.0 each&lt;br /&gt;
such computation introduces its own axiom, which &amp;lt;code&amp;gt;#print axioms&amp;lt;/code&amp;gt; lists, so the&lt;br /&gt;
dependence is visible.&amp;lt;ref name=&amp;quot;rm-validating&amp;quot;&amp;gt;&amp;quot;Validating a Lean Proof&amp;quot;, a chapter of &amp;#039;&amp;#039;The Lean Language Reference&amp;#039;&amp;#039; (edition covering Lean 4.34.0), section &amp;quot;On Lean.trustCompiler (up to Lean 4.28.0)&amp;quot;. [https://lean-lang.org/doc/reference/4.34.0/ValidatingProofs/ lean-lang.org/doc/reference/4.34.0/ValidatingProofs/]&amp;lt;/ref&amp;gt;&lt;br /&gt;
[[Lean theorem prover/System/Proof export and independent checkers|Proof export and independent checkers]]&lt;br /&gt;
shows the function &amp;lt;code&amp;gt;ident&amp;lt;/code&amp;gt; above used to prove a falsehood in exactly this way, and&lt;br /&gt;
how the axiom gives it away.&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/System/Lake and Lean projects|Lake and Lean projects]] describes how&lt;br /&gt;
Lean source files are organised into Lake packages and compiled together.&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>