<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://invarians.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=PMA+Publisher</id>
	<title>The Invariance Itself - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://invarians.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=PMA+Publisher"/>
	<link rel="alternate" type="text/html" href="https://invarians.org/wiki/Special:Contributions/PMA_Publisher"/>
	<updated>2026-10-21T08:13:50Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.46.2</generator>
	<entry>
		<id>https://invarians.org/index.php?title=Main_Page&amp;diff=6822</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Main_Page&amp;diff=6822"/>
		<updated>2026-10-15T19:35:55Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&amp;lt;!-- IPSUM INVARIANS - Main Page. Box structure per supplied template; styles inline so the page renders with no extensions installed. mp-* ids retained so a later stylesheet can override without editing wikitext. --&amp;gt;&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&amp;lt;!-- Top banner --&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;mp-topbanner&amp;quot; style=&amp;quot;border: 1px solid #a2a9b1; margin-bottom: 15px; background: #f8f9fa; padding: 10px; text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;mp-welcome&amp;quot;&amp;gt;&amp;lt;h1 style=&amp;quot;margin: 0; border: none; padding: 0.1em; font-size: 1.8em; font-weight: normal;&amp;quot;&amp;gt;IPSUM INVARIANS: The Invariance Itself&lt;br /&gt;
&amp;lt;/h1&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;mp-free&amp;quot; style=&amp;quot;font-size: 0.95em;&amp;quot;&amp;gt;The public record of the invariance program. est. 1 September 2026&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;articlecount&amp;quot; style=&amp;quot;font-size: 0.85em; margin-top: 0.3em;&amp;quot;&amp;gt;[[Special:Statistics|{{NUMBEROFARTICLES}}]] articles &amp;amp;middot; [[Special:Statistics|{{NUMBEROFACTIVEUSERS}}]] active editors &amp;amp;middot; [[Special:RecentChanges|{{NUMBEROFEDITS}} edits]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Main Container using Flexbox for responsiveness --&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: flex; flex-wrap: wrap; gap: 15px; justify-content: space-between;&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;!-- Left Column --&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;mp-left&amp;quot; style=&amp;quot;flex: 1 1 48%; min-width: 300px;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;!-- Green Box --&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;mp-intro-box&amp;quot; style=&amp;quot;border: 1px solid #a2a9b1; margin-bottom: 15px; background: #ffffff;&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;h2 id=&amp;quot;mp-intro-h2&amp;quot; style=&amp;quot;margin: 0; padding: 8px 10px; background-color: #cef2e0; border-bottom: 1px solid #a2a9b1; font-size: 1.2em; font-weight: bold;&amp;quot;&amp;gt;Introduction&amp;lt;/h2&amp;gt;&lt;br /&gt;
      &amp;lt;div id=&amp;quot;mp-intro&amp;quot; style=&amp;quot;padding: 10px;&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;Please be patient as we pull this site together.  Check back often for the latest developments.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Welcome to Ipsum Invarians, a platform built in four sections:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The Arena&#039;&#039;&#039; (Principia Machina): Essentially, this venue functions as an evaluation framework for testing physical hypotheses using artificial intelligence. It provides an AI protocol and a public research registry. We call this framework &#039;&#039;[[the Principia Machina]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The Weapon&#039;&#039;&#039; (Hamilton&#039;s Principle): Our namesake reflects what is arguably the single most important formulation in physics: the Action Principle or even Hamilton&#039;s principle. In our gladiatorial arena, [[Hamilton&#039;s principle]] is the sharpest, most lethal weapon available. To give this underappreciated concept its due, Ipsum Invarians carries a dedicated field manual for Hamilton’s Principle and its attendant [[Noether&#039;s theorems|Noether&#039;s theorem]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The Gladiator&#039;&#039;&#039; (SVD): Continuing the metaphor, our local gladiator is Structured Vacuum Dynamics (SVD). SVD enters the arena with a specific postulate: that a single permutation of Maxwell’s 1861 paper, Hamilton’s Principle, and Noether&#039;s First Theorem is sufficient to populate all of physics.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The Blueprint&#039;&#039;&#039; (Specifications): [[The_Principia_Machina/Hub/General_reader|Complete specifications]] for the Principia Machina and its standard prompt setup are openly published to ensure transparency and replication.  However, for security and reliability reasons, some internal testing functionality are only offered as pseudo code rather than providing the full testing paradigm.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;([[Introduction|Full article...]])&#039;&#039;&#039;&lt;br /&gt;
      &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- pma:begin lean --&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Green Box --&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;mp-lean-box&amp;quot; style=&amp;quot;border: 1px solid #a2a9b1; margin-bottom: 15px; background: #ffffff; color: #202122;&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;h2 id=&amp;quot;mp-lean-h2&amp;quot; style=&amp;quot;margin: 0; padding: 8px 10px; background-color: #cef2e0; border-bottom: 1px solid #a2a9b1; font-size: 1.2em; font-weight: bold;&amp;quot;&amp;gt;The Current Program (Round 3): the move to Lean&amp;lt;/h2&amp;gt;&lt;br /&gt;
      &amp;lt;div id=&amp;quot;mp-lean&amp;quot; style=&amp;quot;padding: 10px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;templatestyles src=&amp;quot;Principia Machina/styles.css&amp;quot; /&amp;gt;&lt;br /&gt;
[[The Principia Machina]] is being rewritten in &#039;&#039;&#039;Lean 4&#039;&#039;&#039;, a language in which proofs are checked by machine: one source for the specification and its Calculator, theorems where version 1 had only tests, and a proof checker as the gate every change must pass. The move also inspired a restructuring of the development workflow.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Where it stands&#039;&#039;&#039; (14 October 2026): Phase 0 of seven, the development setup, is under way. Phase 0 ports nothing from version 1 beyond one small module used as its test subject; the port itself is the work of Phase 2, the Calculator.&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: flex; flex-wrap: wrap; gap: 0 1em; align-items: flex-start;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;flex: 1 1 220px; min-width: 0;&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Done:&#039;&#039;&#039; Lean 4.35.0 pinned on every machine; a first library with three proved theorems, the Calculator and its tests; the proof and names gates; one task carried from one machine to another; publishing to this wiki under the Declarer&#039;s one-time code.&lt;br /&gt;
* &#039;&#039;&#039;Open:&#039;&#039;&#039; the second development machine; steering a session from a phone or tablet.&lt;br /&gt;
* &#039;&#039;&#039;Next:&#039;&#039;&#039; Test T1 has run: a Lean program runs on the wiki&#039;s own server outside a web request, so one Calculator still serves both sides. Tests T2 and T3 follow on the same server: the time one call takes, and what a hundred calls in one scheduled run cost.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;pma-fig&amp;quot; style=&amp;quot;flex: 0 1 356px; min-width: 0; margin: 0 auto; text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;graphviz&amp;gt;&lt;br /&gt;
digraph phases {&lt;br /&gt;
  rankdir=TB; bgcolor=&amp;quot;transparent&amp;quot;; nodesep=0.2; ranksep=0.18; size=&amp;quot;5.6,9&amp;quot;;&lt;br /&gt;
  node [shape=box, style=&amp;quot;rounded,filled&amp;quot;, fontname=&amp;quot;Helvetica&amp;quot;, fontsize=10, color=&amp;quot;#a2a9b1&amp;quot;, fillcolor=&amp;quot;#eaecf0&amp;quot;, fontcolor=&amp;quot;#202122&amp;quot;, margin=&amp;quot;0.12,0.06&amp;quot;];&lt;br /&gt;
  edge [color=&amp;quot;#54595d&amp;quot;, fontname=&amp;quot;Helvetica&amp;quot;, fontsize=9, fontcolor=&amp;quot;#202122&amp;quot;, arrowsize=0.7];&lt;br /&gt;
  node [width=3.6];&lt;br /&gt;
  P0 [label=&amp;quot;Phase 0  The development setup\nunder way: the current focus&amp;quot;, fillcolor=&amp;quot;#cedff2&amp;quot;, color=&amp;quot;#6a8fbf&amp;quot;, penwidth=2.4];&lt;br /&gt;
  P1 [label=&amp;quot;Phase 1  Foundations\nunder way&amp;quot;, fillcolor=&amp;quot;#cedff2&amp;quot;, color=&amp;quot;#6a8fbf&amp;quot;];&lt;br /&gt;
  P2 [label=&amp;quot;Phase 2  The Calculator\nunder way&amp;quot;, fillcolor=&amp;quot;#cedff2&amp;quot;, color=&amp;quot;#6a8fbf&amp;quot;];&lt;br /&gt;
  P3 [label=&amp;quot;Phase 3  Custos\nnot started&amp;quot;];&lt;br /&gt;
  P4 [label=&amp;quot;Phase 4  The Research Client\nnot started&amp;quot;];&lt;br /&gt;
  P5 [label=&amp;quot;Phase 5  Other model families\nnot started&amp;quot;];&lt;br /&gt;
  P6 [label=&amp;quot;Phase 6  Lifecycle and cutover\nnot started&amp;quot;];&lt;br /&gt;
  R  [label=&amp;quot;First release declared&amp;quot;, shape=doubleoctagon, style=filled, fillcolor=&amp;quot;#ffedad&amp;quot;, color=&amp;quot;#ac6600&amp;quot;, width=2.2];&lt;br /&gt;
  P0 -&amp;gt; P1 -&amp;gt; P2 -&amp;gt; P3 -&amp;gt; P4 -&amp;gt; P5 -&amp;gt; P6 -&amp;gt; R;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/graphviz&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size: 0.88em; color: #54595d;&amp;quot;&amp;gt;The seven phases, in order.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;([[Principia Machina/Lean transition|Full article...]])&#039;&#039;&#039; &amp;amp;nbsp;&amp;amp;middot;&amp;amp;nbsp; &#039;&#039;&#039;[[Principia Machina/Progress/Status|Status]]&#039;&#039;&#039; &amp;amp;nbsp;&amp;amp;middot;&amp;amp;nbsp; [[Principia Machina/Lean transition#lt-plate-box|The two-doors riddle, in Lean]] &amp;amp;nbsp;&amp;amp;middot;&amp;amp;nbsp; Version 1: [[Round 3|program of record]], [[The Principia Machina/Testing|testing]]&lt;br /&gt;
      &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;!-- pma:end lean --&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Grey Box --&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;mp-history-box&amp;quot; style=&amp;quot;border: 1px solid #a2a9b1; margin-bottom: 15px; background: #ffffff;&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;h2 id=&amp;quot;mp-history-h2&amp;quot; style=&amp;quot;margin: 0; padding: 8px 10px; background-color: #eaecf0; border-bottom: 1px solid #a2a9b1; font-size: 1.2em; font-weight: bold;&amp;quot;&amp;gt;Program History&amp;lt;/h2&amp;gt;&lt;br /&gt;
      &amp;lt;div id=&amp;quot;mp-history&amp;quot; style=&amp;quot;padding: 10px;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We started with a simple permutation of Maxwell&#039;s 1861 framework that yielded a promising interpretation of General Relativity. We applied a second permutation; analyzed it with tabletop testing and back-of-the-envelope calculations, and found we could derive both the eigenstates of hydrogen and chromodynamics. These two disparate domains (GR &amp;amp; QM) long advertised as incompatible, seem to be perfectly harmonious derivations from Maxwell&#039;s 1861 work. The result suggests a viable postulate: if we constrain ourselves with Hamilton’s Principle and Noether’s First Theorem,  can we build all of physics from a single assumption? From two assumptions?&lt;br /&gt;
&lt;br /&gt;
[[File:Modified vorticie.jpg|thumb|center|upright=1.5|A simple permutation of Maxwell&#039;s 1861 framework.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The idea is daunting, but maybe AI can help.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Round 1&#039;&#039;&#039; &amp;amp;ndash; Technical paper: Structured Vacuum Dynamics &lt;br /&gt;
&lt;br /&gt;
This was more of a proof of concept: would AI confirm the math or maybe find new paradigms to fit the otherwise disparate math together?  We started with a simple technical paper around the postulate and a strict set of AI controls and restrictions.  We designed a rigerous prompt that pitted the AI Agent against itself, doing more work to double and triple check its results than the original work to get the results, but this effort quickly overwhelmed the local AI context.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Round 2&#039;&#039;&#039; &amp;amp;ndash; The Research Register (RR-n)&lt;br /&gt;
&lt;br /&gt;
The Lesson from round 1 - physics is a much bigger domain than a single paper.  We did start to understand the context limits of the most reasonably available AI offerings and the constraints it left us with.  We broke the design into two parts: a back-end research register and a front-end that could generate papers from the research register.  Soon we ran into problems mapping the axioms to the environment.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Round 3 opening&#039;&#039;&#039; &amp;amp;ndash; The Principia Machina (TPM)&lt;br /&gt;
&lt;br /&gt;
The Lesson from round 2 - Local AI context was never going to be enough for any serious work.  We realized we could kill three birds with one stone if we moved the research context to a Wiki:&lt;br /&gt;
#The context would be effectively unlimited&lt;br /&gt;
#A public, formalized, framework would foster independent verification&lt;br /&gt;
#it would give a great public record to invite collaboration and outside ideas&lt;br /&gt;
&lt;br /&gt;
Thus &#039;&#039;&#039;[[the Principia Machina]]:&#039;&#039;&#039; an AI Harness inspired physics solver/research platform and test bed implemented in MediaWiki.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;([[Program history|Full record...]])&#039;&#039;&#039; &amp;amp;nbsp;&amp;amp;middot;&amp;amp;nbsp; [[Program history/Archive|Archive]]&lt;br /&gt;
      &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;!-- Grey Box ?--&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;mp-round-box&amp;quot; style=&amp;quot;border: 1px solid #a2a9b1; margin-bottom: 15px; background: #ffffff;&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;h2 id=&amp;quot;mp-round-h2&amp;quot; style=&amp;quot;margin: 0; padding: 8px 10px; background-color: #eaecf0; border-bottom: 1px solid #a2a9b1; font-size: 1.2em; font-weight: bold;&amp;quot;&amp;gt;The Principia Machina Specification (TPS) &amp;lt;/h2&amp;gt;&lt;br /&gt;
      &amp;lt;div id=&amp;quot;mp-round&amp;quot; style=&amp;quot;padding: 10px;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The Principia Machina Specification&#039;&#039;&#039; (TPS) is the complete, published&lt;br /&gt;
description of The Principia Machina (TPM), a set of rules for doing research&lt;br /&gt;
with AI assistants so that the result can be checked afterwards by anyone.&lt;br /&gt;
TPS is written for two readers at once: a person who wants to understand how&lt;br /&gt;
the framework works, and an AI agent of any make that wants to work under it.&lt;br /&gt;
It is one of five parts, and it is the part that binds the other four.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;The foundations record.&#039;&#039;&#039; A dated account of every design decision, the options rejected, and the reasons. It is the source TPS was written from. It describes; it never instructs.&lt;br /&gt;
# &#039;&#039;&#039;The specification.&#039;&#039;&#039; This document. It defines the five layers of the framework, the sealed container a piece of research lives in, the wiki machinery that records the work, and the Agent Contract: the rules any AI agent follows to work a container. It is versioned, and its fingerprint is the first line of the wiki&#039;s chain of declarations.&lt;br /&gt;
# &#039;&#039;&#039;The implementations.&#039;&#039;&#039; What runs the rules. On the server, TPX, a MediaWiki extension that performs every check a machine can perform. Beside the agent, PRB, the client an agent uses to hold its working copy and land results. And each agent&#039;s own instruction set, implementing the Agent Contract. The project&#039;s own instruction set is written for Claude and is one implementation among any number.&lt;br /&gt;
# &#039;&#039;&#039;The wiki.&#039;&#039;&#039; Where all of the above is published and read, and the system of record for everything TPM does.&lt;br /&gt;
# &#039;&#039;&#039;The containers.&#039;&#039;&#039; The research itself: a sealed set of laws and assumptions, and the register of findings built on it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;!-- Right Column --&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;mp-right&amp;quot; style=&amp;quot;flex: 1 1 48%; min-width: 300px;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;!-- Blue Box --&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;mp-hamilton-box&amp;quot; style=&amp;quot;border: 1px solid #a2a9b1; margin-bottom: 15px; background: #ffffff;&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;h2 id=&amp;quot;mp-hamilton-h2&amp;quot; style=&amp;quot;margin: 0; padding: 8px 10px; background-color: #cedff2; border-bottom: 1px solid #a2a9b1; font-size: 1.2em; font-weight: bold;&amp;quot;&amp;gt;Hamilton&#039;s Principle&amp;lt;/h2&amp;gt;&lt;br /&gt;
      &amp;lt;div id=&amp;quot;mp-hamilton&amp;quot; style=&amp;quot;padding: 10px;&amp;quot;&amp;gt;&lt;br /&gt;
Newton&#039;s laws, Maxwell&#039;s equations, general relativity and the Standard Model are each formulated as an action via Hamilton&#039;s Principle.  Across all these domains, dynamical equations emerge as derived outcomes rather than fundamental starting axioms. Conservation of energy, momentum and charge are not separate laws at all — [[Hamilton&#039;s principle/Mathematics/Noether&#039;s first theorem|Noether proved]] they follow from the action&#039;s symmetries. New models are now built by writing the action constrained by symmetry and letting the dynamics follow.  This is how electromagnetism and gravity were derived and how the nuclear forces were found. Alone among classical concepts, &#039;&#039;&#039;Hamilton&#039;s Principle&#039;&#039;&#039; transitions smoothly into quantum mechanics, where the action represents a phase carried across distinct trajectories and the classical path marks where destructive interference is minimized.  The action is the deepest thing physics knows.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:OPL-HP-F-01.png|thumb|center|upright=1.5|A true path and several comparison paths between fixed endpoints.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[Hamilton&#039;s principle/Mathematics/The Jacobi condition and conjugate points|Stationary is not least]] — the long way round a great circle obeys the same rule at every point, and is plainly not the shortest. [[:File:OPL-HP-F-05.png|See the diagram]].&lt;br /&gt;
* [[Hamilton&#039;s principle/Applications/The Feynman path integral|Why the rule holds at all]] — nature selects nothing. It sums over everything, and what looks like a choice is the residue left by interference.&lt;br /&gt;
* [[Hamilton&#039;s principle/Explainers/Comparing paths|Start without the mathematics]] — every page carrying equations has a plain-language counterpart, linked from it and linking back.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;([[Hamilton&#039;s principle|Full article...]])&#039;&#039;&#039;&lt;br /&gt;
      &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;!-- Blue Box --&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;mp-noether-box&amp;quot; style=&amp;quot;border: 1px solid #a2a9b1; margin-bottom: 15px; background: #ffffff;&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;h2 id=&amp;quot;mp-noether-h2&amp;quot; style=&amp;quot;margin: 0; padding: 8px 10px; background-color: #cedff2; border-bottom: 1px solid #a2a9b1; font-size: 1.2em; font-weight: bold;&amp;quot;&amp;gt;Noether&#039;s theorems&amp;lt;/h2&amp;gt;&lt;br /&gt;
      &amp;lt;div id=&amp;quot;mp-noether&amp;quot; style=&amp;quot;padding: 10px;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:NT-F-07.png|thumb|center|400px|alt=Continuous symmetries on the left, the quantities they conserve on the right, with the map between them|The symmetry-to-conservation map]]&lt;br /&gt;
&lt;br /&gt;
Klein read the paper to the Göttingen Scientific Society on 26 July 1918. Its&lt;br /&gt;
last section answers a claim of Hilbert&#039;s: that energy conservation in general&lt;br /&gt;
relativity fails to take the form it takes everywhere else in physics.&lt;br /&gt;
&#039;&#039;&#039;There are two theorems in the paper, and they are not versions of one another.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The initial theorem relates global, finite-parameter symmetries directly to corresponding physical conservation laws governing actual dynamics. The second takes a symmetry that is allowed to differ from place to place and returns identities between the&lt;br /&gt;
field equations — identities that hold whether or not those equations are&lt;br /&gt;
satisfied. The second theorem is why a gauge theory has fewer independent field&lt;br /&gt;
equations than it has fields, and why gravity has no local energy.&lt;br /&gt;
&lt;br /&gt;
A 90-page reading edition: both theorems proved in full and kept apart, the&lt;br /&gt;
mathematics they need, the physics they explain, and a plain-language&lt;br /&gt;
counterpart for every page that carries equations.&lt;br /&gt;
&lt;br /&gt;
* [[Noether&#039;s theorems/History/Gottingen and the energy problem|Göttingen and the energy problem]] — the question the paper was written to settle&lt;br /&gt;
* [[Noether&#039;s theorems/Explainers/Symmetry and conservation, the first theorem|The primer]] — plain language, no mathematics&lt;br /&gt;
* [[Noether&#039;s theorems/Second theorem/The two theorems side by side|The two theorems side by side]] — the distinction most accounts lose&lt;br /&gt;
&lt;br /&gt;
([[Noether&#039;s theorems|Full article...]])&lt;br /&gt;
      &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;!-- Blue Box --&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;mp-maxwell-box&amp;quot; style=&amp;quot;border: 1px solid #a2a9b1; margin-bottom: 15px; background: #ffffff;&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;h2 id=&amp;quot;mp-maxwell-h2&amp;quot; style=&amp;quot;margin: 0; padding: 8px 10px; background-color: #cedff2; border-bottom: 1px solid #a2a9b1; font-size: 1.2em; font-weight: bold;&amp;quot;&amp;gt;The Work of James Clerk Maxwell&amp;lt;/h2&amp;gt;&lt;br /&gt;
      &amp;lt;div id=&amp;quot;mp-maxwell&amp;quot; style=&amp;quot;padding: 10px;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== On Physical Lines of Force ==&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
[[File:OPL-fig-lines-of-force.svg|thumb|center|upright=1.5|Lines of force about a bar magnet]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In four instalments between March 1861 and February 1862, James Clerk Maxwell&lt;br /&gt;
filled space with spinning cells and little rolling particles, to explain the mechanics behind magnetic fields. &#039;&#039;&#039;His machine was wrong.&#039;&#039;&#039; On the way to building it,&lt;br /&gt;
he wrote down the displacement current, derived the speed of light from two&lt;br /&gt;
electrical measurements that had nothing to do with optics, and founded field&lt;br /&gt;
theory.&lt;br /&gt;
 &lt;br /&gt;
A 65-page reading edition: Maxwell&#039;s argument in his own order and register, the&lt;br /&gt;
modern equations derived from his results, and a plain-language explainer for&lt;br /&gt;
every major idea.&lt;br /&gt;
 &lt;br /&gt;
* [[On Physical Lines of Force/Introduction|Introduction]] — the story, and why the paper matters&lt;br /&gt;
* [[On Physical Lines of Force/Explainers|The primer]] — plain language, no mathematics&lt;br /&gt;
* [[On Physical Lines of Force/Explainers/The missing term|The missing term]] — the one addition that made radio possible&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;([[On_Physical_Lines_of_Force|Full article...]])&#039;&#039;&#039;&lt;br /&gt;
      &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;!-- Blue Box --&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;mp-toolkit-box&amp;quot; style=&amp;quot;border: 1px solid #a2a9b1; margin-bottom: 15px; background: #ffffff;&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;h2 id=&amp;quot;mp-toolkit-h2&amp;quot; style=&amp;quot;margin: 0; padding: 8px 10px; background-color: #cedff2; border-bottom: 1px solid #a2a9b1; font-size: 1.2em; font-weight: bold;&amp;quot;&amp;gt;Research Toolkit&amp;lt;/h2&amp;gt;&lt;br /&gt;
      &amp;lt;div id=&amp;quot;mp-toolkit&amp;quot; style=&amp;quot;padding: 10px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;graphviz&amp;gt;&lt;br /&gt;
digraph mp_toolkit {&lt;br /&gt;
  rankdir=TB; bgcolor=&amp;quot;transparent&amp;quot;; nodesep=0.2; ranksep=0.3;&lt;br /&gt;
  node [shape=box, style=&amp;quot;rounded,filled&amp;quot;, fillcolor=&amp;quot;#eaf3ff&amp;quot;, color=&amp;quot;#6a8fbf&amp;quot;, fontname=&amp;quot;Helvetica&amp;quot;, fontsize=10];&lt;br /&gt;
  edge [color=&amp;quot;#6a8fbf&amp;quot;, arrowsize=0.6];&lt;br /&gt;
  M [label=&amp;quot;The manual\nstart here&amp;quot;, fillcolor=&amp;quot;#ffffff&amp;quot;];&lt;br /&gt;
  F [label=&amp;quot;Agent flow\ncontrol\n39 practices&amp;quot;];&lt;br /&gt;
  R [label=&amp;quot;Research\nmethods\n59 techniques&amp;quot;];&lt;br /&gt;
  T [label=&amp;quot;Research\ntools\n22 + 55 tools&amp;quot;];&lt;br /&gt;
  B [label=&amp;quot;Bibliography\n284 sources&amp;quot;, shape=note, style=filled, fillcolor=&amp;quot;#ffffff&amp;quot;];&lt;br /&gt;
  M -&amp;gt; F; M -&amp;gt; R; M -&amp;gt; T; F -&amp;gt; B; R -&amp;gt; B; T -&amp;gt; B;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/graphviz&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Everything an AI agent, or a person, needs to do research on this wiki, in one place. &#039;&#039;&#039;An AI arriving here starts with [[The Principia Machina/Research Toolkit/Manual|the manual]].&#039;&#039;&#039; The toolkit has three parts:&lt;br /&gt;
* &#039;&#039;&#039;[[The Principia Machina/Research Toolkit/Agent flow control|Agent flow control]]&#039;&#039;&#039; &amp;amp;ndash; how an agent plans, checks, retries, escalates and stays safe: thirty-nine practices with their evidence.&lt;br /&gt;
* &#039;&#039;&#039;[[The Principia Machina/Research Toolkit/Research methods|Research methods]]&#039;&#039;&#039; &amp;amp;ndash; how to solve an abstract problem, check the answer and report it: fifty-nine techniques and the process from question to compared result.&lt;br /&gt;
* &#039;&#039;&#039;[[The Principia Machina/Research Toolkit/Research tools|Research tools]]&#039;&#039;&#039; &amp;amp;ndash; the programs and services, assessed: the twenty-two [[The Principia Machina/Tools|physics tools]] and fifty-five general tools.&lt;br /&gt;
With [[The Principia Machina/Research Toolkit/Bibliography|the bibliography]] (284 sources, each with a note of how it was checked) and [[The Principia Machina/Agent/Research toolkit|a card for AI agents]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;([[The Principia Machina/Research Toolkit|The full toolkit...]])&#039;&#039;&#039;&lt;br /&gt;
      &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;!-- pma:begin lean-edition --&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Blue Box --&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;mp-lean-edition-box&amp;quot; style=&amp;quot;border: 1px solid #a2a9b1; margin-bottom: 15px; background: #ffffff;&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;h2 id=&amp;quot;mp-lean-edition-h2&amp;quot; style=&amp;quot;margin: 0; padding: 8px 10px; background-color: #cedff2; border-bottom: 1px solid #a2a9b1; font-size: 1.2em; font-weight: bold;&amp;quot;&amp;gt;Lean theorem prover&amp;lt;/h2&amp;gt;&lt;br /&gt;
      &amp;lt;div id=&amp;quot;mp-lean-edition&amp;quot; style=&amp;quot;padding: 10px;&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Lean&#039;&#039;&#039; is a proof assistant and a programming language. A person writes definitions, statements and proofs in Lean&#039;s formal language, and Lean checks each proof against the rules of its logic before it accepts the statement as a theorem. A small part of the program, the Lean kernel, makes that check; everything else only proposes.&lt;br /&gt;
&lt;br /&gt;
A 71-page reading edition: what Lean checks and how, the type theory behind it, how the program works, where it came from and what it is used for, written for a reader with no logic or programming and for one who wants the rules, with a plain-language counterpart for every technical page.&lt;br /&gt;
&lt;br /&gt;
* [[Lean theorem prover/Explainers/What a proof assistant does|What a proof assistant does]] — plain language, the place to start&lt;br /&gt;
* [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]] — the rules Lean checks against&lt;br /&gt;
* [[Lean theorem prover/Explainers/What has to be trusted|What has to be trusted]] — what a checked proof still rests on&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;([[Lean theorem prover|Full article...]])&#039;&#039;&#039;&lt;br /&gt;
      &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;!-- pma:end lean-edition --&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Full-width sections --&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;mp-lower&amp;quot; style=&amp;quot;border: 1px solid #a2a9b1; margin-bottom: 15px; background: #ffffff;&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;h2 id=&amp;quot;mp-plate-h2&amp;quot; style=&amp;quot;margin: 0; padding: 8px 10px; background-color: #ffedad; border-bottom: 1px solid #a2a9b1; font-size: 1.2em; font-weight: bold;&amp;quot;&amp;gt;Featured plate&amp;lt;/h2&amp;gt;&lt;br /&gt;
 &amp;lt;div id=&amp;quot;mp-plate&amp;quot; style=&amp;quot;padding: 10px; text-align: left; display: flex; flex-wrap: wrap; flex-direction: row-reverse; gap: 1em; align-items: flex-start;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;mp-plate-box&amp;quot; style=&amp;quot;flex: 0 1 300px; max-width: 100%; margin: 0 auto;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;infobox&amp;quot; style=&amp;quot;width: 100%; box-sizing: border-box; margin: 0; font-size: 90%; background: #f9f9f9; border: 1px solid #aaa; padding: 5px;&amp;quot;&lt;br /&gt;
|+ style=&amp;quot;font-size: 120%; font-weight: bold; padding-bottom: 5px;&amp;quot; | Analytical Foundations of Physics&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; style=&amp;quot;text-align: center;&amp;quot; | [[File:Lagrange_portrait.jpg|250px|alt=Portrait of Joseph-Louis Lagrange]]&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; style=&amp;quot;text-align: center; font-size: smaller; padding-bottom: 10px;&amp;quot; | &#039;&#039;The shift from Newtonian vectors to scalar fields and variational principles defined modern theoretical physics.&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; style=&amp;quot;background: #ccf; text-align: center;&amp;quot; | Core Frameworks&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Classical Mechanics&#039;&#039;&#039; || [[Lagrangian mechanics]]&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Dynamical Optimization&#039;&#039;&#039; || [[Principle of least action]]&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Electromagnetism&#039;&#039;&#039; || [[Maxwell&#039;s equations]]&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Vacuum Dynamics&#039;&#039;&#039; || [[Spacetime topology]]&lt;br /&gt;
|-&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; style=&amp;quot;background: #ccf; text-align: center;&amp;quot; | Key Equations&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; style=&amp;quot;text-align: center; padding: 5px;&amp;quot; |&lt;br /&gt;
&amp;lt;math&amp;gt;S = \int L \, dt&amp;lt;/math&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;G_{\mu\nu} + \Lambda g_{\mu\nu} = \frac{8\pi G}{c^4} T_{\mu\nu}&amp;lt;/math&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;mp-plate-text&amp;quot; style=&amp;quot;flex: 1 1 320px; min-width: 0;&amp;quot;&amp;gt;&lt;br /&gt;
== [[Timeline of Physics]] ==&lt;br /&gt;
The narrative of 18th- to 20th-century physics lies in a profound mathematical restructuring. This era marked the transition from treating nature as a collection of forces acting on point masses to understanding it through continuous fields, spacetime manifolds, and unified variational principles.&lt;br /&gt;
&lt;br /&gt;
The foundation was laid when physical systems began to be analyzed &#039;&#039;&#039;not through Newtonian vectors, but through scalar quantities—kinetic and potential energy—operating within generalized coordinates.&#039;&#039;&#039; By positing that the true dynamical trajectory of any system is the one that leaves the action integral stationary, &#039;&#039;&#039;theorists established a universal mathematical language.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This analytical approach seamlessly extended beyond mechanical gears and pulleys into the continuum. It provided the structural mathematics required to unify electricity and magnetism into a single vacuum field theory, and later, to model gravity not as a pulling force, but as the dynamic geometric curvature of spacetime itself. Whether applied to subatomic particle behavior or cosmic expansion, these foundational principles continue to govern the leading edge of modern physics.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== [[The Principia Machina/Tools|Physics Tools]] ==&lt;br /&gt;
Theoretical rigor must be paired with high-performance computational machinery. Twenty-two open tools are now surveyed for [[the Principia Machina]]; the first twelve cover three analytical frontiers:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;The Inverse Action Problem:&#039;&#039;&#039; Discovering analytical scalar Lagrangians &amp;lt;math&amp;gt;\mathcal{L}(\phi, \partial_\mu \phi)&amp;lt;/math&amp;gt; and continuous Noether symmetries directly from perturbation data using [[The_Principia_Machina/Tools/PySR|PySR]] and [[The_Principia_Machina/Tools/AIFeynman|AI Feynman]].&lt;br /&gt;
* &#039;&#039;&#039;Variational &amp;amp; Mesh-Free Solvers:&#039;&#039;&#039; Minimizing continuous action integrals across complex geometries via Physics-Informed Neural Networks ([[The_Principia_Machina/Tools/DeepXDE|DeepXDE]]) and symbolic finite-element/difference stencils ([[The_Principia_Machina/Tools/FEniCS|FEniCS]] &amp;amp; [[The_Principia_Machina/Tools/Devito|Devito]]).&lt;br /&gt;
* &#039;&#039;&#039;Spacetime &amp;amp; Tensor Algebra:&#039;&#039;&#039; Evaluating functional variational derivatives in [[The_Principia_Machina/Tools/Cadabra2|Cadabra2]], 3+1 ADM spacetime evolution in the [[The_Principia_Machina/Tools/EinsteinToolkit|Einstein Toolkit]], and open quantum dynamics in [[The_Principia_Machina/Tools/QuTiP|QuTiP]].&lt;br /&gt;
&lt;br /&gt;
Ten more were added on 2026-10-06: SymPy, SageMath, xAct, Lean with Mathlib and Physlib, FORM, FeynCalc, Lagrangian and Hamiltonian networks, PySINDy, Dedalus and SpECTRE ([[The Principia Machina/Tools#The additions of 2026-10-06|the additions]]). All twenty-two are in [[The Principia Machina/Research Toolkit/Research tools|the Research Toolkit&#039;s third part]], beside fifty-five general tools.&lt;br /&gt;
&lt;br /&gt;
Read it your way: &#039;&#039;&#039;[[The Principia Machina/Tools/General reader|in plain language]]&#039;&#039;&#039; &amp;amp;middot; &#039;&#039;&#039;[[The Principia Machina/Tools/Operator&#039;s guide|the operator&#039;s guide]]&#039;&#039;&#039; &amp;amp;middot; &#039;&#039;&#039;[[The Principia Machina/Agent/Tools|for AI agents]]&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;([[The Principia Machina/Tools|Full survey and domain evaluation...]])&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;mp-other-box&amp;quot; style=&amp;quot;border: 1px solid #a2a9b1; margin-bottom: 15px; background: #ffffff;&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;h2 id=&amp;quot;mp-other&amp;quot; style=&amp;quot;margin: 0; padding: 8px 10px; background-color: #eaecf0; border-bottom: 1px solid #a2a9b1; font-size: 1.2em; font-weight: bold;&amp;quot;&amp;gt;Other areas of Ipsum Invarians&amp;lt;/h2&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;mp-other-content&amp;quot; style=&amp;quot;padding: 10px;&amp;quot;&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;[[Special:AllPages|All pages]]&#039;&#039;&#039; &amp;amp;ndash; ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.&lt;br /&gt;
* &#039;&#039;&#039;[[Special:RecentChanges|Recent changes]]&#039;&#039;&#039; &amp;amp;ndash; nisi ut aliquip ex ea commodo consequat duis aute irure.&lt;br /&gt;
* &#039;&#039;&#039;[[Special:Categories|Categories]]&#039;&#039;&#039; &amp;amp;ndash; dolor in reprehenderit in voluptate velit esse cillum dolore.&lt;br /&gt;
* &#039;&#039;&#039;[[Special:SpecialPages|Special pages]]&#039;&#039;&#039; &amp;amp;ndash; eu fugiat nulla pariatur excepteur sint occaecat cupidatat.&lt;br /&gt;
* &#039;&#039;&#039;[[Project:Sandbox|Sandbox]]&#039;&#039;&#039; &amp;amp;ndash; non proident, sunt in culpa qui officia deserunt mollit anim.&lt;br /&gt;
* &#039;&#039;&#039;[[Special:Upload|Upload]]&#039;&#039;&#039; &amp;amp;ndash; id est laborum sed ut perspiciatis unde omnis iste natus error.&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;mp-lang-box&amp;quot; style=&amp;quot;border: 1px solid #a2a9b1; margin-bottom: 15px; background: #ffffff;&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;h2 id=&amp;quot;mp-lang&amp;quot; style=&amp;quot;margin: 0; padding: 8px 10px; background-color: #eaecf0; border-bottom: 1px solid #a2a9b1; font-size: 1.2em; font-weight: bold;&amp;quot;&amp;gt;Ipsum Invarians languages&amp;lt;/h2&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;mp-lang-content&amp;quot; style=&amp;quot;padding: 10px; text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
Totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;small&amp;gt;&#039;&#039;Language editions are not yet configured. Set them up with [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Interwiki interwiki links] or [https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:Translate Extension:Translate].&#039;&#039;&amp;lt;/small&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;__NOTOC____NOEDITSECTION__&lt;/div&gt;</summary>
		<author><name>PMA Publisher</name></author>
	</entry>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/Further_reading&amp;diff=6821</id>
		<title>Lean theorem prover/Further reading</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Further_reading&amp;diff=6821"/>
		<updated>2026-10-15T19:35:54Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Further reading}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
This edition describes Lean; it does not teach it. The works below do, and all of them can be&lt;br /&gt;
read free of charge online. Each line says what the work is for; the link is in its&lt;br /&gt;
reference. Most are cited on the edition&#039;s pages, which are named where they draw on a work.&lt;br /&gt;
&lt;br /&gt;
== Books and manuals ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Theorem Proving in Lean 4&#039;&#039;&#039;&#039;&#039;, by Jeremy Avigad, Leonardo de Moura, Soonho Kong and Sebastian Ullrich: Lean&#039;s logic from the inside, from dependent type theory and propositions to tactics, inductive types, type classes and the axioms; the companion to the [[Lean theorem prover/Foundations/Terms, types and judgments|Foundations]] pages.&amp;lt;ref name=&amp;quot;tpil&amp;quot;&amp;gt;Jeremy Avigad, Leonardo de Moura, Soonho Kong and Sebastian Ullrich, with contributions from the Lean community, &#039;&#039;Theorem Proving in Lean 4&#039;&#039;, online book, lean-lang.org. https://lean-lang.org/theorem_proving_in_lean4/&amp;lt;/ref&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Functional Programming in Lean&#039;&#039;&#039;&#039;&#039;, by David Thrane Christiansen: Lean as a programming language, from its basics through type classes and monads to dependent types and proofs about programs; the companion to [[Lean theorem prover/System/Monads and do-notation|Monads and do-notation]].&amp;lt;ref name=&amp;quot;fpil&amp;quot;&amp;gt;David Thrane Christiansen, &#039;&#039;Functional Programming in Lean&#039;&#039;, online book, lean-lang.org. https://lean-lang.org/functional_programming_in_lean/&amp;lt;/ref&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Mathematics in Lean&#039;&#039;&#039;&#039;&#039;, by Jeremy Avigad and Patrick Massot: doing mathematics with Mathlib, from basic logic and number theory to topology, calculus and measure theory.&amp;lt;ref name=&amp;quot;mil&amp;quot;&amp;gt;Jeremy Avigad and Patrick Massot, &#039;&#039;Mathematics in Lean&#039;&#039;, online book. https://leanprover-community.github.io/mathematics_in_lean/&amp;lt;/ref&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;The Lean Language Reference&#039;&#039;&#039;&#039;&#039;, by the Lean developers: the precise description of the language, a reference work rather than a tutorial, with an edition for each version of Lean; this edition cites the one for Lean 4.34.0.&amp;lt;ref name=&amp;quot;refman&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, for Lean 4.34.0, lean-lang.org, 2026. https://lean-lang.org/doc/reference/4.34.0/&amp;lt;/ref&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Metaprogramming in Lean 4&#039;&#039;&#039;&#039;&#039;, by Arthur Paulino and others: how to write new notation, commands and tactics in Lean; the companion to [[Lean theorem prover/System/Metaprogramming in Lean|Metaprogramming in Lean]].&amp;lt;ref name=&amp;quot;mpb&amp;quot;&amp;gt;Arthur Paulino, Damiano Testa, Edward Ayers, Evgenia Karunus, Henrik Böving, Jannis Limperg, Siddhartha Gadgil and Siddharth Bhat, &#039;&#039;Metaprogramming in Lean 4&#039;&#039;, online book, Lean community. https://leanprover-community.github.io/lean4-metaprogramming-book/&amp;lt;/ref&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Logic and Proof&#039;&#039;&#039;&#039;&#039;, by J. Avigad, R. Y. Lewis and F. van Doorn, adapted to Lean 4 by J. Hua: an introduction to symbolic logic and to writing proofs, with Lean.&amp;lt;ref name=&amp;quot;lap&amp;quot;&amp;gt;J. Avigad, J. Hua, R. Y. Lewis and F. van Doorn, &#039;&#039;Logic and Proof&#039;&#039;, online textbook, Lean 4 edition. https://leanprover-community.github.io/logic_and_proof/&amp;lt;/ref&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;The Mechanics of Proof&#039;&#039;&#039;&#039;&#039;, by Heather Macbeth: a first university course in writing careful proofs, with Lean beside the text.&amp;lt;ref name=&amp;quot;mop&amp;quot;&amp;gt;Heather Macbeth, &#039;&#039;The Mechanics of Proof&#039;&#039;, online book for Math 2001, Fordham University, 2022–2024. https://hrmacbeth.github.io/math2001/&amp;lt;/ref&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Formalising Mathematics&#039;&#039;&#039;&#039;&#039;, by Kevin Buzzard: the handbook of a course for mathematics students who want to formalise with Mathlib.&amp;lt;ref name=&amp;quot;fm&amp;quot;&amp;gt;Kevin Buzzard, &#039;&#039;Formalising Mathematics&#039;&#039;, course handbook, Imperial College London, 2024 edition. https://www.ma.imperial.ac.uk/~buzzard/xena/formalising-mathematics-2024/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/Applications/Teaching with Lean|Teaching with Lean]] describes several of these books and the courses built on them.&lt;br /&gt;
&lt;br /&gt;
== A game ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;The Natural Number Game&#039;&#039;&#039;, by Kevin Buzzard, Jon Eugster and others: played in a web browser, it constructs the natural numbers from zero and the next number and proves their facts one level at a time.&amp;lt;ref name=&amp;quot;nng&amp;quot;&amp;gt;Kevin Buzzard, Jon Eugster et al., &#039;&#039;Natural Number Game&#039;&#039;, Lean 4 version, on the Lean Game Server: https://adam.math.hhu.de/#/g/leanprover-community/nng4 (source and credits: https://github.com/leanprover-community/NNG4)&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Papers ==&lt;br /&gt;
&lt;br /&gt;
* The first description of Lean, by Leonardo de Moura and four colleagues (2015).&amp;lt;ref name=&amp;quot;lean2015&amp;quot;&amp;gt;Leonardo de Moura, Soonho Kong, Jeremy Avigad, Floris van Doorn and Jakob von Raumer, &amp;quot;The Lean Theorem Prover (system description)&amp;quot;, in &#039;&#039;Automated Deduction – CADE-25&#039;&#039;, Lecture Notes in Computer Science 9195, Springer, 2015, pp. 378–388. doi:10.1007/978-3-319-21401-6_26. Author&#039;s copy: https://lean-lang.org/papers/system.pdf&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Tactics written in Lean itself, in Lean 3 (2017).&amp;lt;ref name=&amp;quot;ebner2017&amp;quot;&amp;gt;Gabriel Ebner, Sebastian Ullrich, Jared Roesch, Jeremy Avigad and Leonardo de Moura, &amp;quot;A metaprogramming framework for formal verification&amp;quot;, &#039;&#039;Proceedings of the ACM on Programming Languages&#039;&#039; 1 (ICFP), article 34, 2017. doi:10.1145/3110278. Author&#039;s copy: https://lean-lang.org/papers/tactic.pdf&amp;lt;/ref&amp;gt;&lt;br /&gt;
* The design of Lean 4, by de Moura and Ullrich (2021).&amp;lt;ref name=&amp;quot;lean4&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 &#039;&#039;Automated Deduction – CADE 28&#039;&#039;, Lecture Notes in Computer Science 12699, Springer, 2021, pp. 625–635. doi:10.1007/978-3-030-79876-5_37. Author&#039;s copy: https://lean-lang.org/papers/lean4.pdf&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Mathlib&#039;s own account of itself (2020).&amp;lt;ref name=&amp;quot;cpp2020&amp;quot;&amp;gt;The mathlib Community, &amp;quot;The Lean Mathematical Library&amp;quot;, in &#039;&#039;Proceedings of the 9th ACM SIGPLAN International Conference on Certified Programs and Proofs (CPP 2020)&#039;&#039;, ACM, 2020, pp. 367–381. doi:10.1145/3372885.3373824. Preprint: https://arxiv.org/abs/1910.09336&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Lean&#039;s type theory written out rule by rule, with a proof of its consistency relative to set theory, for Lean 3 (2019).&amp;lt;ref name=&amp;quot;carneiro2019&amp;quot;&amp;gt;Mario Carneiro, &#039;&#039;The Type Theory of Lean&#039;&#039;, MSc thesis, Carnegie Mellon University, 2019. https://github.com/digama0/lean-type-theory/releases/tag/v1.0&amp;lt;/ref&amp;gt;&lt;br /&gt;
* A complete type checker for Lean 4 written in Lean, and work towards proving it correct (2026).&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 &#039;&#039;31st International Conference on Types for Proofs and Programs (TYPES 2025)&#039;&#039;, LIPIcs vol. 384, pp. 2:1–2:23, 2026. https://doi.org/10.4230/LIPIcs.TYPES.2025.2&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Lean&#039;s hygienic macros (2022).&amp;lt;ref name=&amp;quot;bn&amp;quot;&amp;gt;Sebastian Ullrich and Leonardo de Moura, &amp;quot;Beyond Notations: Hygienic Macro Expansion for Theorem Proving Languages&amp;quot;, &#039;&#039;Logical Methods in Computer Science&#039;&#039; 18 (2), 2022, article 1. https://doi.org/10.46298/lmcs-18(2:1)2022&amp;lt;/ref&amp;gt;&lt;br /&gt;
* The reference counting behind Lean&#039;s runtime (2019).&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 &#039;&#039;Proceedings of the 31st Symposium on Implementation and Application of Functional Languages (IFL 2019)&#039;&#039;, ACM, 2019. doi:10.1145/3412932.3412935. Preprint: https://arxiv.org/abs/1908.05647&amp;lt;/ref&amp;gt;&lt;br /&gt;
* The search behind Lean 4&#039;s type classes (2020).&amp;lt;ref name=&amp;quot;selsam&amp;quot;&amp;gt;Daniel Selsam, Sebastian Ullrich and Leonardo de Moura, &amp;quot;Tabled Typeclass Resolution&amp;quot;, arXiv:2001.04301, 2020. https://arxiv.org/abs/2001.04301&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Why mathematics might be checked by machine, and the de Bruijn criterion (2005).&amp;lt;ref name=&amp;quot;bw2005&amp;quot;&amp;gt;Henk Barendregt and Freek Wiedijk, &amp;quot;The challenge of computer mathematics&amp;quot;, &#039;&#039;Philosophical Transactions of the Royal Society A&#039;&#039; 363 (1835), 2005, pp. 2351–2375. doi:10.1098/rsta.2005.1650. Author&#039;s copy: https://www.cs.ru.nl/~freek/pubs/rspaper.pdf&amp;lt;/ref&amp;gt;&lt;br /&gt;
* What it takes to believe a proof a machine has checked (1998).&amp;lt;ref name=&amp;quot;pollack&amp;quot;&amp;gt;R. Pollack, &amp;quot;How to believe a machine-checked proof&amp;quot;, in G. Sambin and J. M. Smith (eds), &#039;&#039;Twenty Five Years of Constructive Type Theory&#039;&#039;, Oxford University Press, 1998; first issued as BRICS Report RS-97-18, Aarhus University, 1997. https://doi.org/10.7146/brics.v4i18.18945&amp;lt;/ref&amp;gt;&lt;br /&gt;
* The history of LCF and its descendants, by a participant (2000).&amp;lt;ref name=&amp;quot;gordon2000&amp;quot;&amp;gt;Mike Gordon, &amp;quot;From LCF to HOL: a short history&amp;quot;, in G. Plotkin, C. Stirling and M. Tofte (eds), &#039;&#039;Proof, Language, and Interaction: Essays in Honour of Robin Milner&#039;&#039;, MIT Press, 2000. Author&#039;s copy: https://www.cl.cam.ac.uk/~mjcg/papers/HolHistory.pdf&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Every work cited in the edition is listed in the [[Lean theorem prover/Bibliography|Bibliography]].&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover|Lean theorem prover]], the start of the edition.&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>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/Bibliography&amp;diff=6820</id>
		<title>Lean theorem prover/Bibliography</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Bibliography&amp;diff=6820"/>
		<updated>2026-10-15T19:35:52Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Bibliography}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
&lt;br /&gt;
Every work cited on the pages of this edition, listed once, with the pages that cite it in reading order. There are 277: 86 papers and books; 114 items of Lean documentation and source, 52 of them parts of the reference manual; 64 project pages and announcements; and 13 press articles and encyclopedia entries.&lt;br /&gt;
&lt;br /&gt;
Two citations are taken to be one work when they share a DOI, an arXiv number or a web address. A preprint and its published version are listed apart when the pages cite them apart, and so is each version of a document that changes with Lean: a chapter of the reference manual cited in its edition for Lean 4.34.0 on some pages and for Lean 4.35.0 on others appears twice, once under each address.&lt;br /&gt;
&lt;br /&gt;
Where pages cite one work in different forms, the form given here is the fullest, and a note says what differs when it is more than punctuation, capitals or the sections a page names. The 19 works that were not read, or were read only in part, are marked; [[Lean theorem prover/Sources|the sources page]] says what each one carries and what carries it instead.&lt;br /&gt;
&lt;br /&gt;
== Papers and books ==&lt;br /&gt;
&lt;br /&gt;
* Andreas Abel and Thierry Coquand, &amp;quot;Failure of normalization in impredicative type theory with proof-irrelevant propositional equality&amp;quot;, &#039;&#039;Logical Methods in Computer Science&#039;&#039; 16(2) (2020), paper 14. https://doi.org/10.23638/LMCS-16(2:14)2020 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Foundations/Universes and Prop|Universes and Prop]], [[Lean theorem prover/Foundations/Definitional equality|Definitional equality]], [[Lean theorem prover/Foundations/Proof irrelevance and subsingleton elimination|Proof irrelevance and subsingleton elimination]], [[Lean theorem prover/Foundations/Consistency and the metatheory|Consistency and the metatheory]].&lt;br /&gt;
* Anne Baanen, &amp;quot;Use and Abuse of Instance Parameters in the Lean Mathematical Library&amp;quot;, in &#039;&#039;13th International Conference on Interactive Theorem Proving (ITP 2022)&#039;&#039;, Leibniz International Proceedings in Informatics 237, Schloss Dagstuhl, 2022, pp. 4:1–4:20. doi:10.4230/LIPIcs.ITP.2022.4 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Type classes and instance resolution|Type classes and instance resolution]].&lt;br /&gt;
* Anne Baanen, Matthew R. Ballard, Johan Commelin, Bryan Gin-ge Chen, Michael Rothgang and Damiano Testa, &amp;quot;Growing Mathlib: maintenance of a large scale mathematical library&amp;quot;, arXiv:2508.21593, version 2, 7 October 2025; to appear at the Conference on Intelligent Computer Mathematics (CICM) 2025. [https://arxiv.org/abs/2508.21593 arxiv.org/abs/2508.21593] &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Checking a proof again later|Checking a proof again later]], [[Lean theorem prover/Explainers/A library of mathematics|A library of mathematics]].&lt;br /&gt;
* Henk Barendregt and Freek Wiedijk, &amp;quot;The challenge of computer mathematics&amp;quot;, &#039;&#039;Philosophical Transactions of the Royal Society A&#039;&#039; 363 (1835), 2005, pp. 2351–2375. doi:10.1098/rsta.2005.1650. Author&#039;s copy: https://www.cs.ru.nl/~freek/pubs/rspaper.pdf &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/The small trusted core|The small trusted core]], [[Lean theorem prover/History/Automath|Automath]], [[Lean theorem prover/Further reading|Further reading]].&lt;br /&gt;
* Lars Becker, María Inés de Frutos-Fernández, Leo Diedering, Floris van Doorn, Sébastien Gouëzel, et al., &amp;quot;A blueprint for the formalization of Carleson&#039;s theorem on convergence of Fourier series&amp;quot;, arXiv:2405.06423, May 2024 (revised 6 August 2025). https://arxiv.org/abs/2405.06423 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Research mathematics|Research mathematics]].&lt;br /&gt;
* Maxwell P. Bobbin, Colin Jones, John Velkey and Tyler R. Josephson, &amp;quot;Formalizing dimensional analysis using the Lean theorem prover&amp;quot;, arXiv:2509.13142, 16 September 2025. [https://arxiv.org/abs/2509.13142 arxiv.org/abs/2509.13142] &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Lean and physics|Lean and physics]].&lt;br /&gt;
* Matthew Bolan, Joachim Breitner, Jose Brox, et al. (34 authors, including Terence Tao), &amp;quot;The Equational Theories Project: Advancing Collaborative Mathematical Research at Scale&amp;quot;, arXiv:2512.07087, December 2025 (revised 16 December 2025). https://arxiv.org/abs/2512.07087 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Research mathematics|Research mathematics]], [[Lean theorem prover/Applications/The polynomial Freiman-Ruzsa conjecture|The polynomial Freiman-Ruzsa conjecture]], [[Lean theorem prover/Applications/The equational theories project|The equational theories project]], [[Lean theorem prover/Applications/Machine learning and theorem proving|Machine learning and theorem proving]].&lt;br /&gt;
* Ana Bove, Peter Dybjer and Ulf Norell, &amp;quot;A brief overview of Agda – a functional language with dependent types&amp;quot;, in &#039;&#039;Theorem Proving in Higher Order Logics (TPHOLs 2009)&#039;&#039;, Lecture Notes in Computer Science 5674, Springer, 2009, pp. 73–78. doi:10.1007/978-3-642-03359-9_6 &#039;&#039;Not read: the pages rest on its bibliographic record or on a secondary account (see [[Lean theorem prover/Sources|Sources]]).&#039;&#039; &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]].&lt;br /&gt;
* N. G. de Bruijn, &amp;quot;The mathematical language AUTOMATH, its usage, and some of its extensions&amp;quot;, in &#039;&#039;Symposium on Automatic Demonstration&#039;&#039;, Lecture Notes in Mathematics 125, Springer, 1970, pp. 29–61. doi:10.1007/BFb0060623. Scan in the Automath Archive: https://automath.win.tue.nl/archive/pdf/aut002.pdf &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Automath|Automath]].&lt;br /&gt;
* N. G. de Bruijn, &amp;quot;Lambda calculus notation with nameless dummies, a tool for automatic formula manipulation, with application to the Church-Rosser theorem&amp;quot;, &#039;&#039;Indagationes Mathematicae&#039;&#039; 34 (= &#039;&#039;Proceedings KNAW&#039;&#039; A 75), 1972, pp. 381–392. doi:10.1016/1385-7258(72)90034-0. Reprint from &#039;&#039;Selected Papers on Automath&#039;&#039; in the Eindhoven repository: https://alexandria.tue.nl/repository/freearticles/597619.pdf &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]], [[Lean theorem prover/History/Automath|Automath]].&amp;lt;ref&amp;gt;[[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]] gives the journal as &#039;&#039;Indagationes Mathematicae (Proceedings)&#039;&#039; 75 (5); [[Lean theorem prover/History/Automath|Automath]] gives both numberings, as above.&amp;lt;/ref&amp;gt;&lt;br /&gt;
* N. G. de Bruijn, &amp;quot;A survey of the project Automath&amp;quot;, in J. P. Seldin and J. R. Hindley (eds.), &#039;&#039;To H. B. Curry: Essays on Combinatory Logic, Lambda Calculus and Formalism&#039;&#039;, Academic Press, 1980, pp. 579–606; reprinted in Nederpelt, Geuvers and de Vrijer (eds.), &#039;&#039;Selected Papers on Automath&#039;&#039; (1994), pp. 141–161. Scan in the Automath Archive: https://automath.win.tue.nl/archive/pdf/aut072.pdf &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Automath|Automath]].&lt;br /&gt;
* Kevin Buzzard, Johan Commelin and Patrick Massot, &amp;quot;Formalising perfectoid spaces&amp;quot;, in &#039;&#039;CPP 2020: Proceedings of the 9th ACM SIGPLAN International Conference on Certified Programs and Proofs&#039;&#039;, 2020, pp. 299–312. doi:10.1145/3372885.3373830. arXiv:1910.12320 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Research mathematics|Research mathematics]], [[Lean theorem prover/Applications/Teaching with Lean|Teaching with Lean]].&lt;br /&gt;
* Mario Carneiro, &#039;&#039;The Type Theory of Lean&#039;&#039;, MSc thesis, Carnegie Mellon University, 2019. https://github.com/digama0/lean-type-theory/releases/tag/v1.0 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]], [[Lean theorem prover/Foundations/Dependent function types|Dependent function types]], [[Lean theorem prover/Foundations/Universes and Prop|Universes and Prop]], [[Lean theorem prover/Foundations/Inductive types and recursors|Inductive types and recursors]], [[Lean theorem prover/Foundations/Definitional equality|Definitional equality]], [[Lean theorem prover/Foundations/Propositional equality|Propositional equality]], [[Lean theorem prover/Foundations/Quotient types|Quotient types]], [[Lean theorem prover/Foundations/The three axioms|The three axioms]], [[Lean theorem prover/Foundations/Proof irrelevance and subsingleton elimination|Proof irrelevance and subsingleton elimination]], [[Lean theorem prover/Foundations/Consistency and the metatheory|Consistency and the metatheory]], [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]], [[Lean theorem prover/Further reading|Further reading]].&amp;lt;ref&amp;gt;[[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]] cites the PDF attached to the release, as a thesis of April 2019; the other pages cite the release page.&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Mario Carneiro, &amp;quot;Lean4Lean: Verifying a Typechecker for Lean, in Lean&amp;quot;, arXiv:2403.14064, version 3, 14 September 2025. [https://arxiv.org/abs/2403.14064 arxiv.org/abs/2403.14064] &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/What has to be trusted|What has to be trusted]], [[Lean theorem prover/Explainers/Checking a proof again later|Checking a proof again later]], [[Lean theorem prover/Foundations/Consistency and the metatheory|Consistency and the metatheory]].&amp;lt;ref&amp;gt;[[Lean theorem prover/Explainers/Checking a proof again later|Checking a proof again later]], [[Lean theorem prover/Explainers/What has to be trusted|What has to be trusted]] and [[Lean theorem prover/Foundations/Consistency and the metatheory|Consistency and the metatheory]] cite version 3 of the arXiv text, of 14 September 2025. The paper&#039;s TYPES 2025 version is listed separately; [[Lean theorem prover/Foundations/Definitional equality|Definitional equality]], [[Lean theorem prover/Foundations/Inductive types and recursors|Inductive types and recursors]] and [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]] cite that version and say they read version 2 of the arXiv text.&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Mario Carneiro, &amp;quot;Lean4Lean: Verifying a Typechecker for Lean, in Lean&amp;quot;, in &#039;&#039;31st International Conference on Types for Proofs and Programs (TYPES 2025)&#039;&#039;, Leibniz International Proceedings in Informatics 384, Schloss Dagstuhl, 2026, pp. 2:1–2:23. [https://doi.org/10.4230/LIPIcs.TYPES.2025.2 doi:10.4230/LIPIcs.TYPES.2025.2]; preprint [https://arxiv.org/abs/2403.14064 arXiv:2403.14064]. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Two kinds of equality|Two kinds of equality]], [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]], [[Lean theorem prover/Foundations/Inductive types and recursors|Inductive types and recursors]], [[Lean theorem prover/Foundations/Definitional equality|Definitional equality]], [[Lean theorem prover/System/Proof export and independent checkers|Proof export and independent checkers]], [[Lean theorem prover/Further reading|Further reading]].&amp;lt;ref&amp;gt;[[Lean theorem prover/Foundations/Definitional equality|Definitional equality]], [[Lean theorem prover/Foundations/Inductive types and recursors|Inductive types and recursors]] and [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]] say they read the text in arXiv version 2; [[Lean theorem prover/Explainers/Two kinds of equality|Two kinds of equality]] calls the arXiv text a preprint, [[Lean theorem prover/System/Proof export and independent checkers|Proof export and independent checkers]] its full version. Version 3 of the arXiv text is listed separately.&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Alonzo Church, &amp;quot;A note on the Entscheidungsproblem&amp;quot;, &#039;&#039;Journal of Symbolic Logic&#039;&#039; 1 (1936), pp. 40–41. doi:10.2307/2269326 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Automation and its limits|Automation and its limits]].&lt;br /&gt;
* R. L. Constable, S. F. Allen, H. M. Bromley, W. R. Cleaveland, J. F. Cremer, R. W. Harper, D. J. Howe, T. B. Knoblock, N. P. Mendler, P. Panangaden, J. T. Sasaki and S. F. Smith, &#039;&#039;Implementing Mathematics with the Nuprl Proof Development System&#039;&#039;, Prentice-Hall, 1986. ISBN 0-13-451832-2. Catalogue record: https://openlibrary.org/books/OL2715187M &#039;&#039;Not read: the pages rest on its bibliographic record or on a secondary account (see [[Lean theorem prover/Sources|Sources]]).&#039;&#039; &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]].&lt;br /&gt;
* Thierry Coquand and Gérard Huet, &amp;quot;Constructions: a higher order proof system for mechanizing mathematics&amp;quot;, in &#039;&#039;EUROCAL &#039;85&#039;&#039;, Lecture Notes in Computer Science 203, Springer, 1985, pp. 151–184. doi:10.1007/3-540-15983-5_13 &#039;&#039;Not read: the pages rest on its bibliographic record or on a secondary account (see [[Lean theorem prover/Sources|Sources]]).&#039;&#039; &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]].&lt;br /&gt;
* Thierry Coquand and Gérard Huet, &amp;quot;The calculus of constructions&amp;quot;, INRIA Research Report RR-0530, May 1986. https://inria.hal.science/inria-00076024 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]].&lt;br /&gt;
* Thierry Coquand and Gérard Huet, &amp;quot;The calculus of constructions&amp;quot;, &#039;&#039;Information and Computation&#039;&#039; 76(2–3), 1988, pp. 95–120. https://doi.org/10.1016/0890-5401(88)90005-3 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Foundations/Universes and Prop|Universes and Prop]], [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]].&amp;lt;ref&amp;gt;Read for [[Lean theorem prover/Foundations/Universes and Prop|Universes and Prop]]; [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]] cites it from its bibliographic record.&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Thierry Coquand and Christine Paulin, &amp;quot;Inductively defined types&amp;quot;, in P. Martin-Löf and G. Mints (eds.), &#039;&#039;COLOG-88&#039;&#039;, Lecture Notes in Computer Science 417, Springer, 1990, pp. 50–66. doi:10.1007/3-540-52335-9_47 &#039;&#039;Not read: the pages rest on its bibliographic record or on a secondary account (see [[Lean theorem prover/Sources|Sources]]).&#039;&#039; &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]].&lt;br /&gt;
* H. B. Curry, &amp;quot;Functionality in combinatory logic&amp;quot;, &#039;&#039;Proceedings of the National Academy of Sciences&#039;&#039; 20 (11), 1934, pp. 584–590. [https://doi.org/10.1073/pnas.20.11.584 doi:10.1073/pnas.20.11.584] &#039;&#039;Not read: the pages rest on its bibliographic record or on a secondary account (see [[Lean theorem prover/Sources|Sources]]).&#039;&#039; &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Propositions as types|Propositions as types]].&lt;br /&gt;
* Joseph W. Cutler, Craig Disselkoen, Aaron Eline, et al., &amp;quot;Cedar: A New Language for Expressive, Fast, Safe, and Analyzable Authorization&amp;quot;, &#039;&#039;Proceedings of the ACM on Programming Languages&#039;&#039; 8 (OOPSLA1), 2024, pp. 670–697. doi:10.1145/3649835 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Software verification|Software verification]].&lt;br /&gt;
* Radu Diaconescu, &amp;quot;Axiom of choice and complementation&amp;quot;, &#039;&#039;Proceedings of the American Mathematical Society&#039;&#039; 51 (1), 1975, pp. 176–178. [https://doi.org/10.1090/S0002-9939-1975-0373893-X doi:10.1090/S0002-9939-1975-0373893-X] &#039;&#039;Not read: the pages rest on its bibliographic record or on a secondary account (see [[Lean theorem prover/Sources|Sources]]).&#039;&#039; &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/What the axioms are|What the axioms are]], [[Lean theorem prover/Foundations/Classical logic from choice|Classical logic from choice]].&lt;br /&gt;
* Craig Disselkoen, Aaron Eline, Shaobo He, et al., &amp;quot;How We Built Cedar: A Verification-Guided Approach&amp;quot;, in &#039;&#039;Companion Proceedings of the 32nd ACM International Conference on the Foundations of Software Engineering (FSE Companion &#039;24)&#039;&#039;, 2024. doi:10.1145/3663529.3663854. arXiv:2407.01688 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Software verification|Software verification]].&lt;br /&gt;
* Floris van Doorn, Jakob von Raumer and Ulrik Buchholtz, &amp;quot;Homotopy type theory in Lean&amp;quot;, in &#039;&#039;Interactive Theorem Proving (ITP 2017)&#039;&#039;, Lecture Notes in Computer Science 10499, Springer, 2017, pp. 479–495. doi:10.1007/978-3-319-66107-0_30. Preprint: https://arxiv.org/abs/1704.06781 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Lean 1 to Lean 3|Lean 1 to Lean 3]].&lt;br /&gt;
* Peter Dybjer, &amp;quot;Inductive families&amp;quot;, &#039;&#039;Formal Aspects of Computing&#039;&#039; 6(4), 1994, pp. 440–465. https://doi.org/10.1007/BF01211308 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Foundations/Inductive types and recursors|Inductive types and recursors]].&lt;br /&gt;
* Gabriel Ebner, Sebastian Ullrich, Jared Roesch, Jeremy Avigad and Leonardo de Moura, &amp;quot;A metaprogramming framework for formal verification&amp;quot;, &#039;&#039;Proceedings of the ACM on Programming Languages&#039;&#039; 1 (ICFP), article 34, 2017. doi:10.1145/3110278. Author&#039;s copy: https://lean-lang.org/papers/tactic.pdf &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]], [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]], [[Lean theorem prover/History/Lean 1 to Lean 3|Lean 1 to Lean 3]], [[Lean theorem prover/Further reading|Further reading]].&lt;br /&gt;
* Herman Geuvers, &amp;quot;Proof assistants: history, ideas and future&amp;quot;, &#039;&#039;Sādhanā&#039;&#039; 34 (1), 2009, pp. 3–25. [https://doi.org/10.1007/s12046-009-0001-5 doi:10.1007/s12046-009-0001-5] &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/What a proof assistant does|What a proof assistant does]], [[Lean theorem prover/Explainers/Checking instead of convincing|Checking instead of convincing]].&lt;br /&gt;
* Herman Geuvers and Rob Nederpelt, &amp;quot;Characteristics of de Bruijn&#039;s early proof checker Automath&amp;quot;, &#039;&#039;Fundamenta Informaticae&#039;&#039; 185 (4), 2022, pp. 313–336. doi:10.3233/FI-222112. Preprint: https://arxiv.org/abs/2203.01173 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Automath|Automath]].&lt;br /&gt;
* Kurt Gödel, &amp;quot;Über formal unentscheidbare Sätze der Principia Mathematica und verwandter Systeme I&amp;quot;, &#039;&#039;Monatshefte für Mathematik und Physik&#039;&#039; 38 (1931), 173–198. https://doi.org/10.1007/BF01700692 &#039;&#039;Not read: the pages rest on its bibliographic record or on a secondary account (see [[Lean theorem prover/Sources|Sources]]).&#039;&#039; &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Automation and its limits|Automation and its limits]], [[Lean theorem prover/Foundations/Consistency and the metatheory|Consistency and the metatheory]].&lt;br /&gt;
* Warren D. Goldfarb, &amp;quot;The undecidability of the second-order unification problem&amp;quot;, &#039;&#039;Theoretical Computer Science&#039;&#039; 13(2), 1981, pp. 225–230. doi:10.1016/0304-3975(81)90040-2. Not consulted directly; the result is stated, with this citation, in the introduction of Miller 1991. &#039;&#039;Not read: the pages rest on its bibliographic record or on a secondary account (see [[Lean theorem prover/Sources|Sources]]).&#039;&#039; &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Metavariables and unification|Metavariables and unification]].&lt;br /&gt;
* Nicolas D. Goodman and John Myhill, &amp;quot;Choice implies excluded middle&amp;quot;, &#039;&#039;Zeitschrift für mathematische Logik und Grundlagen der Mathematik&#039;&#039; 24 (1978), 461. https://doi.org/10.1002/malq.19780242514 &#039;&#039;Not read: the pages rest on its bibliographic record or on a secondary account (see [[Lean theorem prover/Sources|Sources]]).&#039;&#039; &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Foundations/Classical logic from choice|Classical logic from choice]].&lt;br /&gt;
* M. Gordon, R. Milner, L. Morris, M. Newey and C. Wadsworth, &amp;quot;A metalanguage for interactive proof in LCF&amp;quot;, in &#039;&#039;Proceedings of the 5th ACM SIGACT-SIGPLAN Symposium on Principles of Programming Languages (POPL &#039;78)&#039;&#039;, ACM, 1978, pp. 119–130. doi:10.1145/512760.512773 &#039;&#039;Not read: the pages rest on its bibliographic record or on a secondary account (see [[Lean theorem prover/Sources|Sources]]).&#039;&#039; &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]].&lt;br /&gt;
* Michael J. Gordon, Robin Milner and Christopher P. Wadsworth, &#039;&#039;Edinburgh LCF: A Mechanised Logic of Computation&#039;&#039;, Lecture Notes in Computer Science 78, Springer, 1979. doi:10.1007/3-540-09724-4 &#039;&#039;Not read: the pages rest on its bibliographic record or on a secondary account (see [[Lean theorem prover/Sources|Sources]]).&#039;&#039; &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]].&lt;br /&gt;
* Michael J. C. Gordon, &amp;quot;From LCF to HOL: a short history&amp;quot;, in Gordon Plotkin, Colin Stirling and Mads Tofte (eds), &#039;&#039;Proof, Language, and Interaction: Essays in Honour of Robin Milner&#039;&#039;, MIT Press, 2000. https://www.cl.cam.ac.uk/~mjcg/papers/HolHistory.html &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Tactics|Tactics]], [[Lean theorem prover/Explainers/Automation and its limits|Automation and its limits]], [[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]], [[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]], [[Lean theorem prover/Further reading|Further reading]].&amp;lt;ref&amp;gt;[[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]] and [[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]] cite the author&#039;s PDF copy, www.cl.cam.ac.uk/~mjcg/papers/HolHistory.pdf, under the name Mike Gordon; [[Lean theorem prover/Explainers/Automation and its limits|Automation and its limits]] and [[Lean theorem prover/Explainers/Tactics|Tactics]] cite the HTML copy given here.&amp;lt;/ref&amp;gt;&lt;br /&gt;
* W. T. Gowers, Ben Green, Freddie Manners and Terence Tao, &amp;quot;On a conjecture of Marton&amp;quot;, arXiv:2311.05762, 9 November 2023 (revised 12 December 2023). https://arxiv.org/abs/2311.05762 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/The polynomial Freiman-Ruzsa conjecture|The polynomial Freiman-Ruzsa conjecture]].&lt;br /&gt;
* W. T. Gowers, Ben Green, Freddie Manners and Terence Tao, &amp;quot;Marton&#039;s Conjecture in abelian groups with bounded torsion&amp;quot;, arXiv:2404.02244, 2 April 2024. https://arxiv.org/abs/2404.02244 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/The polynomial Freiman-Ruzsa conjecture|The polynomial Freiman-Ruzsa conjecture]].&lt;br /&gt;
* W. T. Gowers, Ben Green, Freddie Manners and Terence Tao, &amp;quot;On a conjecture of Marton&amp;quot;, &#039;&#039;Annals of Mathematics&#039;&#039; 201 (2025), no. 2, pp. 515–549. doi:10.4007/annals.2025.201.2.5 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/The polynomial Freiman-Ruzsa conjecture|The polynomial Freiman-Ruzsa conjecture]].&lt;br /&gt;
* Thomas C. Hales, &amp;quot;A proof of the Kepler conjecture&amp;quot;, &#039;&#039;Annals of Mathematics&#039;&#039; 162 (3), 2005, pp. 1065–1185. [https://doi.org/10.4007/annals.2005.162.1065 doi:10.4007/annals.2005.162.1065] &#039;&#039;Not read: the pages rest on its bibliographic record or on a secondary account (see [[Lean theorem prover/Sources|Sources]]).&#039;&#039; &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Checking instead of convincing|Checking instead of convincing]].&lt;br /&gt;
* Thomas Hales and 21 co-authors, &amp;quot;A formal proof of the Kepler conjecture&amp;quot;, &#039;&#039;Forum of Mathematics, Pi&#039;&#039; 5, e2, 2017. [https://doi.org/10.1017/fmp.2017.1 doi:10.1017/fmp.2017.1]; preprint [https://arxiv.org/abs/1501.02155 arXiv:1501.02155]. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/What a proof assistant does|What a proof assistant does]], [[Lean theorem prover/Explainers/Checking instead of convincing|Checking instead of convincing]].&lt;br /&gt;
* Sidharth Hariharan, Christopher Birkbeck, Seewoo Lee, Ho Kiu Gareth Ma, Bhavik Mehta, Auguste Poiroux and Maryna Viazovska, &amp;quot;Progress in Formalizing Sphere Packing in Dimension 8&amp;quot;, arXiv:2604.23468, April 2026 (revised May 2026). https://arxiv.org/abs/2604.23468 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Research mathematics|Research mathematics]], [[Lean theorem prover/Applications/Machine learning and theorem proving|Machine learning and theorem proving]].&lt;br /&gt;
* Son Ho and Jonathan Protzenko, &amp;quot;Aeneas: Rust verification by functional translation&amp;quot;, &#039;&#039;Proceedings of the ACM on Programming Languages&#039;&#039; 6 (ICFP), 2022, pp. 711–741. doi:10.1145/3547647 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Software verification|Software verification]].&lt;br /&gt;
* W. A. Howard, &amp;quot;The formulae-as-types notion of construction&amp;quot;, in J. P. Seldin and J. R. Hindley (eds.), &#039;&#039;To H. B. Curry: Essays on Combinatory Logic, Lambda Calculus and Formalism&#039;&#039;, Academic Press, 1980, pp. 479–490. Written and circulated in 1969. &#039;&#039;Not read: the pages rest on its bibliographic record or on a secondary account (see [[Lean theorem prover/Sources|Sources]]).&#039;&#039; &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Propositions as types|Propositions as types]].&lt;br /&gt;
* Thomas Hubert, Rishi Mehta, Laurent Sartran, et al., &amp;quot;Olympiad-level formal mathematical reasoning with reinforcement learning&amp;quot;, &#039;&#039;Nature&#039;&#039; 651, pp. 607–613, published online 12 November 2025. doi:10.1038/s41586-025-09833-y &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Machine learning and theorem proving|Machine learning and theorem proving]].&lt;br /&gt;
* Gérard P. Huet, &amp;quot;A unification algorithm for typed λ-calculus&amp;quot;, &#039;&#039;Theoretical Computer Science&#039;&#039; 1(1), 1975, pp. 27–57. doi:10.1016/0304-3975(75)90011-0 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Metavariables and unification|Metavariables and unification]].&lt;br /&gt;
* Antonius J. C. Hurkens, &amp;quot;A simplification of Girard&#039;s paradox&amp;quot;, in &#039;&#039;Typed Lambda Calculi and Applications&#039;&#039; (TLCA 1995), Lecture Notes in Computer Science 902, Springer, 1995, pp. 266–278. https://doi.org/10.1007/BFb0014058 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Foundations/Universes and Prop|Universes and Prop]], [[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]].&amp;lt;ref&amp;gt;Read for [[Lean theorem prover/Foundations/Universes and Prop|Universes and Prop]]; [[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]] cites it from its bibliographic record.&amp;lt;/ref&amp;gt;&lt;br /&gt;
* L. S. van Benthem Jutting, &#039;&#039;Checking Landau&#039;s &amp;quot;Grundlagen&amp;quot; in the Automath System&#039;&#039;, Mathematical Centre Tracts 83, Mathematisch Centrum, Amsterdam, 1979. ISBN 90-6196-147-5. Record and scan: https://ir.cwi.nl/pub/13104 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Automath|Automath]].&lt;br /&gt;
* Jeffrey C. Lagarias, &amp;quot;The 3x+1 problem: an annotated bibliography (1963–1999) (sorted by author)&amp;quot;, arXiv:math/0309224 (2003, revised 2011). https://arxiv.org/abs/math/0309224 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Functions that always finish|Functions that always finish]].&lt;br /&gt;
* Per Martin-Löf, &amp;quot;An intuitionistic theory of types&amp;quot;, written 1972 at the University of Stockholm; published in G. Sambin and J. M. Smith (eds.), &#039;&#039;Twenty-Five Years of Constructive Type Theory&#039;&#039;, Oxford University Press, 1998, pp. 127–172. Copy of the 1972 text: https://archive-pml.github.io/martin-lof/pdfs/An-Intuitionistic-Theory-of-Types-1972.pdf &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]].&lt;br /&gt;
* Per Martin-Löf, &amp;quot;An intuitionistic theory of types: predicative part&amp;quot;, in H. E. Rose and J. C. Shepherdson (eds.), &#039;&#039;Logic Colloquium &#039;73&#039;&#039;, Studies in Logic and the Foundations of Mathematics 80, North-Holland, 1975, pp. 73–118. doi:10.1016/S0049-237X(08)71945-1 &#039;&#039;Not read: the pages rest on its bibliographic record or on a secondary account (see [[Lean theorem prover/Sources|Sources]]).&#039;&#039; &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]].&lt;br /&gt;
* Per Martin-Löf, &#039;&#039;Intuitionistic Type Theory&#039;&#039;, notes by Giovanni Sambin of a series of lectures given in Padua, June 1980, Bibliopolis, Naples, 1984. Re-typeset edition: https://archive-pml.github.io/martin-lof/pdfs/Bibliopolis-Book-retypeset-1984.pdf &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]].&lt;br /&gt;
* Per Martin-Löf, &amp;quot;Constructive mathematics and computer programming&amp;quot;, in L. J. Cohen, J. Łoś, H. Pfeiffer and K.-P. Podewski (eds.), &#039;&#039;Logic, Methodology and Philosophy of Science VI&#039;&#039;, North-Holland, 1982, pp. 153–175. doi:10.1016/S0049-237X(09)70189-2 &#039;&#039;Not read: the pages rest on its bibliographic record or on a secondary account (see [[Lean theorem prover/Sources|Sources]]).&#039;&#039; &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]].&lt;br /&gt;
* Patrick Massot, Floris van Doorn and Oliver Nash, &amp;quot;Formalising the h-principle and sphere eversion&amp;quot;, arXiv:2210.07746, October 2022. https://arxiv.org/abs/2210.07746 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Research mathematics|Research mathematics]].&lt;br /&gt;
* The mathlib Community, &amp;quot;The Lean mathematical library&amp;quot;, in &#039;&#039;Proceedings of the 9th ACM SIGPLAN International Conference on Certified Programs and Proofs (CPP 2020)&#039;&#039;, ACM, 2020, pp. 367–381. [https://doi.org/10.1145/3372885.3373824 doi:10.1145/3372885.3373824]; also arXiv:1910.09336. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/A library of mathematics|A library of mathematics]], [[Lean theorem prover/System/Type classes and instance resolution|Type classes and instance resolution]], [[Lean theorem prover/History/Mathlib and its community|Mathlib and its community]], [[Lean theorem prover/Applications/Research mathematics|Research mathematics]], [[Lean theorem prover/Further reading|Further reading]].&lt;br /&gt;
* Conor McBride, Healfdene Goguen and James McKinna, &amp;quot;A Few Constructions on Constructors&amp;quot;, in &#039;&#039;Types for Proofs and Programs&#039;&#039; (TYPES 2004), Lecture Notes in Computer Science 3839, Springer, 2006, pp. 186–200. https://doi.org/10.1007/11617990_12 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Foundations/Structural and well-founded recursion|Structural and well-founded recursion]].&lt;br /&gt;
* Markus de Medeiros, Muhammad Naveed, Tancrède Lepoint, Temesghen Kahsai, Tristan Ravitch, Stefan Zetzsche, Anjali Joshi, Joseph Tassarotti, Aws Albarghouthi and Jean-Baptiste Tristan, &amp;quot;Verified Foundations for Differential Privacy&amp;quot;, &#039;&#039;Proceedings of the ACM on Programming Languages&#039;&#039; 9 (PLDI), 2025, pp. 1094–1118. doi:10.1145/3729294. arXiv:2412.01671 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Software verification|Software verification]].&lt;br /&gt;
* Alex Meiburg, Leonardo A. Lessa and Rodolfo R. Soldati, &amp;quot;A Formalization of the Generalized Quantum Stein&#039;s Lemma in Lean&amp;quot;, arXiv:2510.08672, October 2025. https://arxiv.org/abs/2510.08672 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Physics in Lean|Physics in Lean]].&lt;br /&gt;
* Dale Miller, &amp;quot;A logic programming language with lambda-abstraction, function variables, and simple unification&amp;quot;, &#039;&#039;Journal of Logic and Computation&#039;&#039; 1(4), 1991, pp. 497–536. doi:10.1093/logcom/1.4.497 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Metavariables and unification|Metavariables and unification]].&lt;br /&gt;
* Robin Milner, &#039;&#039;Logic for Computable Functions: Description of a Machine Implementation&#039;&#039;, Stanford Artificial Intelligence Memo AIM-169, Computer Science Report STAN-CS-72-288, Stanford University, May 1972. http://i.stanford.edu/pub/cstr/reports/cs/tr/72/288/CS-TR-72-288.pdf &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]].&lt;br /&gt;
* Robin Milner, &amp;quot;A theory of type polymorphism in programming&amp;quot;, &#039;&#039;Journal of Computer and System Sciences&#039;&#039; 17 (3), 1978, pp. 348–375. doi:10.1016/0022-0000(78)90014-4 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]].&lt;br /&gt;
* Leonardo de Moura, Soonho Kong, Jeremy Avigad, Floris van Doorn and Jakob von Raumer, &amp;quot;The Lean Theorem Prover (system description)&amp;quot;, in &#039;&#039;Automated Deduction – CADE-25&#039;&#039;, Lecture Notes in Computer Science 9195, Springer, 2015, pp. 378–388. doi:10.1007/978-3-319-21401-6_26. Author&#039;s copy: https://lean-lang.org/papers/system.pdf &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]], [[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]], [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]], [[Lean theorem prover/History/Lean 1 to Lean 3|Lean 1 to Lean 3]], [[Lean theorem prover/Further reading|Further reading]].&lt;br /&gt;
* Leonardo de Moura and Sebastian Ullrich, &amp;quot;The Lean 4 Theorem Prover and Programming Language (System Description)&amp;quot;, in &#039;&#039;Automated Deduction – CADE 28&#039;&#039;, Lecture Notes in Computer Science 12699, Springer, 2021, pp. 625–635. doi:10.1007/978-3-030-79876-5_37. Author&#039;s copy: https://lean-lang.org/papers/lean4.pdf &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/What a proof assistant does|What a proof assistant does]], [[Lean theorem prover/Explainers/Why there is no type of all types|Why there is no type of all types]], [[Lean theorem prover/Explainers/Tactics|Tactics]], [[Lean theorem prover/Explainers/The small trusted core|The small trusted core]], [[Lean theorem prover/Explainers/Programs and proofs in one language|Programs and proofs in one language]], [[Lean theorem prover/Foundations/Inductive types and recursors|Inductive types and recursors]], [[Lean theorem prover/System/Elaboration|Elaboration]], [[Lean theorem prover/System/The Lean kernel|The Lean kernel]], [[Lean theorem prover/System/Type classes and instance resolution|Type classes and instance resolution]], [[Lean theorem prover/System/The tactic framework|The tactic framework]], [[Lean theorem prover/System/Decision procedures|Decision procedures]], [[Lean theorem prover/System/Metaprogramming in Lean|Metaprogramming in Lean]], [[Lean theorem prover/System/The compiler and runtime|The compiler and runtime]], [[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]], [[Lean theorem prover/History/Lean 1 to Lean 3|Lean 1 to Lean 3]], [[Lean theorem prover/History/Lean 4|Lean 4]], [[Lean theorem prover/Applications/Principia Machina|Principia Machina]], [[Lean theorem prover/Further reading|Further reading]].&amp;lt;ref&amp;gt;[[Lean theorem prover/Applications/Principia Machina|Principia Machina]], [[Lean theorem prover/Explainers/Tactics|Tactics]], [[Lean theorem prover/Explainers/What a proof assistant does|What a proof assistant does]] and [[Lean theorem prover/Explainers/Why there is no type of all types|Why there is no type of all types]] give the title without &amp;quot;(System Description)&amp;quot;; [[Lean theorem prover/Foundations/Inductive types and recursors|Inductive types and recursors]], [[Lean theorem prover/Explainers/Programs and proofs in one language|Programs and proofs in one language]] and [[Lean theorem prover/Explainers/The small trusted core|The small trusted core]] omit the volume number 12699.&amp;lt;/ref&amp;gt;&lt;br /&gt;
* R. P. Nederpelt, J. H. Geuvers and R. C. de Vrijer (eds.), &#039;&#039;Selected Papers on Automath&#039;&#039;, Studies in Logic and the Foundations of Mathematics 133, North-Holland, Amsterdam, 1994. ISBN 0-444-89822-0. Publisher&#039;s page with contents: https://shop.elsevier.com/books/selected-papers-on-automath/nederpelt/978-0-444-89822-7 &#039;&#039;Not read: the pages rest on its bibliographic record or on a secondary account (see [[Lean theorem prover/Sources|Sources]]).&#039;&#039; &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Automath|Automath]].&lt;br /&gt;
* Ulf Norell, &#039;&#039;Towards a Practical Programming Language Based on Dependent Type Theory&#039;&#039;, PhD thesis, Chalmers University of Technology and Göteborg University, 2007. https://www.cse.chalmers.se/~ulfn/papers/thesis.pdf &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]].&lt;br /&gt;
* Azim Ospanov, Farzan Farnia and Roozbeh Yousefzadeh, &amp;quot;miniF2F-Lean Revisited: Reviewing Limitations and Charting a Path Forward&amp;quot;, arXiv:2511.03108, 5 November 2025. [https://arxiv.org/abs/2511.03108 arxiv.org/abs/2511.03108] &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Stating the right thing|Stating the right thing]].&lt;br /&gt;
* Christine Paulin-Mohring, &amp;quot;Inductive definitions in the system Coq: rules and properties&amp;quot;, in &#039;&#039;Typed Lambda Calculi and Applications (TLCA &#039;93)&#039;&#039;, Lecture Notes in Computer Science 664, Springer, 1993, pp. 328–345. doi:10.1007/BFb0037116 &#039;&#039;Not read: the pages rest on its bibliographic record or on a secondary account (see [[Lean theorem prover/Sources|Sources]]).&#039;&#039; &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Foundations/Inductive types and recursors|Inductive types and recursors]], [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]].&lt;br /&gt;
* Christine Paulin-Mohring, &amp;quot;Introduction to the Calculus of Inductive Constructions&amp;quot;, in B. Woltzenlogel Paleo and D. Delahaye (eds.), &#039;&#039;All about Proofs, Proofs for All&#039;&#039;, Studies in Logic 55, College Publications, 2015. https://inria.hal.science/hal-01094195 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]].&lt;br /&gt;
* Lawrence C. Paulson, &amp;quot;The foundation of a generic theorem prover&amp;quot;, &#039;&#039;Journal of Automated Reasoning&#039;&#039; 5 (3), 1989, pp. 363–397. doi:10.1007/BF00248324. Preprint: https://arxiv.org/abs/cs/9301105 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]].&lt;br /&gt;
* R. Pollack, &amp;quot;How to believe a machine-checked proof&amp;quot;, in Giovanni Sambin and Jan M. Smith (eds), &#039;&#039;Twenty Five Years of Constructive Type Theory&#039;&#039;, Oxford University Press, 1998, chapter 11 (from p. 205); first issued as BRICS Report RS-97-18, Aarhus University, 1997. [https://doi.org/10.7146/brics.v4i18.18945 doi:10.7146/brics.v4i18.18945] &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/The small trusted core|The small trusted core]], [[Lean theorem prover/Explainers/What has to be trusted|What has to be trusted]], [[Lean theorem prover/Explainers/Checking a proof again later|Checking a proof again later]], [[Lean theorem prover/Explainers/Stating the right thing|Stating the right thing]], [[Lean theorem prover/Further reading|Further reading]].&lt;br /&gt;
* William Pugh, &amp;quot;The Omega test: a fast and practical integer programming algorithm for dependence analysis&amp;quot;, &#039;&#039;Proceedings of the 1991 ACM/IEEE Conference on Supercomputing (Supercomputing &#039;91)&#039;&#039;, ACM, 1991, pp. 4–13. doi:10.1145/125826.125848. Read in an expanded version whose first page states that it appeared in &#039;&#039;Communications of the ACM&#039;&#039; in August 1992, there titled &amp;quot;A practical algorithm for exact array dependence analysis&amp;quot;, 35(8), pp. 102–114, doi:10.1145/135226.135233. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Decision procedures|Decision procedures]].&lt;br /&gt;
* Bertrand Russell, &amp;quot;Mathematical logic as based on the theory of types&amp;quot;, &#039;&#039;American Journal of Mathematics&#039;&#039; 30 (3), 1908, pp. 222–262. [https://doi.org/10.2307/2369948 doi:10.2307/2369948] &#039;&#039;Not read: the pages rest on its bibliographic record or on a secondary account (see [[Lean theorem prover/Sources|Sources]]).&#039;&#039; &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Why there is no type of all types|Why there is no type of all types]].&lt;br /&gt;
* Daniel Selsam, Sebastian Ullrich and Leonardo de Moura, &amp;quot;Tabled Typeclass Resolution&amp;quot;, arXiv:2001.04301 [cs.PL], 2020. https://arxiv.org/abs/2001.04301 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Type classes and instance resolution|Type classes and instance resolution]], [[Lean theorem prover/Further reading|Further reading]].&lt;br /&gt;
* Joseph Tooby-Smith, &amp;quot;Formalization of physics index notation in Lean 4&amp;quot;, arXiv:2411.07667, November 2024. https://arxiv.org/abs/2411.07667 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Physics in Lean|Physics in Lean]].&lt;br /&gt;
* Joseph Tooby-Smith, &amp;quot;HepLean: Digitalising high energy physics&amp;quot;, &#039;&#039;Computer Physics Communications&#039;&#039; 308 (2025), article 109457. [https://doi.org/10.1016/j.cpc.2024.109457 doi:10.1016/j.cpc.2024.109457]; preprint arXiv:2405.08863. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Lean and physics|Lean and physics]], [[Lean theorem prover/Applications/Physics in Lean|Physics in Lean]].&lt;br /&gt;
* Joseph Tooby-Smith, &amp;quot;Formalizing the stability of the two Higgs doublet model potential into Lean: identifying an error in the literature&amp;quot;, arXiv:2603.08139, version 2, 20 April 2026. [https://arxiv.org/abs/2603.08139 arxiv.org/abs/2603.08139] &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Lean and physics|Lean and physics]].&lt;br /&gt;
* A. M. Turing, &amp;quot;On Computable Numbers, with an Application to the Entscheidungsproblem&amp;quot;, &#039;&#039;Proceedings of the London Mathematical Society&#039;&#039;, series 2, vol. 42 (1936–37), pp. 230–265. doi:10.1112/plms/s2-42.1.230 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Functions that always finish|Functions that always finish]], [[Lean theorem prover/Explainers/Automation and its limits|Automation and its limits]].&lt;br /&gt;
* Sebastian Ullrich and Leonardo de Moura, &amp;quot;Counting Immutable Beans: Reference Counting Optimized for Purely Functional Programming&amp;quot;, in &#039;&#039;Proceedings of the 31st Symposium on Implementation and Application of Functional Languages (IFL 2019)&#039;&#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]. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/The compiler and runtime|The compiler and runtime]], [[Lean theorem prover/Further reading|Further reading]].&lt;br /&gt;
* Sebastian Ullrich and Leonardo de Moura, &amp;quot;Beyond Notations: Hygienic Macro Expansion for Theorem Proving Languages&amp;quot;, &#039;&#039;Logical Methods in Computer Science&#039;&#039; 18(2), 2022, article 1, 21 pp. Extended version of the paper in &#039;&#039;Automated Reasoning: IJCAR 2020&#039;&#039;, Lecture Notes in Computer Science 12167, Springer, 2020, pp. 167–182 (doi:10.1007/978-3-030-51054-1_10). doi:[https://doi.org/10.46298/lmcs-18(2:1)2022 10.46298/lmcs-18(2:1)2022]; preprint [https://arxiv.org/abs/2001.10490 arXiv:2001.10490]. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Syntax extension and hygienic macros|Syntax extension and hygienic macros]], [[Lean theorem prover/Further reading|Further reading]].&lt;br /&gt;
* Sebastian Ullrich and Leonardo de Moura, &amp;quot;‘do’ Unchained: Embracing Local Imperativity in a Purely Functional Language (Functional Pearl)&amp;quot;, &#039;&#039;Proceedings of the ACM on Programming Languages&#039;&#039; 6 (ICFP), article 109, August 2022, 28 pp. doi:[https://doi.org/10.1145/3547640 10.1145/3547640]; author&#039;s copy [https://lean-lang.org/papers/do.pdf lean-lang.org/papers/do.pdf]. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Monads and do-notation|Monads and do-notation]].&lt;br /&gt;
* The Univalent Foundations Program, &#039;&#039;Homotopy Type Theory: Univalent Foundations of Mathematics&#039;&#039;, Institute for Advanced Study, 2013; Notes to Chapter 1, Example 3.1.9 and §7.2. https://homotopytypetheory.org/book/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Foundations/Universes and Prop|Universes and Prop]], [[Lean theorem prover/Foundations/Propositional equality|Propositional equality]].&lt;br /&gt;
* Philip Wadler, &amp;quot;Propositions as types&amp;quot;, &#039;&#039;Communications of the ACM&#039;&#039; 58 (12), 2015, pp. 75–84. [https://doi.org/10.1145/2699407 doi:10.1145/2699407] &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/What a proof assistant does|What a proof assistant does]], [[Lean theorem prover/Explainers/Propositions as types|Propositions as types]], [[Lean theorem prover/Explainers/Two kinds of equality|Two kinds of equality]].&lt;br /&gt;
* Benjamin Werner, &amp;quot;Sets in types, types in sets&amp;quot;, in Martín Abadi and Takayasu Ito (eds.), &#039;&#039;Theoretical Aspects of Computer Software (TACS 1997)&#039;&#039;, Lecture Notes in Computer Science 1281, Springer, 1997, pp. 530–546. https://doi.org/10.1007/BFb0014566 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Foundations/Consistency and the metatheory|Consistency and the metatheory]].&lt;br /&gt;
* Freek Wiedijk, &amp;quot;A new implementation of Automath&amp;quot;, &#039;&#039;Journal of Automated Reasoning&#039;&#039; 29 (3–4), 2002, pp. 365–387. doi:10.1023/A:1021983302516. Author&#039;s copy: https://www.cs.ru.nl/~freek/aut/aut.pdf &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Automath|Automath]].&lt;br /&gt;
* Kaiyu Yang, Aidan M. Swope, Alex Gu, Rahul Chalamala, Peiyang Song, Shixing Yu, Saad Godil, Ryan Prenger and Anima Anandkumar, &amp;quot;LeanDojo: Theorem Proving with Retrieval-Augmented Language Models&amp;quot;, NeurIPS 2023 Datasets and Benchmarks Track. arXiv:2306.15626 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Machine learning and theorem proving|Machine learning and theorem proving]].&lt;br /&gt;
* Kunhao Zheng, Jesse Michael Han and Stanislas Polu, &amp;quot;MiniF2F: a cross-system benchmark for formal Olympiad-level mathematics&amp;quot;, International Conference on Learning Representations (ICLR), 2022. arXiv:2109.00110 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Machine learning and theorem proving|Machine learning and theorem proving]].&lt;br /&gt;
&lt;br /&gt;
== Lean documentation and source ==&lt;br /&gt;
&lt;br /&gt;
=== The Lean Language Reference ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, version for Lean 4.34.0, front page and table of contents. [https://lean-lang.org/doc/reference/4.34.0/ lean-lang.org/doc/reference/4.34.0/], consulted 14 October 2026. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover|Lean theorem prover]], [[Lean theorem prover/Sources|Sources]], [[Lean theorem prover/Further reading|Further reading]].&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, version 4.34.0, chapter 8 &amp;quot;Axioms&amp;quot;: the introduction, §8.2 &amp;quot;Consistency&amp;quot;, §8.3 &amp;quot;Reduction&amp;quot;, §8.4 &amp;quot;Standard Axioms&amp;quot; and §8.5 &amp;quot;Displaying Axiom Dependencies&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/Axioms/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Foundations/The three axioms|The three axioms]], [[Lean theorem prover/Sources|Sources]].&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, for Lean 4.34.0, lean-lang.org, 2026, section 20.1, &amp;quot;Natural Numbers&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/Basic-Types/Natural-Numbers/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Computation inside proofs|Computation inside proofs]], [[Lean theorem prover/Foundations/Definitional equality|Definitional equality]].&lt;br /&gt;
* &amp;quot;Build Tools and Distribution&amp;quot;, a chapter of &#039;&#039;The Lean Language Reference&#039;&#039; (edition covering Lean 4.34.0). [https://lean-lang.org/doc/reference/4.34.0/Build-Tools-and-Distribution/ lean-lang.org/doc/reference/4.34.0/Build-Tools-and-Distribution/] &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Lake and Lean projects|Lake and Lean projects]], [[Lean theorem prover/System/Proof export and independent checkers|Proof export and independent checkers]].&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, version for Lean 4.34.0, section &amp;quot;Lake&amp;quot;. [https://lean-lang.org/doc/reference/4.34.0/Build-Tools-and-Distribution/Lake/ lean-lang.org/doc/reference/4.34.0/Build-Tools-and-Distribution/Lake], consulted 14 October 2026. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/A library of mathematics|A library of mathematics]], [[Lean theorem prover/System/Lake and Lean projects|Lake and Lean projects]].&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, version for Lean 4.34.0, section &amp;quot;Managing Toolchains with Elan&amp;quot;. [https://lean-lang.org/doc/reference/4.34.0/Build-Tools-and-Distribution/Managing-Toolchains-with-Elan/ lean-lang.org/doc/reference/4.34.0/Build-Tools-and-Distribution/Managing-Toolchains-with-Elan], consulted 14 October 2026. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Checking a proof again later|Checking a proof again later]], [[Lean theorem prover/System/Lake and Lean projects|Lake and Lean projects]].&lt;br /&gt;
* Lean Developers, &#039;&#039;The Lean Language Reference&#039;&#039;, version 4.34.0, chapter &amp;quot;Coercions&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/Coercions/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Elaboration|Elaboration]], [[Lean theorem prover/System/Type classes and instance resolution|Type classes and instance resolution]].&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, version for Lean 4.34.0, section &amp;quot;Recursive Definitions&amp;quot;. [https://lean-lang.org/doc/reference/4.34.0/Definitions/Recursive-Definitions/ lean-lang.org/doc/reference/4.34.0/Definitions/Recursive-Definitions], consulted 14 October 2026. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Functions that always finish|Functions that always finish]], [[Lean theorem prover/Explainers/When Lean says no|When Lean says no]], [[Lean theorem prover/Explainers/Programs and proofs in one language|Programs and proofs in one language]], [[Lean theorem prover/Foundations/Structural and well-founded recursion|Structural and well-founded recursion]].&lt;br /&gt;
* Lean Developers, &#039;&#039;The Lean Language Reference&#039;&#039;, version 4.34.0, chapter &amp;quot;Elaboration and Compilation&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/Elaboration-and-Compilation/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Functions that always finish|Functions that always finish]], [[Lean theorem prover/Explainers/Holes and goals|Holes and goals]], [[Lean theorem prover/Explainers/When Lean says no|When Lean says no]], [[Lean theorem prover/Explainers/The small trusted core|The small trusted core]], [[Lean theorem prover/Explainers/Checking a proof again later|Checking a proof again later]], [[Lean theorem prover/Explainers/Programs and proofs in one language|Programs and proofs in one language]], [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]], [[Lean theorem prover/Foundations/Universes and Prop|Universes and Prop]], [[Lean theorem prover/Foundations/Structural and well-founded recursion|Structural and well-founded recursion]], [[Lean theorem prover/Foundations/Definitional equality|Definitional equality]], [[Lean theorem prover/System/Elaboration|Elaboration]], [[Lean theorem prover/System/The Lean kernel|The Lean kernel]], [[Lean theorem prover/System/Metaprogramming in Lean|Metaprogramming in Lean]], [[Lean theorem prover/System/The compiler and runtime|The compiler and runtime]], [[Lean theorem prover/Glossary|Glossary]].&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, version for Lean 4.34.0 (lean-lang.org, 2026), &amp;quot;Error Explanations&amp;quot;: &amp;lt;code&amp;gt;lean.synthInstanceFailed&amp;lt;/code&amp;gt;. https://lean-lang.org/doc/reference/4.34.0/Error-Explanations/About___--synthInstanceFailed/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/When Lean says no|When Lean says no]].&lt;br /&gt;
* &amp;quot;Functors, Monads and do-Notation&amp;quot;, chapter of &#039;&#039;The Lean Language Reference&#039;&#039; (edition covering Lean 4.34.0), introduction and section 18.3 &amp;quot;Syntax&amp;quot;. [https://lean-lang.org/doc/reference/4.34.0/Functors___-Monads-and--do--Notation/ lean-lang.org/doc/reference/4.34.0/Functors___-Monads-and--do--Notation/]; [https://lean-lang.org/doc/reference/4.34.0/Functors___-Monads-and--do--Notation/Syntax/ …/Syntax/] &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Monads and do-notation|Monads and do-notation]].&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, section 1.1 &amp;quot;History&amp;quot;, for version 4.34.0 of Lean. https://lean-lang.org/doc/reference/4.34.0/Introduction/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Lean 1 to Lean 3|Lean 1 to Lean 3]], [[Lean theorem prover/History/Lean 4|Lean 4]], [[Lean theorem prover/History/Mathlib and its community|Mathlib and its community]], [[Lean theorem prover/History/Lean since 2023|Lean since 2023]].&lt;br /&gt;
* &amp;quot;Custom Operators&amp;quot;, section 23.1 of &#039;&#039;The Lean Language Reference&#039;&#039; (edition covering Lean 4.34.0). [https://lean-lang.org/doc/reference/4.34.0/Notations-and-Macros/Custom-Operators/ lean-lang.org/doc/reference/4.34.0/Notations-and-Macros/Custom-Operators/] &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Syntax extension and hygienic macros|Syntax extension and hygienic macros]].&lt;br /&gt;
* &amp;quot;Elaborators&amp;quot;, section 23.6 of &#039;&#039;The Lean Language Reference&#039;&#039; (edition covering Lean 4.34.0). [https://lean-lang.org/doc/reference/4.34.0/Notations-and-Macros/Elaborators/ lean-lang.org/doc/reference/4.34.0/Notations-and-Macros/Elaborators/] &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Metaprogramming in Lean|Metaprogramming in Lean]].&lt;br /&gt;
* &amp;quot;Macros&amp;quot;, section 23.5 of &#039;&#039;The Lean Language Reference&#039;&#039; (edition covering Lean 4.34.0), including 23.5.1 &amp;quot;Hygiene&amp;quot;, 23.5.3 &amp;quot;Quotation&amp;quot; and 23.5.5 &amp;quot;Defining Macros&amp;quot;. [https://lean-lang.org/doc/reference/4.34.0/Notations-and-Macros/Macros/ lean-lang.org/doc/reference/4.34.0/Notations-and-Macros/Macros/] &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Syntax extension and hygienic macros|Syntax extension and hygienic macros]], [[Lean theorem prover/System/Metaprogramming in Lean|Metaprogramming in Lean]].&lt;br /&gt;
* &amp;quot;Notations&amp;quot;, section 23.3 of &#039;&#039;The Lean Language Reference&#039;&#039; (edition covering Lean 4.34.0). [https://lean-lang.org/doc/reference/4.34.0/Notations-and-Macros/Notations/ lean-lang.org/doc/reference/4.34.0/Notations-and-Macros/Notations/] &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Syntax extension and hygienic macros|Syntax extension and hygienic macros]].&lt;br /&gt;
* &amp;quot;Foreign Function Interface&amp;quot;, section 12.4 of &#039;&#039;The Lean Language Reference&#039;&#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/] &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/The compiler and runtime|The compiler and runtime]].&lt;br /&gt;
* &amp;quot;Reference Counting&amp;quot;, section 12.2 of &#039;&#039;The Lean Language Reference&#039;&#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/] &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/The compiler and runtime|The compiler and runtime]].&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, version for Lean 4.34.0 (lean-lang.org, 2026), chapter 14, &amp;quot;Tactic Proofs&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/Tactic-Proofs/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Tactics|Tactics]], [[Lean theorem prover/Explainers/Holes and goals|Holes and goals]], [[Lean theorem prover/Explainers/Automation and its limits|Automation and its limits]], [[Lean theorem prover/System/The tactic framework|The tactic framework]].&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, version for Lean 4.34.0 (lean-lang.org, 2026), section 14.8, &amp;quot;Custom Tactics&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/Tactic-Proofs/Custom-Tactics/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Tactics|Tactics]].&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, version for Lean 4.34.0 (lean-lang.org, 2026), section 14.5, &amp;quot;Tactic Reference&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/Tactic-Proofs/Tactic-Reference/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Induction, as the machine sees it|Induction, as the machine sees it]], [[Lean theorem prover/Explainers/Tactics|Tactics]], [[Lean theorem prover/Explainers/Holes and goals|Holes and goals]], [[Lean theorem prover/Explainers/Automation and its limits|Automation and its limits]], [[Lean theorem prover/Explainers/When Lean says no|When Lean says no]], [[Lean theorem prover/Explainers/Computation inside proofs|Computation inside proofs]].&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, for Lean 4.34.0, lean-lang.org, 2026, section 13.2, &amp;quot;Function Types&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/Terms/Function-Types/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Foundations/Dependent function types|Dependent function types]].&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, for Lean 4.34.0, lean-lang.org, 2026, section 13.3, &amp;quot;Functions&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/Terms/Functions/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Notation|Notation]].&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, version for Lean 4.34.0 (lean-lang.org, 2026), chapter 16, &amp;quot;The grind tactic&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/The--grind--tactic/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Automation and its limits|Automation and its limits]], [[Lean theorem prover/System/Decision procedures|Decision procedures]], [[Lean theorem prover/History/Lean since 2023|Lean since 2023]].&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, version for Lean 4.34.0 (lean-lang.org, 2026), chapter 15, &amp;quot;The Simplifier&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/The-Simplifier/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Automation and its limits|Automation and its limits]], [[Lean theorem prover/System/Decision procedures|Decision procedures]].&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, version for Lean 4.34.0, chapter 4, &amp;quot;The Type System&amp;quot;. [https://lean-lang.org/doc/reference/4.34.0/The-Type-System/ lean-lang.org/doc/reference/4.34.0/The-Type-System/], consulted 14 October 2026. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]], [[Lean theorem prover/Foundations/Definitional equality|Definitional equality]], [[Lean theorem prover/Foundations/Proof irrelevance and subsingleton elimination|Proof irrelevance and subsingleton elimination]], [[Lean theorem prover/Glossary|Glossary]].&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, for Lean 4.34.0, lean-lang.org, 2026, section 4.1, &amp;quot;Functions&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/The-Type-System/Functions/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Foundations/Dependent function types|Dependent function types]], [[Lean theorem prover/Foundations/Structural and well-founded recursion|Structural and well-founded recursion]], [[Lean theorem prover/Foundations/Definitional equality|Definitional equality]], [[Lean theorem prover/Notation|Notation]].&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, for Lean 4.34.0, lean-lang.org, 2026, section 4.4, &amp;quot;Inductive Types&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/The-Type-System/Inductive-Types/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Building things from constructors|Building things from constructors]], [[Lean theorem prover/Explainers/Induction, as the machine sees it|Induction, as the machine sees it]], [[Lean theorem prover/Foundations/Universes and Prop|Universes and Prop]], [[Lean theorem prover/Foundations/Inductive types and recursors|Inductive types and recursors]], [[Lean theorem prover/Foundations/Structural and well-founded recursion|Structural and well-founded recursion]], [[Lean theorem prover/Foundations/Propositional equality|Propositional equality]], [[Lean theorem prover/Foundations/Proof irrelevance and subsingleton elimination|Proof irrelevance and subsingleton elimination]].&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, for Lean 4.34.0, lean-lang.org, 2026, section 4.2, &amp;quot;Propositions&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/The-Type-System/Propositions/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Foundations/Universes and Prop|Universes and Prop]], [[Lean theorem prover/Foundations/The three axioms|The three axioms]], [[Lean theorem prover/Foundations/Proof irrelevance and subsingleton elimination|Proof irrelevance and subsingleton elimination]].&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, version 4.34.0, §4.5 &amp;quot;Quotients&amp;quot;: the introduction, §4.5.5 &amp;quot;Logical Model&amp;quot;, §4.5.5.2 &amp;quot;Quotients and Inductive Types&amp;quot;, §4.5.6 &amp;quot;Quotients and Function Extensionality&amp;quot; and §4.5.7 &amp;quot;Squash Types&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/The-Type-System/Quotients/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Foundations/Propositional equality|Propositional equality]], [[Lean theorem prover/Foundations/Quotient types|Quotient types]].&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, version for Lean 4.34.0, section 4.3, &amp;quot;Universes&amp;quot;. [https://lean-lang.org/doc/reference/4.34.0/The-Type-System/Universes/ lean-lang.org/doc/reference/4.34.0/The-Type-System/Universes/], consulted 14 October 2026. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Foundations/Universes and Prop|Universes and Prop]], [[Lean theorem prover/Glossary|Glossary]].&lt;br /&gt;
* Lean Developers, &#039;&#039;The Lean Language Reference&#039;&#039;, version 4.34.0, chapter &amp;quot;Type Classes&amp;quot;, and its section &amp;quot;Instance Synthesis&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/Type-Classes/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Type classes and instance resolution|Type classes and instance resolution]].&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, version for Lean 4.34.0, section &amp;quot;Validating a Lean Proof&amp;quot;. [https://lean-lang.org/doc/reference/4.34.0/ValidatingProofs/ lean-lang.org/doc/reference/4.34.0/ValidatingProofs], consulted 14 October 2026. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Tactics|Tactics]], [[Lean theorem prover/Explainers/Holes and goals|Holes and goals]], [[Lean theorem prover/Explainers/Computation inside proofs|Computation inside proofs]], [[Lean theorem prover/Explainers/What has to be trusted|What has to be trusted]], [[Lean theorem prover/Explainers/Checking a proof again later|Checking a proof again later]], [[Lean theorem prover/Explainers/Stating the right thing|Stating the right thing]], [[Lean theorem prover/Foundations/The three axioms|The three axioms]], [[Lean theorem prover/Foundations/Consistency and the metatheory|Consistency and the metatheory]], [[Lean theorem prover/System/Elaboration|Elaboration]], [[Lean theorem prover/System/The Lean kernel|The Lean kernel]], [[Lean theorem prover/System/Decision procedures|Decision procedures]], [[Lean theorem prover/System/Syntax extension and hygienic macros|Syntax extension and hygienic macros]], [[Lean theorem prover/System/Metaprogramming in Lean|Metaprogramming in Lean]], [[Lean theorem prover/System/The compiler and runtime|The compiler and runtime]], [[Lean theorem prover/System/Lake and Lean projects|Lake and Lean projects]], [[Lean theorem prover/System/Proof export and independent checkers|Proof export and independent checkers]], [[Lean theorem prover/History/Lean since 2023|Lean since 2023]].&lt;br /&gt;
* &amp;quot;Lean 4.22.0&amp;quot;, in &amp;quot;Release Notes&amp;quot;, &#039;&#039;The Lean Language Reference&#039;&#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/] &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/The compiler and runtime|The compiler and runtime]].&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, for Lean 4.34.0, lean-lang.org, 2026, release notes, &amp;quot;Lean 4.27.0&amp;quot;, section &amp;quot;Language&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/releases/v4.27.0/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Foundations/Structural and well-founded recursion|Structural and well-founded recursion]].&lt;br /&gt;
* &amp;quot;Lean 4.28.0&amp;quot;, in &amp;quot;Release Notes&amp;quot;, &#039;&#039;The Lean Language Reference&#039;&#039; (edition covering Lean 4.34.0), section &amp;quot;External Checker&amp;quot;. [https://lean-lang.org/doc/reference/4.34.0/releases/v4.28.0/ lean-lang.org/doc/reference/4.34.0/releases/v4.28.0/] &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Proof export and independent checkers|Proof export and independent checkers]].&lt;br /&gt;
* &amp;quot;Lean 4.32.0&amp;quot;, in &amp;quot;Release Notes&amp;quot;, &#039;&#039;The Lean Language Reference&#039;&#039; (edition covering Lean 4.34.0), Highlights and Language sections. [https://lean-lang.org/doc/reference/4.34.0/releases/v4.32.0/ lean-lang.org/doc/reference/4.34.0/releases/v4.32.0/] &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Monads and do-notation|Monads and do-notation]].&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, version for Lean 4.34.0, &amp;quot;Lean 4.32.1 (2026-07-22)&amp;quot;, release notes. [https://lean-lang.org/doc/reference/4.34.0/releases/v4.32.1/ lean-lang.org/doc/reference/4.34.0/releases/v4.32.1], consulted 14 October 2026. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/What has to be trusted|What has to be trusted]], [[Lean theorem prover/History/Lean since 2023|Lean since 2023]].&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, version for Lean 4.34.0, &amp;quot;Lean 4.32.2 (2026-07-28)&amp;quot;, release notes. [https://lean-lang.org/doc/reference/4.34.0/releases/v4.32.2/ lean-lang.org/doc/reference/4.34.0/releases/v4.32.2], consulted 14 October 2026. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/What has to be trusted|What has to be trusted]], [[Lean theorem prover/History/Lean since 2023|Lean since 2023]].&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, for Lean 4.34.0, lean-lang.org, 2026, release notes, &amp;quot;Lean 4.8.0&amp;quot; (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). https://lean-lang.org/doc/reference/4.34.0/releases/v4.8.0/ and https://lean-lang.org/doc/reference/4.34.0/releases/v4.18.0/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Foundations/Structural and well-founded recursion|Structural and well-founded recursion]].&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, version for Lean 4.35.0, front page and table of contents. [https://lean-lang.org/doc/reference/4.35.0/ lean-lang.org/doc/reference/4.35.0/], consulted 14 October 2026. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Sources|Sources]].&lt;br /&gt;
* The Lean Developers, &amp;quot;Axioms&amp;quot;, &#039;&#039;The Lean Language Reference&#039;&#039;, for Lean 4.35.0, chapter 8. [https://lean-lang.org/doc/reference/4.35.0/Axioms/ lean-lang.org/doc/reference/4.35.0/Axioms/] (accessed 13 October 2026). &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Why there is no type of all types|Why there is no type of all types]], [[Lean theorem prover/Explainers/What the axioms are|What the axioms are]], [[Lean theorem prover/Sources|Sources]].&lt;br /&gt;
* The Lean Developers, &amp;quot;Finite natural numbers&amp;quot;, &#039;&#039;The Lean Language Reference&#039;&#039;, for Lean 4.35.0, section 21.3. [https://lean-lang.org/doc/reference/4.35.0/Basic-Types/Finite-Natural-Numbers/ lean-lang.org/doc/reference/4.35.0/Basic-Types/Finite-Natural-Numbers/] (accessed 14 October 2026). &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Types as specifications|Types as specifications]].&lt;br /&gt;
* The Lean Developers, &amp;quot;Subtypes&amp;quot;, &#039;&#039;The Lean Language Reference&#039;&#039;, for Lean 4.35.0, section 21.20. [https://lean-lang.org/doc/reference/4.35.0/Basic-Types/Subtypes/ lean-lang.org/doc/reference/4.35.0/Basic-Types/Subtypes/] (accessed 14 October 2026). &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Types as specifications|Types as specifications]].&lt;br /&gt;
* The Lean Developers, &amp;quot;Introduction&amp;quot;, &#039;&#039;The Lean Language Reference&#039;&#039;, for Lean 4.35.0, section 1.1, &amp;quot;History&amp;quot;. [https://lean-lang.org/doc/reference/4.35.0/Introduction/ lean-lang.org/doc/reference/4.35.0/Introduction/] (accessed 14 October 2026). &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/What a proof assistant does|What a proof assistant does]], [[Lean theorem prover/Explainers/Checking instead of convincing|Checking instead of convincing]].&lt;br /&gt;
* The Lean Developers, &amp;quot;The type system&amp;quot;, &#039;&#039;The Lean Language Reference&#039;&#039;, for Lean 4.35.0, chapter 4. [https://lean-lang.org/doc/reference/4.35.0/The-Type-System/ lean-lang.org/doc/reference/4.35.0/The-Type-System/] (accessed 13 October 2026). &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Checking instead of convincing|Checking instead of convincing]], [[Lean theorem prover/Explainers/Types as specifications|Types as specifications]], [[Lean theorem prover/Explainers/Two kinds of equality|Two kinds of equality]].&lt;br /&gt;
* The Lean Developers, &amp;quot;Propositions&amp;quot;, &#039;&#039;The Lean Language Reference&#039;&#039;, for Lean 4.35.0, section 4.2. [https://lean-lang.org/doc/reference/4.35.0/The-Type-System/Propositions/ lean-lang.org/doc/reference/4.35.0/The-Type-System/Propositions/] (accessed 13 October 2026). &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Why there is no type of all types|Why there is no type of all types]], [[Lean theorem prover/Explainers/What the axioms are|What the axioms are]].&lt;br /&gt;
* The Lean Developers, &amp;quot;Universes&amp;quot;, &#039;&#039;The Lean Language Reference&#039;&#039;, for Lean 4.35.0, section 4.3. [https://lean-lang.org/doc/reference/4.35.0/The-Type-System/Universes/ lean-lang.org/doc/reference/4.35.0/The-Type-System/Universes/] (accessed 13 October 2026). &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Why there is no type of all types|Why there is no type of all types]].&lt;br /&gt;
* The Lean Developers, &amp;quot;Validating a Lean proof&amp;quot;, &#039;&#039;The Lean Language Reference&#039;&#039;, for Lean 4.35.0. [https://lean-lang.org/doc/reference/4.35.0/ValidatingProofs/ lean-lang.org/doc/reference/4.35.0/ValidatingProofs/] (accessed 13 October 2026). &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/What a proof assistant does|What a proof assistant does]], [[Lean theorem prover/Explainers/What the axioms are|What the axioms are]], [[Lean theorem prover/Sources|Sources]].&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, version for Lean 4.35.0, &amp;quot;Release Notes&amp;quot;, list of versions with their dates. [https://lean-lang.org/doc/reference/4.35.0/releases/ lean-lang.org/doc/reference/4.35.0/releases/], consulted 14 October 2026. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Sources|Sources]].&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, &amp;quot;Release Notes&amp;quot;, list of versions with their dates (read 14 October 2026). https://lean-lang.org/doc/reference/latest/releases/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Lean since 2023|Lean since 2023]], [[Lean theorem prover/Chronology|Chronology]].&lt;br /&gt;
* &#039;&#039;The Lean Language Reference&#039;&#039;, &amp;quot;Lean 4.22.0 (2025-08-14)&amp;quot;, release notes. https://lean-lang.org/doc/reference/latest/releases/v4.22.0/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Lean since 2023|Lean since 2023]].&amp;lt;ref&amp;gt;The same notes, in the edition of the manual for Lean 4.34.0, are listed above, cited on [[Lean theorem prover/System/The compiler and runtime|The compiler and runtime]]. This citation uses the address under &amp;quot;latest&amp;quot;, which follows the newest version.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Other documentation and textbooks ===&lt;br /&gt;
&lt;br /&gt;
* Christopher A. Bailey, with contributions from the Lean community, &#039;&#039;Type Checking in Lean 4&#039;&#039; (online book), chapters &amp;quot;Weak and strong reduction&amp;quot;, &amp;quot;Definitional Equality&amp;quot; and &amp;quot;Reduction&amp;quot;. https://ammkrn.github.io/type_checking_in_lean4/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]], [[Lean theorem prover/Foundations/Definitional equality|Definitional equality]].&lt;br /&gt;
* &#039;&#039;Type Checking in Lean 4&#039;&#039;, online book, chapter &amp;quot;Trust&amp;quot;. [https://ammkrn.github.io/type_checking_in_lean4/trust/trust.html ammkrn.github.io/type_checking_in_lean4], consulted 14 October 2026. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/The small trusted core|The small trusted core]], [[Lean theorem prover/Explainers/What has to be trusted|What has to be trusted]], [[Lean theorem prover/Explainers/Programs and proofs in one language|Programs and proofs in one language]].&lt;br /&gt;
* Heather Macbeth, &#039;&#039;The Mechanics of Proof&#039;&#039;, online book for Math 2001, Fordham University, 2022–2024. https://hrmacbeth.github.io/math2001/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Teaching with Lean|Teaching with Lean]], [[Lean theorem prover/Further reading|Further reading]].&lt;br /&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] &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/The compiler and runtime|The compiler and runtime]].&lt;br /&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] &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/The compiler and runtime|The compiler and runtime]].&lt;br /&gt;
* David Thrane Christiansen, &#039;&#039;Functional Programming in Lean&#039;&#039;, front page. [https://lean-lang.org/functional_programming_in_lean/ lean-lang.org/functional_programming_in_lean/], consulted 14 October 2026. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Programs and proofs in one language|Programs and proofs in one language]], [[Lean theorem prover/Applications/Teaching with Lean|Teaching with Lean]], [[Lean theorem prover/Sources|Sources]], [[Lean theorem prover/Further reading|Further reading]].&lt;br /&gt;
* David Thrane Christiansen, &#039;&#039;Functional Programming in Lean&#039;&#039;, online book (code tested with Lean 4.33.0), section 4.5 &amp;quot;The IO Monad&amp;quot;. [https://lean-lang.org/functional_programming_in_lean/Monads/The-IO-Monad/ lean-lang.org/functional_programming_in_lean/Monads/The-IO-Monad/] &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Monads and do-notation|Monads and do-notation]].&lt;br /&gt;
* David Thrane Christiansen, &#039;&#039;Functional Programming in Lean&#039;&#039;, online book (code tested with Lean 4.33.0), section 4.4 &amp;quot;&amp;lt;code&amp;gt;do&amp;lt;/code&amp;gt;-Notation for Monads&amp;quot;. [https://lean-lang.org/functional_programming_in_lean/Monads/do--Notation-for-Monads/ lean-lang.org/functional_programming_in_lean/Monads/do--Notation-for-Monads/] &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Monads and do-notation|Monads and do-notation]].&lt;br /&gt;
* Jeremy Avigad, Leonardo de Moura, Soonho Kong and Sebastian Ullrich, &#039;&#039;Theorem Proving in Lean 4&#039;&#039;, front page. [https://lean-lang.org/theorem_proving_in_lean4/ lean-lang.org/theorem_proving_in_lean4/], consulted 14 October 2026. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Teaching with Lean|Teaching with Lean]], [[Lean theorem prover/Sources|Sources]], [[Lean theorem prover/Further reading|Further reading]].&lt;br /&gt;
* Jeremy Avigad, Leonardo de Moura, Soonho Kong and Sebastian Ullrich, with contributions from the Lean Community, &#039;&#039;Theorem Proving in Lean 4&#039;&#039;, chapter 12, &amp;quot;Axioms and Computation&amp;quot;, online book for Lean 4.33.0. [https://lean-lang.org/theorem_proving_in_lean4/Axioms-and-Computation/ lean-lang.org/theorem_proving_in_lean4/Axioms-and-Computation/] (accessed 13 October 2026). &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/What the axioms are|What the axioms are]], [[Lean theorem prover/Foundations/Quotient types|Quotient types]], [[Lean theorem prover/Foundations/The three axioms|The three axioms]], [[Lean theorem prover/Foundations/Classical logic from choice|Classical logic from choice]].&lt;br /&gt;
* Jeremy Avigad, Leonardo de Moura, Soonho Kong and Sebastian Ullrich, &#039;&#039;Theorem Proving in Lean 4&#039;&#039;, lean-lang.org (version for Lean 4.33.0), chapter 2, &amp;quot;Dependent Type Theory&amp;quot;. https://lean-lang.org/theorem_proving_in_lean4/Dependent-Type-Theory/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Types as specifications|Types as specifications]], [[Lean theorem prover/Explainers/Why there is no type of all types|Why there is no type of all types]], [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]], [[Lean theorem prover/Foundations/Dependent function types|Dependent function types]].&lt;br /&gt;
* Jeremy Avigad, Leonardo de Moura, Soonho Kong and Sebastian Ullrich, &#039;&#039;Theorem Proving in Lean 4&#039;&#039; (online edition for Lean 4.33.0, lean-lang.org), chapter 7, &amp;quot;Inductive Types&amp;quot;. https://lean-lang.org/theorem_proving_in_lean4/Inductive-Types/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Propositions as types|Propositions as types]], [[Lean theorem prover/Explainers/Two kinds of equality|Two kinds of equality]], [[Lean theorem prover/Explainers/Building things from constructors|Building things from constructors]], [[Lean theorem prover/Explainers/Induction, as the machine sees it|Induction, as the machine sees it]].&lt;br /&gt;
* Jeremy Avigad, Leonardo de Moura, Soonho Kong and Sebastian Ullrich, with contributions from the Lean Community, &#039;&#039;Theorem Proving in Lean 4&#039;&#039;, chapter 1, &amp;quot;Introduction&amp;quot;, online book for Lean 4.33.0. [https://lean-lang.org/theorem_proving_in_lean4/Introduction/ lean-lang.org/theorem_proving_in_lean4/Introduction/] (accessed 13 October 2026). &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/What a proof assistant does|What a proof assistant does]].&lt;br /&gt;
* Jeremy Avigad, Leonardo de Moura, Soonho Kong and Sebastian Ullrich, with contributions from the Lean Community, &#039;&#039;Theorem Proving in Lean 4&#039;&#039;, chapter 3, &amp;quot;Propositions and Proofs&amp;quot;, section 3.1, online book for Lean 4.33.0. [https://lean-lang.org/theorem_proving_in_lean4/Propositions-and-Proofs/ lean-lang.org/theorem_proving_in_lean4/Propositions-and-Proofs/] (accessed 13 October 2026). &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Propositions as types|Propositions as types]], [[Lean theorem prover/Explainers/Two kinds of equality|Two kinds of equality]], [[Lean theorem prover/Foundations/Classical logic from choice|Classical logic from choice]].&lt;br /&gt;
* Jeremy Avigad, Leonardo de Moura, Soonho Kong and Sebastian Ullrich, with contributions from the Lean Community, &#039;&#039;Theorem Proving in Lean 4&#039;&#039;, chapter 4, &amp;quot;Quantifiers and Equality&amp;quot;, section 4.2, &amp;quot;Equality&amp;quot;, online book for Lean 4.33.0. [https://lean-lang.org/theorem_proving_in_lean4/Quantifiers-and-Equality/ lean-lang.org/theorem_proving_in_lean4/Quantifiers-and-Equality/] (accessed 13 October 2026). &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Why there is no type of all types|Why there is no type of all types]], [[Lean theorem prover/Explainers/Two kinds of equality|Two kinds of equality]].&lt;br /&gt;
* Jeremy Avigad, Leonardo de Moura, Soonho Kong and Sebastian Ullrich, &#039;&#039;Theorem Proving in Lean 4&#039;&#039; (online edition for Lean 4.33.0, lean-lang.org), chapter 5, &amp;quot;Tactics&amp;quot;. https://lean-lang.org/theorem_proving_in_lean4/Tactics/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Tactics|Tactics]], [[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]].&amp;lt;ref&amp;gt;[[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]] cites the chapter at its earlier address, lean-lang.org/theorem_proving_in_lean4/tactics.html, which now forwards here.&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Lean community, &amp;quot;Lean projects&amp;quot; (installation instructions). [https://leanprover-community.github.io/install/project.html leanprover-community.github.io/install/project.html], consulted 14 October 2026. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/A library of mathematics|A library of mathematics]].&lt;br /&gt;
* Arthur Paulino, Damiano Testa, Edward Ayers, Evgenia Karunus, Henrik Böving, Jannis Limperg, Siddhartha Gadgil and Siddharth Bhat, &#039;&#039;Metaprogramming in Lean 4&#039;&#039;, online book, Lean community. https://leanprover-community.github.io/lean4-metaprogramming-book/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Further reading|Further reading]].&lt;br /&gt;
* Arthur Paulino, Damiano Testa, Edward Ayers, Evgenia Karunus, Henrik Böving, Jannis Limperg, Siddhartha Gadgil and Siddharth Bhat, &#039;&#039;Metaprogramming in Lean 4&#039;&#039;, online book, chapter &amp;quot;MetaM&amp;quot;. [https://leanprover-community.github.io/lean4-metaprogramming-book/main/04_metam.html leanprover-community.github.io/lean4-metaprogramming-book/main/04_metam.html] &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Holes and goals|Holes and goals]], [[Lean theorem prover/System/Metavariables and unification|Metavariables and unification]], [[Lean theorem prover/System/Metaprogramming in Lean|Metaprogramming in Lean]].&lt;br /&gt;
* J. Avigad, J. Hua, R. Y. Lewis and F. van Doorn, &#039;&#039;Logic and Proof&#039;&#039;, online textbook, Lean 4 edition, read 14 October 2026. https://leanprover-community.github.io/logic_and_proof/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Teaching with Lean|Teaching with Lean]], [[Lean theorem prover/Further reading|Further reading]].&lt;br /&gt;
* Jeremy Avigad and Patrick Massot, &#039;&#039;Mathematics in Lean&#039;&#039;, online book, read 14 October 2026. https://leanprover-community.github.io/mathematics_in_lean/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Teaching with Lean|Teaching with Lean]], [[Lean theorem prover/Further reading|Further reading]].&lt;br /&gt;
* Jeremy Avigad and Patrick Massot, &#039;&#039;Mathematics in Lean&#039;&#039;, online book, chapter 8, &amp;quot;Hierarchies&amp;quot;. https://leanprover-community.github.io/mathematics_in_lean/C08_Hierarchies.html &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Type classes and instance resolution|Type classes and instance resolution]].&lt;br /&gt;
* Kevin Buzzard, &#039;&#039;Formalising Mathematics&#039;&#039;, course handbook, Imperial College London, 2024 edition. https://www.ma.imperial.ac.uk/~buzzard/xena/formalising-mathematics-2024/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Teaching with Lean|Teaching with Lean]], [[Lean theorem prover/Further reading|Further reading]].&lt;br /&gt;
&lt;br /&gt;
=== Source code ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;Batteries&#039;&#039; (README). [https://github.com/leanprover-community/batteries github.com/leanprover-community/batteries], consulted 14 October 2026. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/A library of mathematics|A library of mathematics]].&lt;br /&gt;
* Lean 3 community edition, README file and its earlier version. https://github.com/leanprover-community/lean &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Lean 1 to Lean 3|Lean 1 to Lean 3]].&lt;br /&gt;
* Lean 3 community edition, change log (&amp;lt;code&amp;gt;doc/changes.md&amp;lt;/code&amp;gt;), entries from v3.2.0 (June 2017) to 3.51.1c (24 May 2023). https://github.com/leanprover-community/lean/blob/master/doc/changes.md &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Lean 1 to Lean 3|Lean 1 to Lean 3]].&lt;br /&gt;
* Lean 3 mathlib, README file. https://github.com/leanprover-community/mathlib &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Lean 4|Lean 4]], [[Lean theorem prover/History/Mathlib and its community|Mathlib and its community]].&lt;br /&gt;
* Mathlib, README of the Lean 4 library. https://github.com/leanprover-community/mathlib4 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Mathlib and its community|Mathlib and its community]].&lt;br /&gt;
* Mathlib, source file &amp;lt;code&amp;gt;Mathlib/Basic/Real/Basic.lean&amp;lt;/code&amp;gt;, module documentation &amp;quot;Real numbers from Cauchy sequences&amp;quot;. [https://github.com/leanprover-community/mathlib4/blob/master/Mathlib/Basic/Real/Basic.lean github.com/leanprover-community/mathlib4], consulted 14 October 2026. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Lean and physics|Lean and physics]].&lt;br /&gt;
* Mathport, README file. https://github.com/leanprover-community/mathport &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Lean 4|Lean 4]].&lt;br /&gt;
* Lean 2 source code, README file (&amp;quot;This is a snapshot of the Lean 0.2 theorem prover...&amp;quot;). https://github.com/leanprover/lean2 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Lean 1 to Lean 3|Lean 1 to Lean 3]].&lt;br /&gt;
* Lean 3 source code, README file, notice that the code is frozen and Lean 4 is the official line. https://github.com/leanprover/lean3 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Lean 1 to Lean 3|Lean 1 to Lean 3]].&lt;br /&gt;
* Lean 3 source code, version tag v3.0.0, published 20 January 2017. https://github.com/leanprover/lean3/releases/tag/v3.0.0 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Lean 1 to Lean 3|Lean 1 to Lean 3]].&lt;br /&gt;
* Lean 4 source, file &amp;lt;code&amp;gt;src/Init/Classical.lean&amp;lt;/code&amp;gt;, version 4.34.1: &amp;lt;code&amp;gt;Classical.em&amp;lt;/code&amp;gt; (&amp;quot;Diaconescu&#039;s theorem&amp;quot;), &amp;lt;code&amp;gt;Classical.choose&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Classical.propDecidable&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Init/Classical.lean &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Foundations/Classical logic from choice|Classical logic from choice]].&lt;br /&gt;
* Lean 4 source, file &amp;lt;code&amp;gt;src/Init/Core.lean&amp;lt;/code&amp;gt;, version 4.34.1: the definitions of &amp;lt;code&amp;gt;Setoid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Quotient&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Quotient.exact&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Init/Core.lean &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Foundations/Quotient types|Quotient types]], [[Lean theorem prover/System/The compiler and runtime|The compiler and runtime]].&lt;br /&gt;
* Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Init/Grind/Tactics.lean&amp;lt;/code&amp;gt;: the documentation string of the &amp;lt;code&amp;gt;grind&amp;lt;/code&amp;gt; tactic. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Init/Grind/Tactics.lean &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Decision procedures|Decision procedures]].&lt;br /&gt;
* Lean 4 source, file &amp;lt;code&amp;gt;src/Init/Prelude.lean&amp;lt;/code&amp;gt;, version 4.34.1: the &amp;lt;code&amp;gt;init_quot&amp;lt;/code&amp;gt; command and the documentation of &amp;lt;code&amp;gt;Quot&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Quot.mk&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Quot.lift&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Quot.ind&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Quot.sound&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Quot.lcInv&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Init/Prelude.lean &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Foundations/Propositional equality|Propositional equality]], [[Lean theorem prover/Foundations/Quotient types|Quotient types]], [[Lean theorem prover/System/Elaboration|Elaboration]].&lt;br /&gt;
* Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Init/Tactics.lean&amp;lt;/code&amp;gt;: the documentation strings and definitions of &amp;lt;code&amp;gt;all_goals&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;focus&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;first&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;try&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;lt;;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;repeat&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;exact?&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;apply?&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Init/Tactics.lean &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/The tactic framework|The tactic framework]], [[Lean theorem prover/System/Decision procedures|Decision procedures]].&lt;br /&gt;
* Lean 4 source code, version 4.34.1 (2026), files &amp;lt;code&amp;gt;src/Lean/Elab/Notation.lean&amp;lt;/code&amp;gt; (the functions &amp;lt;code&amp;gt;elabNotation&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;mkUnexpander&amp;lt;/code&amp;gt;) and &amp;lt;code&amp;gt;src/Lean/Elab/Macro.lean&amp;lt;/code&amp;gt; (the function &amp;lt;code&amp;gt;elabMacro&amp;lt;/code&amp;gt;). Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/Elab/Notation.lean &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Syntax extension and hygienic macros|Syntax extension and hygienic macros]].&lt;br /&gt;
* Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Lean/Elab/SyntheticMVars.lean&amp;lt;/code&amp;gt;: the function &amp;lt;code&amp;gt;synthesizeSyntheticMVars&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/Elab/SyntheticMVars.lean &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Elaboration|Elaboration]], [[Lean theorem prover/System/The tactic framework|The tactic framework]].&lt;br /&gt;
* Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Lean/Elab/Tactic/BVDecide.lean&amp;lt;/code&amp;gt;: the overview of &amp;lt;code&amp;gt;bv_decide&amp;lt;/code&amp;gt;, sections &amp;quot;Architecture&amp;quot; and &amp;quot;Axioms&amp;quot;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/Elab/Tactic/BVDecide.lean &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Decision procedures|Decision procedures]].&lt;br /&gt;
* Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Lean/Elab/Tactic/Basic.lean&amp;lt;/code&amp;gt;: the definitions &amp;lt;code&amp;gt;TacticM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Tactic&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;getGoals&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;tryCatchRestore&amp;lt;/code&amp;gt;, with the structure &amp;lt;code&amp;gt;Tactic.State&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;src/Lean/Elab/Term/TermElabM.lean&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/Elab/Tactic/Basic.lean &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/The tactic framework|The tactic framework]].&lt;br /&gt;
* Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Lean/Elab/Tactic/Omega.lean&amp;lt;/code&amp;gt;: implementation notes of the &amp;lt;code&amp;gt;omega&amp;lt;/code&amp;gt; tactic. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/Elab/Tactic/Omega.lean &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Decision procedures|Decision procedures]].&lt;br /&gt;
* Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Lean/Elab/Term/TermElabM.lean&amp;lt;/code&amp;gt;: the function &amp;lt;code&amp;gt;elabTermAux&amp;lt;/code&amp;gt; and the type &amp;lt;code&amp;gt;SyntheticMVarKind&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/Elab/Term/TermElabM.lean &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Elaboration|Elaboration]], [[Lean theorem prover/System/The tactic framework|The tactic framework]].&lt;br /&gt;
* Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Lean/Environment.lean&amp;lt;/code&amp;gt;: the structure &amp;lt;code&amp;gt;Lean.Kernel.Environment&amp;lt;/code&amp;gt;, the option &amp;lt;code&amp;gt;debug.skipKernelTC&amp;lt;/code&amp;gt; and the function &amp;lt;code&amp;gt;addDeclWithoutChecking&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/Environment.lean &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/The Lean kernel|The Lean kernel]].&lt;br /&gt;
* Lean 4 source, &amp;lt;code&amp;gt;src/Lean/Expr.lean&amp;lt;/code&amp;gt;, documentation of &amp;lt;code&amp;gt;Expr.bvar&amp;lt;/code&amp;gt;, version 4.34.1. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/Expr.lean &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Automath|Automath]].&lt;br /&gt;
* Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Lean/Message.lean&amp;lt;/code&amp;gt;: the messages for &amp;lt;code&amp;gt;Kernel.Exception&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/Message.lean &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/The Lean kernel|The Lean kernel]].&lt;br /&gt;
* Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Lean/Meta/ExprDefEq.lean&amp;lt;/code&amp;gt;: the notes on pattern unification and its approximations A1 to A7. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/Meta/ExprDefEq.lean &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Metavariables and unification|Metavariables and unification]].&lt;br /&gt;
* Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Lean/Meta/SynthInstance.lean&amp;lt;/code&amp;gt;: the notes on tabled resolution and table keys, the function &amp;lt;code&amp;gt;generate&amp;lt;/code&amp;gt;, and the notes on &amp;lt;code&amp;gt;outParam&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/Meta/SynthInstance.lean &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Type classes and instance resolution|Type classes and instance resolution]].&lt;br /&gt;
* Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Lean/MetavarContext.lean&amp;lt;/code&amp;gt;: the design notes at the head of the file. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/MetavarContext.lean &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Metavariables and unification|Metavariables and unification]], [[Lean theorem prover/System/The tactic framework|The tactic framework]].&lt;br /&gt;
* Lean 4 source, file &amp;lt;code&amp;gt;src/Lean/Parser/Term.lean&amp;lt;/code&amp;gt;, version 4.34.1: the documentation comment of the &amp;lt;code&amp;gt;h ▸ e&amp;lt;/code&amp;gt; syntax. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/Parser/Term.lean &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Foundations/Propositional equality|Propositional equality]].&lt;br /&gt;
* Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Std/Tactic/BVDecide/Reflect.lean&amp;lt;/code&amp;gt;: the definition &amp;lt;code&amp;gt;verifyBVExpr&amp;lt;/code&amp;gt; and the theorem &amp;lt;code&amp;gt;unsat_of_verifyBVExpr_eq_true&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Std/Tactic/BVDecide/Reflect.lean &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Decision procedures|Decision procedures]].&lt;br /&gt;
* Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/kernel/environment.cpp&amp;lt;/code&amp;gt;: the functions &amp;lt;code&amp;gt;add_axiom&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;add_definition&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;add_theorem&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;add_opaque&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;add_mutual&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;check_constant_val&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/kernel/environment.cpp &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/The Lean kernel|The Lean kernel]].&lt;br /&gt;
* Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/kernel/inductive.cpp&amp;lt;/code&amp;gt;: the functions &amp;lt;code&amp;gt;check_constructors&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;check_positivity&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/kernel/inductive.cpp &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/The Lean kernel|The Lean kernel]].&lt;br /&gt;
* Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/kernel/type_checker.cpp&amp;lt;/code&amp;gt;: the functions &amp;lt;code&amp;gt;is_def_eq_core&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;lazy_delta_reduction_step&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;reduce_nat&amp;lt;/code&amp;gt;; with the function &amp;lt;code&amp;gt;compare&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;src/kernel/declaration.cpp&amp;lt;/code&amp;gt;, which orders unfolding by definitional height. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/kernel/type_checker.cpp &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/The Lean kernel|The Lean kernel]].&lt;br /&gt;
* Lean 4 source code, version tag v4.0.0, published 8 September 2023. https://github.com/leanprover/lean4/releases/tag/v4.0.0 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Lean 4|Lean 4]].&lt;br /&gt;
* Lean 4 source, version 4.34.1: files &amp;lt;code&amp;gt;src/Init/Core.lean&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;propext&amp;lt;/code&amp;gt;), &amp;lt;code&amp;gt;src/Init/Prelude.lean&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;Quot.sound&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Classical.choice&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;sorryAx&amp;lt;/code&amp;gt;) and &amp;lt;code&amp;gt;src/Init/Classical.lean&amp;lt;/code&amp;gt; (the proof of &amp;lt;code&amp;gt;Classical.em&amp;lt;/code&amp;gt;). Apache License 2.0. https://github.com/leanprover/lean4/tree/v4.34.1/src/Init &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Foundations/The three axioms|The three axioms]].&lt;br /&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 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/The compiler and runtime|The compiler and runtime]].&lt;br /&gt;
* Lean 4 source code, version 4.34.1 (2026), directory &amp;lt;code&amp;gt;src/kernel&amp;lt;/code&amp;gt; (36 files &amp;lt;code&amp;gt;*.cpp&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;*.h&amp;lt;/code&amp;gt;, plus &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt;). Apache License 2.0. https://github.com/leanprover/lean4/tree/v4.34.1/src/kernel &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/The Lean kernel|The Lean kernel]].&lt;br /&gt;
* &#039;&#039;lean4checker&#039;&#039; (README of the archived project; now distributed with Lean as &amp;lt;code&amp;gt;leanchecker&amp;lt;/code&amp;gt;). [https://github.com/leanprover/lean4checker github.com/leanprover/lean4checker], consulted 13 October 2026. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Checking a proof again later|Checking a proof again later]].&lt;br /&gt;
* &#039;&#039;lean4export&#039;&#039; (README). [https://github.com/leanprover/lean4export github.com/leanprover/lean4export], consulted 13 October 2026. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Checking a proof again later|Checking a proof again later]].&lt;br /&gt;
* &amp;quot;lean4export&amp;quot;, Reservoir, the index of Lake packages: &amp;quot;A simple declaration exporter for Lean 4 using the Lean 4 NDJSON export format&amp;quot;. [https://reservoir.lean-lang.org/@leanprover/lean4export reservoir.lean-lang.org/@leanprover/lean4export] &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Proof export and independent checkers|Proof export and independent checkers]].&lt;br /&gt;
&lt;br /&gt;
== Projects and announcements ==&lt;br /&gt;
&lt;br /&gt;
* ACM SIGPLAN, &amp;quot;Programming Languages Software Award&amp;quot;, recipients, 2025: Lean Theorem Prover. https://www.sigplan.org/Awards/Software/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Lean since 2023|Lean since 2023]].&lt;br /&gt;
* Adam Topaz, &amp;quot;Definitions in the liquid tensor experiment&amp;quot;, Lean community blog, 14 October 2022. https://leanprover-community.github.io/blog/posts/lte-examples/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/The Liquid Tensor Experiment|The Liquid Tensor Experiment]].&lt;br /&gt;
* Alexander Bentkamp, Jon Eugster et al., &amp;quot;Lean 4 Game&amp;quot;, the source of the Lean Game Server: project description and list of hosted games, read 14 October 2026. https://github.com/leanprover-community/lean4game &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Teaching with Lean|Teaching with Lean]].&lt;br /&gt;
* Announcement of the 1991 ACM Turing Award to Robin Milner, with the short citation, forwarded to the TYPES mailing list, 1 November 1991. https://www.engineering.upenn.edu/~sweirich/types/archive/1991/msg00062.html &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]].&lt;br /&gt;
* Anthropic, &amp;quot;Formalizing Fermat&#039;s Last Theorem&amp;quot;, 4 September 2026. https://www.anthropic.com/research/formalizing-fermats-last-theorem &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/The Fermat&#039;s Last Theorem project|The Fermat&#039;s Last Theorem project]], [[Lean theorem prover/Applications/Machine learning and theorem proving|Machine learning and theorem proving]].&lt;br /&gt;
* CADE Inc., &amp;quot;Skolem Award&amp;quot;, with the list of recipients (awards at CADE-30, July 2025). https://cadeinc.org/Skolem-Award &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Lean since 2023|Lean since 2023]].&lt;br /&gt;
* EPFL, &amp;quot;Prof. Viazovska&#039;s proofs of sphere packing formalized with AI&amp;quot;, EPFL news, March 2026. https://actu.epfl.ch/news/prof-viazovska-s-proofs-of-sphere-packing-formaliz/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Research mathematics|Research mathematics]].&lt;br /&gt;
* Floris van Doorn et al., &amp;quot;Formalization of a generalized Carleson&#039;s theorem&amp;quot; (project description, read 13 October 2026). https://github.com/fpvandoorn/carleson &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Research mathematics|Research mathematics]].&lt;br /&gt;
* Freek Wiedijk, &amp;quot;Automath&amp;quot; (notes accompanying the aut checker). https://www.cs.ru.nl/~freek/aut/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Automath|Automath]].&lt;br /&gt;
* Google DeepMind, &amp;quot;AI achieves silver-medal standard solving International Mathematical Olympiad problems&amp;quot;, 25 July 2024. https://deepmind.google/discover/blog/ai-solves-imo-problems-at-silver-medal-level/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Lean since 2023|Lean since 2023]], [[Lean theorem prover/Applications/Machine learning and theorem proving|Machine learning and theorem proving]].&lt;br /&gt;
* &#039;&#039;Isabelle&#039;&#039;, home page. [https://isabelle.in.tum.de/ isabelle.in.tum.de] (accessed 13 October 2026). &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/What a proof assistant does|What a proof assistant does]].&lt;br /&gt;
* Johan Commelin, &amp;quot;Liquid Tensor Experiment: an update&amp;quot;, Lean community blog, 31 December 2021. https://leanprover-community.github.io/blog/posts/lte-update/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/The Liquid Tensor Experiment|The Liquid Tensor Experiment]].&lt;br /&gt;
* John Harrison, &#039;&#039;The HOL Light theorem prover&#039;&#039;, home page. [https://www.cl.cam.ac.uk/~jrh13/hol-light/ www.cl.cam.ac.uk/~jrh13/hol-light/] (accessed 14 October 2026). &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/What a proof assistant does|What a proof assistant does]].&lt;br /&gt;
* Kesha Hietala and Emina Torlak, &amp;quot;Lean Into Verified Software Development&amp;quot;, AWS Open Source Blog, 8 April 2024. https://aws.amazon.com/blogs/opensource/lean-into-verified-software-development/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Software verification|Software verification]].&lt;br /&gt;
* Kevin Buzzard, &amp;quot;A Lean formalisation of Fermat&#039;s Last Theorem&amp;quot; (the project&#039;s general information), written December 2023. https://github.com/ImperialCollegeLondon/FLT/blob/main/GENERAL.md &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Research mathematics|Research mathematics]], [[Lean theorem prover/Applications/The Fermat&#039;s Last Theorem project|The Fermat&#039;s Last Theorem project]], [[Lean theorem prover/Applications/Teaching with Lean|Teaching with Lean]].&lt;br /&gt;
* Kevin Buzzard, &amp;quot;AI at IMO 2025: a round-up&amp;quot;, &#039;&#039;Xena&#039;&#039; (blog), 3 August 2025. https://xenaproject.wordpress.com/2025/08/03/ai-at-imo-2025-a-round-up/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Machine learning and theorem proving|Machine learning and theorem proving]].&lt;br /&gt;
* Kevin Buzzard et al., &amp;quot;Fermat&#039;s Last Theorem&amp;quot; (project page and README), Imperial College London, read 14 October 2026. https://imperialcollegelondon.github.io/FLT/ and https://github.com/ImperialCollegeLondon/FLT &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/The Fermat&#039;s Last Theorem project|The Fermat&#039;s Last Theorem project]].&lt;br /&gt;
* Kevin Buzzard, &amp;quot;Fermat&#039;s Last Theorem — how it&#039;s going&amp;quot;, &#039;&#039;Xena&#039;&#039; (blog), 11 December 2024. https://xenaproject.wordpress.com/2024/12/11/fermats-last-theorem-how-its-going/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Research mathematics|Research mathematics]], [[Lean theorem prover/Applications/The Fermat&#039;s Last Theorem project|The Fermat&#039;s Last Theorem project]].&lt;br /&gt;
* Kevin Buzzard, &amp;quot;FLT: Anthropic has beaten me to it&amp;quot;, &#039;&#039;Xena&#039;&#039; (blog), 4 September 2026. https://xenaproject.wordpress.com/2026/09/04/flt-anthropic-has-beaten-me-to-it/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Research mathematics|Research mathematics]], [[Lean theorem prover/Applications/The Fermat&#039;s Last Theorem project|The Fermat&#039;s Last Theorem project]], [[Lean theorem prover/Applications/Machine learning and theorem proving|Machine learning and theorem proving]].&lt;br /&gt;
* Kevin Buzzard, &amp;quot;Formalizing Fermat workshop&amp;quot;, &#039;&#039;Xena&#039;&#039; (blog), 15 May 2026. https://xenaproject.wordpress.com/2026/05/15/formalizing-fermat-workshop/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/The Fermat&#039;s Last Theorem project|The Fermat&#039;s Last Theorem project]], [[Lean theorem prover/Applications/Machine learning and theorem proving|Machine learning and theorem proving]].&lt;br /&gt;
* Kevin Buzzard, Jon Eugster et al., &#039;&#039;Natural Number Game&#039;&#039;, Lean 4 version, game text and credits. https://github.com/leanprover-community/NNG4 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Teaching with Lean|Teaching with Lean]].&lt;br /&gt;
* Kevin Buzzard, Jon Eugster et al., &#039;&#039;Natural Number Game&#039;&#039;, Lean 4 version, on the Lean Game Server: https://adam.math.hhu.de/#/g/leanprover-community/nng4 (source and credits: https://github.com/leanprover-community/NNG4) &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Further reading|Further reading]].&lt;br /&gt;
* Kevin Buzzard, &amp;quot;The Annals Challenge&amp;quot;, &#039;&#039;Xena&#039;&#039; (blog), 13 August 2026. https://xenaproject.wordpress.com/2026/08/13/the-annals-challenge/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Research mathematics|Research mathematics]], [[Lean theorem prover/Applications/Machine learning and theorem proving|Machine learning and theorem proving]].&lt;br /&gt;
* Kevin Buzzard, &amp;quot;The Fermat&#039;s Last Theorem Project&amp;quot;, Lean community blog, 30 April 2024. https://leanprover-community.github.io/blog/posts/FLT-announcement/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/The Fermat&#039;s Last Theorem project|The Fermat&#039;s Last Theorem project]].&lt;br /&gt;
* Lean community, &amp;quot;Community teams&amp;quot; and &amp;quot;Mathlib reviewers&amp;quot; (read 14 October 2026). https://leanprover-community.github.io/teams.html &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Mathlib and its community|Mathlib and its community]].&lt;br /&gt;
* Lean community, &amp;quot;Contributing to mathlib&amp;quot; (read 14 October 2026). https://leanprover-community.github.io/contribute/index.html &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Mathlib and its community|Mathlib and its community]].&lt;br /&gt;
* Lean community, &amp;quot;Mathlib maintainers&amp;quot; (read 14 October 2026). https://leanprover-community.github.io/teams/maintainers.html &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Mathlib and its community|Mathlib and its community]].&lt;br /&gt;
* Lean community, &amp;quot;Mathlib porting status&amp;quot; (read 14 October 2026). https://leanprover-community.github.io/mathlib-port-status/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Lean 4|Lean 4]].&lt;br /&gt;
* Lean community, &amp;quot;Mathlib statistics&amp;quot;. [https://leanprover-community.github.io/mathlib_stats.html leanprover-community.github.io/mathlib_stats.html], consulted 14 October 2026. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/A library of mathematics|A library of mathematics]], [[Lean theorem prover/History/Mathlib and its community|Mathlib and its community]].&lt;br /&gt;
* Lean FRO, &amp;quot;About&amp;quot; page, with its timeline &amp;quot;A Brief History of Lean&amp;quot; (read 14 October 2026). https://lean-lang.org/fro/about/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Lean since 2023|Lean since 2023]].&lt;br /&gt;
* Lean FRO, home page, &amp;quot;Vision&amp;quot; and &amp;quot;Mission&amp;quot; (read 14 October 2026). https://lean-lang.org/fro/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Lean since 2023|Lean since 2023]].&lt;br /&gt;
* Lean FRO, &amp;quot;Roadmap&amp;quot; (index of the roadmaps from August 2023). https://lean-lang.org/fro/roadmap/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Lean since 2023|Lean since 2023]].&lt;br /&gt;
* Lean FRO, &amp;quot;The Lean FRO Year 4 - Part 1 Roadmap&amp;quot;, covering September 2026 to February 2027. https://lean-lang.org/fro/roadmap/y4-1/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Lean since 2023|Lean since 2023]].&lt;br /&gt;
* &#039;&#039;Lean Kernel Arena&#039;&#039;. [https://arena.lean-lang.org arena.lean-lang.org], consulted 13 October 2026. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Checking a proof again later|Checking a proof again later]], [[Lean theorem prover/System/Proof export and independent checkers|Proof export and independent checkers]].&lt;br /&gt;
* &amp;quot;lean4lean&amp;quot;, checker page, Lean Kernel Arena. [https://arena.lean-lang.org/checker/lean4lean arena.lean-lang.org/checker/lean4lean] &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Proof export and independent checkers|Proof export and independent checkers]].&lt;br /&gt;
* Leonardo de Moura, &amp;quot;Postmortem for Kernel Soundness Bug #14576&amp;quot;, 1 August 2026. https://leodemoura.github.io/blog/2026-8-1-postmortem-for-kernel-soundness-bug-14576/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Lean since 2023|Lean since 2023]].&lt;br /&gt;
* &amp;quot;nanoda&amp;quot;, checker page, Lean Kernel Arena. [https://arena.lean-lang.org/checker/nanoda/ arena.lean-lang.org/checker/nanoda/] &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Proof export and independent checkers|Proof export and independent checkers]].&lt;br /&gt;
* &#039;&#039;nanoda_lib&#039;&#039; (README), an external type checker for Lean 4 written in Rust. [https://github.com/ammkrn/nanoda_lib github.com/ammkrn/nanoda_lib], consulted 13 October 2026. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Checking a proof again later|Checking a proof again later]].&lt;br /&gt;
* Peter Scholze, &amp;quot;Half a year of the Liquid Tensor Experiment: amazing developments&amp;quot;, guest post on the &#039;&#039;Xena&#039;&#039; blog, 5 June 2021. [https://xenaproject.wordpress.com/2021/06/05/half-a-year-of-the-liquid-tensor-experiment-amazing-developments/ xenaproject.wordpress.com] (accessed 13 October 2026). &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Checking instead of convincing|Checking instead of convincing]], [[Lean theorem prover/History/The Liquid Tensor Experiment|The Liquid Tensor Experiment]], [[Lean theorem prover/Applications/Research mathematics|Research mathematics]].&lt;br /&gt;
* Peter Scholze, &amp;quot;Liquid tensor experiment&amp;quot;, guest post on the &#039;&#039;Xena&#039;&#039; blog, 5 December 2020. [https://xenaproject.wordpress.com/2020/12/05/liquid-tensor-experiment/ xenaproject.wordpress.com] (accessed 13 October 2026). &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Checking instead of convincing|Checking instead of convincing]], [[Lean theorem prover/History/The Liquid Tensor Experiment|The Liquid Tensor Experiment]].&lt;br /&gt;
* Physlib, &amp;quot;About Physlib&amp;quot;, project website, read 14 October 2026. https://physlib.io/about &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Physics in Lean|Physics in Lean]].&lt;br /&gt;
* &#039;&#039;Physlib&#039;&#039; (README). [https://github.com/leanprover-community/physlib github.com/leanprover-community/physlib], consulted 14 October 2026; also [https://physlib.io physlib.io]. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Lean and physics|Lean and physics]], [[Lean theorem prover/Applications/Physics in Lean|Physics in Lean]].&lt;br /&gt;
* &amp;quot;Principia Machina: the move to Lean&amp;quot;, the page [[Principia Machina/Lean transition]] on this wiki, status as of 14 October 2026. &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Physics in Lean|Physics in Lean]], [[Lean theorem prover/Applications/Principia Machina|Principia Machina]].&lt;br /&gt;
* Renaissance Philanthropy, &amp;quot;Kevin Buzzard and Alex Kontorovich on the Future of Formal Mathematics: A Mathlib Initiative Interview&amp;quot;, 3 October 2025. https://www.renaissancephilanthropy.org/insights/kevin-buzzard-and-alex-kontorovich-on-the-future-of-formal-mathematics-a-mathlib-initiative-interview &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Mathlib and its community|Mathlib and its community]].&lt;br /&gt;
* Renaissance Philanthropy, &amp;quot;Lean FRO and Mathlib receive $10M from XTX Markets Founder Alex Gerko to further advance the use of AI for mathematical research&amp;quot;, 24 July 2025. https://www.renaissancephilanthropy.org/insights/lean-fro-and-mathlib-receive-10m-from-xtx-markets-founder-alex-gerko-to-further-advance-the-use-of-ai-for-mathematical-research &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Mathlib and its community|Mathlib and its community]], [[Lean theorem prover/History/Lean since 2023|Lean since 2023]].&lt;br /&gt;
* Son Ho, Cédric Fournet, Antoine Delignat-Lavaud, Samuel Lee, Jason Fisher and Jessica Krynitsky, &amp;quot;Verifying Rust cryptography in SymCrypt, from standards to code&amp;quot;, Microsoft Research Blog, 13 July 2026. https://www.microsoft.com/en-us/research/blog/verifying-rust-cryptography-in-symcrypt-from-standards-to-code/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/Software verification|Software verification]], [[Lean theorem prover/Applications/Machine learning and theorem proving|Machine learning and theorem proving]].&lt;br /&gt;
* Terence Tao, &amp;quot;A pilot project in universal algebra to explore new ways to collaborate and use machine assistance?&amp;quot;, &#039;&#039;What&#039;s new&#039;&#039; (blog), 25 September 2024. https://terrytao.wordpress.com/2024/09/25/a-pilot-project-in-universal-algebra-to-explore-new-ways-to-collaborate-and-use-machine-assistance/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/The equational theories project|The equational theories project]].&lt;br /&gt;
* Terence Tao, &amp;quot;Formalizing the proof of PFR in Lean4 using Blueprint: a short tour&amp;quot;, &#039;&#039;What&#039;s new&#039;&#039; (blog), 18 November 2023. https://terrytao.wordpress.com/2023/11/18/formalizing-the-proof-of-pfr-in-lean4-using-blueprint-a-short-tour/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/The polynomial Freiman-Ruzsa conjecture|The polynomial Freiman-Ruzsa conjecture]].&lt;br /&gt;
* Terence Tao, &amp;quot;On a conjecture of Marton&amp;quot;, &#039;&#039;What&#039;s new&#039;&#039; (blog), 13 November 2023. https://terrytao.wordpress.com/2023/11/13/on-a-conjecture-of-marton/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/The polynomial Freiman-Ruzsa conjecture|The polynomial Freiman-Ruzsa conjecture]].&lt;br /&gt;
* Terence Tao, post on Mathstodon, 5 December 2023. https://mathstodon.xyz/@tao/111526765350663641 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/The polynomial Freiman-Ruzsa conjecture|The polynomial Freiman-Ruzsa conjecture]].&lt;br /&gt;
* Terence Tao, Yaël Dillies et al., &amp;quot;The Polynomial Freiman-Ruzsa Conjecture&amp;quot; (project page, with blueprint and Lean source), read 14 October 2026. https://teorth.github.io/pfr/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/The polynomial Freiman-Ruzsa conjecture|The polynomial Freiman-Ruzsa conjecture]].&lt;br /&gt;
* The Agda Team, &amp;quot;What is Agda?&amp;quot;, &#039;&#039;Agda documentation&#039;&#039;. [https://agda.readthedocs.io/en/latest/getting-started/what-is-agda.html agda.readthedocs.io] (accessed 13 October 2026). &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/What a proof assistant does|What a proof assistant does]].&lt;br /&gt;
* The Automath Archive, Eindhoven University of Technology, &amp;quot;About Automath&amp;quot;. https://automath.win.tue.nl/aboutautomath.htm &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Automath|Automath]].&lt;br /&gt;
* &amp;quot;The collected works of Per Martin-Löf&amp;quot;, an online archive of his papers, list of works with dates. https://archive-pml.github.io/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]].&lt;br /&gt;
* &amp;quot;The first official release of Lean 4&amp;quot;, Lean community blog, 8 September 2023. https://leanprover-community.github.io/blog/posts/first-lean-release/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Lean 4|Lean 4]], [[Lean theorem prover/History/Lean since 2023|Lean since 2023]].&lt;br /&gt;
* The mathlib community, &amp;quot;Completion of the Liquid Tensor Experiment&amp;quot;, Lean community blog, 15 July 2022. https://leanprover-community.github.io/blog/posts/lte-final/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/The Liquid Tensor Experiment|The Liquid Tensor Experiment]], [[Lean theorem prover/Applications/Research mathematics|Research mathematics]].&lt;br /&gt;
* The Rocq Prover Reference Manual, &amp;quot;History of Coq&amp;quot;, including &amp;quot;A short history of the early versions&amp;quot; written by Thierry Coquand, Gérard Huet and Christine Paulin-Mohring in September 2015 and Huet&#039;s summary of February 1995. https://rocq-prover.org/doc/master/refman/history.html &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]].&lt;br /&gt;
* The Rocq Team, &amp;quot;About Rocq&amp;quot;, &#039;&#039;The Rocq Prover&#039;&#039;. [https://rocq-prover.org/about rocq-prover.org/about] (accessed 13 October 2026). &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/What a proof assistant does|What a proof assistant does]], [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]].&lt;br /&gt;
* The Rocq Team, &amp;quot;Rocq 9.0.0&amp;quot;, &#039;&#039;The Rocq Prover&#039;&#039;, 12 March 2025. [https://rocq-prover.org/releases/9.0.0 rocq-prover.org/releases/9.0.0] (accessed 13 October 2026). &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/What a proof assistant does|What a proof assistant does]], [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]].&lt;br /&gt;
* The Xena Project (blog), &amp;quot;Division by zero in type theory: a FAQ&amp;quot;, 5 July 2020. [https://xenaproject.wordpress.com/2020/07/05/division-by-zero-in-type-theory-a-faq/ xenaproject.wordpress.com/2020/07/05/division-by-zero-in-type-theory-a-faq] &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Stating the right thing|Stating the right thing]].&lt;br /&gt;
* &amp;quot;Tutorial&amp;quot; test suite, Lean Kernel Arena. [https://arena.lean-lang.org/tutorial/ arena.lean-lang.org/tutorial/] &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/System/Proof export and independent checkers|Proof export and independent checkers]].&lt;br /&gt;
* UK Research and Innovation, Gateway to Research, &amp;quot;Formalising Fermat&amp;quot;, grant EP/Y022904/1, principal investigator Kevin Buzzard, Imperial College London. https://gtr.ukri.org/projects?ref=EP%2FY022904%2F1 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/The Fermat&#039;s Last Theorem project|The Fermat&#039;s Last Theorem project]].&lt;br /&gt;
* University of Bonn, Department of Mathematics, &amp;quot;Skolem Award for Floris van Doorn&amp;quot;, 27 May 2025. https://www.mathematics.uni-bonn.de/en/news/skolem-award-for-floris-van-doorn &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Lean since 2023|Lean since 2023]].&lt;br /&gt;
* &amp;quot;Update on mathport (Dec 2021)&amp;quot;, Lean community blog, 22 December 2021. https://leanprover-community.github.io/blog/posts/intro-to-mathport/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Lean 4|Lean 4]].&lt;br /&gt;
&lt;br /&gt;
== Press and encyclopedias ==&lt;br /&gt;
&lt;br /&gt;
* B. Jack Copeland, &amp;quot;The Church-Turing Thesis&amp;quot;, &#039;&#039;The Stanford Encyclopedia of Philosophy&#039;&#039; (first published 1997, substantive revision 18 December 2023), section 1.7. https://plato.stanford.edu/entries/church-turing/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Automation and its limits|Automation and its limits]].&lt;br /&gt;
* Bernard Linsky and Andrew David Irvine, &amp;quot;Principia Mathematica&amp;quot;, &#039;&#039;The Stanford Encyclopedia of Philosophy&#039;&#039;, substantive revision of 10 March 2026. [https://plato.stanford.edu/entries/principia-mathematica/ plato.stanford.edu/entries/principia-mathematica/] (accessed 13 October 2026). &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Why there is no type of all types|Why there is no type of all types]].&lt;br /&gt;
* Davide Castelvecchi, &amp;quot;Mathematicians welcome computer-assisted proof in &#039;grand unification&#039; theory&amp;quot;, &#039;&#039;Nature&#039;&#039; 595, 2021, pp. 18–19 (news, 18 June 2021). doi:10.1038/d41586-021-01627-2 &#039;&#039;Read in part: the headline, the summary and the first paragraph; the rest is behind a paywall (see [[Lean theorem prover/Sources|Sources]]).&#039;&#039; &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/The Liquid Tensor Experiment|The Liquid Tensor Experiment]].&lt;br /&gt;
* Harry Deutsch, Oliver Marshall and Andrew David Irvine, &amp;quot;Russell&#039;s paradox&amp;quot;, &#039;&#039;The Stanford Encyclopedia of Philosophy&#039;&#039;, substantive revision of 13 March 2026. [https://plato.stanford.edu/entries/russell-paradox/ plato.stanford.edu/entries/russell-paradox/] (accessed 13 October 2026). &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Why there is no type of all types|Why there is no type of all types]].&lt;br /&gt;
* John L. Bell, &amp;quot;The Axiom of Choice&amp;quot;, &#039;&#039;Stanford Encyclopedia of Philosophy&#039;&#039;, substantive revision of 10 December 2021, §5 &amp;quot;The Axiom of Choice and Logic&amp;quot; and note 15. https://plato.stanford.edu/entries/axiom-choice/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Foundations/Classical logic from choice|Classical logic from choice]].&lt;br /&gt;
* Kevin Hartnett, &amp;quot;Proof Assistant Makes Jump to Big-League Math&amp;quot;, &#039;&#039;Quanta Magazine&#039;&#039;, 28 July 2021. https://www.quantamagazine.org/lean-computer-program-confirms-peter-scholze-proof-20210728/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/The Liquid Tensor Experiment|The Liquid Tensor Experiment]].&lt;br /&gt;
* Leila Sloman, &amp;quot;&#039;A-Team&#039; of Math Proves a Critical Link Between Addition and Sets&amp;quot;, &#039;&#039;Quanta Magazine&#039;&#039;, 6 December 2023. https://www.quantamagazine.org/a-team-of-math-proves-a-critical-link-between-addition-and-sets-20231206/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Applications/The polynomial Freiman-Ruzsa conjecture|The polynomial Freiman-Ruzsa conjecture]].&lt;br /&gt;
* Liesbeth De Mol, &amp;quot;Turing Machines&amp;quot;, &#039;&#039;The Stanford Encyclopedia of Philosophy&#039;&#039; (first published 2018, substantive revision 21 May 2025), section 2.4. https://plato.stanford.edu/entries/turing-machine/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Functions that always finish|Functions that always finish]].&lt;br /&gt;
* Mathematics Genealogy Project, entry for Lambert S. van Benthem Jutting: Ph.D., Technische Universiteit Eindhoven, 1977, dissertation &amp;quot;Checking Landau&#039;s &#039;Grundlagen&#039; in the Automath System&amp;quot;, advisors N. G. de Bruijn and W. Peremans. https://www.mathgenealogy.org/id.php?id=63580 &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/History/Automath|Automath]].&lt;br /&gt;
* nLab, &amp;quot;Burali-Forti&#039;s paradox&amp;quot;, section &amp;quot;In type theory: Girard&#039;s paradox&amp;quot;, revision of 24 November 2023. https://ncatlab.org/nlab/show/Girard%27s+paradox &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Foundations/Universes and Prop|Universes and Prop]].&lt;br /&gt;
* Panu Raatikainen, &amp;quot;Gödel&#039;s Incompleteness Theorems&amp;quot;, &#039;&#039;The Stanford Encyclopedia of Philosophy&#039;&#039; (first published 2013, substantive revision 8 October 2025), sections 1 and 4.2. https://plato.stanford.edu/entries/goedel-incompleteness/ &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Automation and its limits|Automation and its limits]], [[Lean theorem prover/Foundations/Consistency and the metatheory|Consistency and the metatheory]].&lt;br /&gt;
* Peter Dybjer and Erik Palmgren, &amp;quot;Intuitionistic type theory&amp;quot;, &#039;&#039;The Stanford Encyclopedia of Philosophy&#039;&#039;, substantive revision of 23 September 2024, sections 3.6 and 7.4. [https://plato.stanford.edu/entries/type-theory-intuitionistic/ plato.stanford.edu/entries/type-theory-intuitionistic/] (accessed 13 October 2026). &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Why there is no type of all types|Why there is no type of all types]], [[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]].&lt;br /&gt;
* Thierry Coquand, &amp;quot;Type theory&amp;quot;, &#039;&#039;The Stanford Encyclopedia of Philosophy&#039;&#039;, substantive revision of 6 September 2022, section 6. [https://plato.stanford.edu/entries/type-theory/ plato.stanford.edu/entries/type-theory/] (accessed 13 October 2026). &#039;&#039;Cited on&#039;&#039; [[Lean theorem prover/Explainers/Why there is no type of all types|Why there is no type of all types]].&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
* [[Lean theorem prover/Further reading|Further reading]]&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>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/Sources&amp;diff=6819</id>
		<title>Lean theorem prover/Sources</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Sources&amp;diff=6819"/>
		<updated>2026-10-15T19:35:51Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Sources}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
This page states what the rest of the edition rests on. It is not a bibliography; [[Lean theorem prover/Bibliography|that is separate]]. It accounts for which sources were read and which were not, what each unread source carries on its page and what carries it instead, which versions of Lean and of its documentation the pages describe, and what remains open.&lt;br /&gt;
&lt;br /&gt;
The short version, before the detail. &#039;&#039;&#039;What the pages say about Lean rests on Lean itself, run on every fragment shown, and on Lean&#039;s own documentation and source, read in the versions the citations name.&#039;&#039;&#039; The edition cites 277 distinct works in 501 citations. Of these works, 258 were opened and read and 19 were not. None of the 19 carries a claim about Lean: each gives a date, a title, a venue, an attribution or a classical result, and each such claim rests as well on a bibliographic record, an abstract, or a source that was read.&lt;br /&gt;
&lt;br /&gt;
== What the edition rests on ==&lt;br /&gt;
&lt;br /&gt;
Every citation falls in one of four classes. The pages add a fifth kind of evidence of their own, Lean&#039;s output.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! class !! works !! citations !! not read&lt;br /&gt;
|-&lt;br /&gt;
| Lean&#039;s output, from running Lean 4.34.1 || colspan=&amp;quot;3&amp;quot; | 214 fragments of Lean on 51 pages, and 111 blocks of what Lean printed&lt;br /&gt;
|-&lt;br /&gt;
| Lean&#039;s documentation and source || 114 || 233 || 0&lt;br /&gt;
|-&lt;br /&gt;
| Papers and books || 86 || 167 || 18&lt;br /&gt;
|-&lt;br /&gt;
| Project pages and announcements || 64 || 86 || 0&lt;br /&gt;
|-&lt;br /&gt;
| Press and encyclopedias || 13 || 15 || 1, read in part&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Lean&#039;s output.&#039;&#039;&#039; The content pages show 214 fragments of Lean code, on 51 pages. Of these, 213 are compiled with Lean 4.34.1, each on its own or, where it continues an earlier fragment on the same page, together with the fragments before it (40 do so), and 52 of the compiled fragments are meant to be refused; their pages quote the error. One uses Mathlib, the community&#039;s library, and is shown without being compiled; its page says so. Output that a page quotes, from &amp;lt;code&amp;gt;#eval&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;#check&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;#print axioms&amp;lt;/code&amp;gt; or an error, is the output Lean 4.34.1 printed, copied and not recalled; 111 such passages are set apart in blocks of their own. On 14 October 2026 every compiled fragment behaved as its page says: those meant to be accepted were accepted, and those meant to be refused were refused. A reader with Lean 4.34.1 can repeat each check.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Lean&#039;s documentation and source.&#039;&#039;&#039; There are 114 works, all read: 52 parts of &#039;&#039;The Lean Language Reference&#039;&#039;, 39 files, directories and descriptions of Lean&#039;s source and of tools that work with it, and 23 other documents, among them &#039;&#039;Theorem Proving in Lean 4&#039;&#039;, &#039;&#039;Functional Programming in Lean&#039;&#039; and the community&#039;s textbooks. The Foundations and System pages draw on them for what they say about how Lean works, and show much of it in Lean&#039;s output.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Papers and books.&#039;&#039;&#039; There are 86 works: the papers on type theory and its history behind the Foundations and History pages, the papers that describe Lean, and the papers of the projects described under Applications. Of these, 68 were read, in whole or in the parts cited, and 18 were not; they are listed below.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Project pages and announcements.&#039;&#039;&#039; There are 64 works, all read: project sites and descriptions, blog posts, lists of awards, roadmaps and announcements. Many of them change over time; see the known gaps below.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Press and encyclopedias.&#039;&#039;&#039; There are 13 works: entries of the &#039;&#039;Stanford Encyclopedia of Philosophy&#039;&#039; and of the nLab, articles in &#039;&#039;Quanta Magazine&#039;&#039; and &#039;&#039;Nature&#039;&#039;, and a record of the Mathematics Genealogy Project. One, the &#039;&#039;Nature&#039;&#039; article, was read in part.&lt;br /&gt;
&lt;br /&gt;
== Versions ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Lean.&#039;&#039;&#039; The pages describe Lean 4.34.1. Every fragment is compiled with it, and every quoted output is its output. Lean 4.34.1 was published on 24 September 2026, ten days after 4.34.0; Lean 4.35.0 followed on 12 October 2026.&amp;lt;ref name=&amp;quot;relnotes&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, version for Lean 4.35.0, &amp;quot;Release Notes&amp;quot;, list of versions with their dates. [https://lean-lang.org/doc/reference/4.35.0/releases/ lean-lang.org/doc/reference/4.35.0/releases/], consulted 14 October 2026.&amp;lt;/ref&amp;gt; Citations of Lean&#039;s source name the tag v4.34.1 (33 citations do), so that what they describe is the code that was run.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The reference manual.&#039;&#039;&#039; &#039;&#039;The Lean Language Reference&#039;&#039; is published in editions numbered by version. The edition for 4.34.0 states that it covers Lean version 4.34.0,&amp;lt;ref name=&amp;quot;man4340&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, version for Lean 4.34.0, front page and table of contents. [https://lean-lang.org/doc/reference/4.34.0/ lean-lang.org/doc/reference/4.34.0/], consulted 14 October 2026.&amp;lt;/ref&amp;gt; and there is no edition for 4.34.1. Most pages cite the edition for 4.34.0: 40 of its parts, in 114 citations on 45 pages. Six explainers, [[Lean theorem prover/Explainers/What a proof assistant does|What a proof assistant does]], [[Lean theorem prover/Explainers/Checking instead of convincing|Checking instead of convincing]], [[Lean theorem prover/Explainers/Types as specifications|Types as specifications]], [[Lean theorem prover/Explainers/Why there is no type of all types|Why there is no type of all types]], [[Lean theorem prover/Explainers/What the axioms are|What the axioms are]] and [[Lean theorem prover/Explainers/Two kinds of equality|Two kinds of equality]], cite the edition for 4.35.0, which was the newest when they were read.&lt;br /&gt;
&lt;br /&gt;
The two editions differ. To find out where, the eight chapters and sections cited in the edition for 4.35.0 were compared with their text in the edition for 4.34.0. Five read the same, apart from section numbers and the label of a marginal note: &amp;quot;Introduction&amp;quot;, &amp;quot;The Type System&amp;quot;, &amp;quot;Propositions&amp;quot;, &amp;quot;Universes&amp;quot; and &amp;quot;Subtypes&amp;quot;. &amp;quot;Finite Natural Numbers&amp;quot; differs in the signature of one library function. &amp;quot;Axioms&amp;quot; and &amp;quot;Validating a Lean Proof&amp;quot; differ in substance. Lean 4.35.0 removed the axiom &amp;lt;code&amp;gt;Lean.trustCompiler&amp;lt;/code&amp;gt; and the machinery around it,&amp;lt;ref name=&amp;quot;val4350&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, version for Lean 4.35.0, &amp;quot;Validating a Lean Proof&amp;quot;. [https://lean-lang.org/doc/reference/4.35.0/ValidatingProofs/ lean-lang.org/doc/reference/4.35.0/ValidatingProofs/], consulted 14 October 2026.&amp;lt;/ref&amp;gt; so the edition for 4.34.0 lists seven standard axioms, three of which record trust in Lean&#039;s compiler, and the edition for 4.35.0 lists four.&amp;lt;ref name=&amp;quot;ax4340&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, version for Lean 4.34.0, chapter 8, &amp;quot;Axioms&amp;quot;. [https://lean-lang.org/doc/reference/4.34.0/Axioms/ lean-lang.org/doc/reference/4.34.0/Axioms/], consulted 14 October 2026.&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;ax4350&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, version for Lean 4.35.0, chapter 8, &amp;quot;Axioms&amp;quot;. [https://lean-lang.org/doc/reference/4.35.0/Axioms/ lean-lang.org/doc/reference/4.35.0/Axioms/], consulted 14 October 2026.&amp;lt;/ref&amp;gt; In Lean 4.34.1 the axiom still exists, and a proof by native evaluation already depends on an axiom of its own, whose name contains &amp;lt;code&amp;gt;_native&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;
#check Lean.trustCompiler&lt;br /&gt;
&lt;br /&gt;
theorem two_plus_two : 2 + 2 = 4 := by native_decide&lt;br /&gt;
#print axioms two_plus_two&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;&lt;br /&gt;
Lean.trustCompiler : True&lt;br /&gt;
&#039;two_plus_two&#039; depends on axioms: [two_plus_two._native.native_decide.ax_1_1]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
None of the six explainers relies on the difference. What they take from the two chapters, the three axioms known to be consistent, &amp;lt;code&amp;gt;sorryAx&amp;lt;/code&amp;gt;, and the axioms with &amp;lt;code&amp;gt;_native&amp;lt;/code&amp;gt; in their names, holds in Lean 4.34.1 as in 4.35.0.&lt;br /&gt;
&lt;br /&gt;
The edition for 4.35.0 also inserts a chapter, &amp;quot;The vcgen tactic&amp;quot;, as chapter 17, and adds a twenty-sixth, so its chapters from 17 on are numbered one higher than in the edition for 4.34.0.&amp;lt;ref name=&amp;quot;man4340&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;man4350&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, version for Lean 4.35.0, front page and table of contents. [https://lean-lang.org/doc/reference/4.35.0/ lean-lang.org/doc/reference/4.35.0/], consulted 14 October 2026.&amp;lt;/ref&amp;gt; A section number given on a page belongs to the edition that page cites.&lt;br /&gt;
&lt;br /&gt;
Some citations use an address marked &amp;quot;latest&amp;quot;, which always shows the newest edition (4 citations in all): the manual&#039;s list of versions and its notes for Lean 4.22.0, on [[Lean theorem prover/History/Lean since 2023|Lean since 2023]] and in the [[Lean theorem prover/Chronology|chronology]], and the documentation of Agda, on [[Lean theorem prover/Explainers/What a proof assistant does|What a proof assistant does]]. What those addresses show will change. The same notes for Lean 4.22.0 are also cited, in the edition for 4.34.0, on [[Lean theorem prover/System/The compiler and runtime|The compiler and runtime]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The books.&#039;&#039;&#039; &#039;&#039;Theorem Proving in Lean 4&#039;&#039; states that it assumes Lean 4.33.0,&amp;lt;ref name=&amp;quot;tpil&amp;quot;&amp;gt;Jeremy Avigad, Leonardo de Moura, Soonho Kong and Sebastian Ullrich, &#039;&#039;Theorem Proving in Lean 4&#039;&#039;, front page. [https://lean-lang.org/theorem_proving_in_lean4/ lean-lang.org/theorem_proving_in_lean4/], consulted 14 October 2026.&amp;lt;/ref&amp;gt; and the code of &#039;&#039;Functional Programming in Lean&#039;&#039; is tested with Lean 4.33.0.&amp;lt;ref name=&amp;quot;fpil&amp;quot;&amp;gt;David Thrane Christiansen, &#039;&#039;Functional Programming in Lean&#039;&#039;, front page. [https://lean-lang.org/functional_programming_in_lean/ lean-lang.org/functional_programming_in_lean/], consulted 14 October 2026.&amp;lt;/ref&amp;gt; The pages cite them for explanations and definitions. Every output the pages show is that of Lean 4.34.1.&lt;br /&gt;
&lt;br /&gt;
== What was not read ==&lt;br /&gt;
&lt;br /&gt;
The 19 works below were not read, or, in one case, read only in part. For each, the table gives the pages that cite it, what they take from it, and what carries that claim instead.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! work !! cited on !! what the page takes from it !! what carries it&lt;br /&gt;
|-&lt;br /&gt;
| Bove, Dybjer and Norell, &amp;quot;A brief overview of Agda&amp;quot;, 2009 || [[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]] || that an overview of the new Agda appeared in 2009, beside the account of its predecessors || Norell&#039;s thesis, read, cited beside it; the bibliographic record&lt;br /&gt;
|-&lt;br /&gt;
| Constable and others, &#039;&#039;Implementing Mathematics with the Nuprl Proof Development System&#039;&#039;, 1986 || [[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]] || that Nuprl rests on an extensional theory close to Martin-Löf&#039;s of 1982 || the &#039;&#039;Stanford Encyclopedia&#039;&#039; entry on intuitionistic type theory, read, cited beside it; a library catalogue record&lt;br /&gt;
|-&lt;br /&gt;
| Coquand and Huet, &amp;quot;Constructions: a higher order proof system for mechanizing mathematics&amp;quot;, 1985 || [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]] || that the calculus was described at EUROCAL in 1985 || the bibliographic record; the history in the Rocq reference manual, read&lt;br /&gt;
|-&lt;br /&gt;
| Coquand and Paulin, &amp;quot;Inductively defined types&amp;quot;, 1990 || [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]] || that the paper was given at COLOG-88 and printed in 1990 || the history in the Rocq reference manual, read, cited beside it; the bibliographic record&lt;br /&gt;
|-&lt;br /&gt;
| Curry, &amp;quot;Functionality in combinatory logic&amp;quot;, 1934 || [[Lean theorem prover/Explainers/Propositions as types|Propositions as types]] || Curry&#039;s observation of 1934 || Wadler&#039;s &amp;quot;Propositions as types&amp;quot;, read, cited beside it. The journal&#039;s copies could not be fetched&lt;br /&gt;
|-&lt;br /&gt;
| Castelvecchi, &amp;quot;Mathematicians welcome computer-assisted proof in &#039;grand unification&#039; theory&amp;quot;, &#039;&#039;Nature&#039;&#039;, 2021 || [[Lean theorem prover/History/The Liquid Tensor Experiment|The Liquid Tensor Experiment]] || its date, its author and its summary || the headline, the summary and the first paragraph, read; the rest is behind a paywall&lt;br /&gt;
|-&lt;br /&gt;
| Diaconescu, &amp;quot;Axiom of choice and complementation&amp;quot;, 1975 || [[Lean theorem prover/Explainers/What the axioms are|What the axioms are]], [[Lean theorem prover/Foundations/Classical logic from choice|Classical logic from choice]] || the theorem&#039;s name and date, and the setting of the first proof || &#039;&#039;Theorem Proving in Lean 4&#039;&#039; and the &#039;&#039;Stanford Encyclopedia&#039;&#039; entry on the axiom of choice, read, cited beside it; the abstract in the publisher&#039;s record&lt;br /&gt;
|-&lt;br /&gt;
| Gödel, &amp;quot;Über formal unentscheidbare Sätze der Principia Mathematica und verwandter Systeme I&amp;quot;, 1931 || [[Lean theorem prover/Explainers/Automation and its limits|Automation and its limits]], [[Lean theorem prover/Foundations/Consistency and the metatheory|Consistency and the metatheory]] || the incompleteness theorems, as the pages state them || the &#039;&#039;Stanford Encyclopedia&#039;&#039; entry on the incompleteness theorems, read, cited beside it; Turing&#039;s paper of 1936, read, which cites it with the same details. No open copy was found&lt;br /&gt;
|-&lt;br /&gt;
| Goldfarb, &amp;quot;The undecidability of the second-order unification problem&amp;quot;, 1981 || [[Lean theorem prover/System/Metavariables and unification|Metavariables and unification]] || that unification is undecidable from order 2 || the introduction of Miller&#039;s paper of 1991, read, which states the result with this citation. The publisher refused access&lt;br /&gt;
|-&lt;br /&gt;
| Goodman and Myhill, &amp;quot;Choice implies excluded middle&amp;quot;, 1978 || [[Lean theorem prover/Foundations/Classical logic from choice|Classical logic from choice]] || the note&#039;s title and date || the bibliographic record, and the &#039;&#039;Stanford Encyclopedia&#039;&#039; entry on the axiom of choice, read. No open copy was found&lt;br /&gt;
|-&lt;br /&gt;
| Gordon, Milner, Morris, Newey and Wadsworth, &amp;quot;A metalanguage for interactive proof in LCF&amp;quot;, 1978 || [[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]] || that ML was described at the 1978 Symposium on Principles of Programming Languages || the bibliographic record&lt;br /&gt;
|-&lt;br /&gt;
| Gordon, Milner and Wadsworth, &#039;&#039;Edinburgh LCF&#039;&#039;, 1979 || [[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]] || that the work was written up as a book in 1979 || the bibliographic record; Gordon&#039;s history of LCF and HOL, read&lt;br /&gt;
|-&lt;br /&gt;
| Hales, &amp;quot;A proof of the Kepler conjecture&amp;quot;, 2005 || [[Lean theorem prover/Explainers/Checking instead of convincing|Checking instead of convincing]] || that the proof was published without complete certification || the Flyspeck paper, read, cited beside it; the journal&#039;s page for the article&lt;br /&gt;
|-&lt;br /&gt;
| Howard, &amp;quot;The formulae-as-types notion of construction&amp;quot;, 1980 || [[Lean theorem prover/Explainers/Propositions as types|Propositions as types]] || that Howard&#039;s notes of 1969 circulated privately and were printed in 1980 || Wadler&#039;s &amp;quot;Propositions as types&amp;quot;, read, cited beside it, with its list of references&lt;br /&gt;
|-&lt;br /&gt;
| Martin-Löf, &amp;quot;An intuitionistic theory of types: predicative part&amp;quot;, 1975 || [[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]] || the hierarchy of universes and the identity type of that version || the &#039;&#039;Stanford Encyclopedia&#039;&#039; entry on intuitionistic type theory, read, cited beside it; the bibliographic record&lt;br /&gt;
|-&lt;br /&gt;
| Martin-Löf, &amp;quot;Constructive mathematics and computer programming&amp;quot;, 1982 || [[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]] || the extensional form of the theory || the same entry, read, cited beside it; the bibliographic record&lt;br /&gt;
|-&lt;br /&gt;
| Nederpelt, Geuvers and de Vrijer (eds.), &#039;&#039;Selected Papers on Automath&#039;&#039;, 1994 || [[Lean theorem prover/History/Automath|Automath]] || the collection and its contents || the publisher&#039;s page with the contents, read&lt;br /&gt;
|-&lt;br /&gt;
| Paulin-Mohring, &amp;quot;Inductive definitions in the system Coq: rules and properties&amp;quot;, 1993 || [[Lean theorem prover/Foundations/Inductive types and recursors|Inductive types and recursors]], [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]] || why the Calculus of Constructions was extended with inductive definitions, and that the rules were set out in 1993 || the paper&#039;s abstract, read; the history in the Rocq reference manual, read. No open copy was found&lt;br /&gt;
|-&lt;br /&gt;
| Russell, &amp;quot;Mathematical logic as based on the theory of types&amp;quot;, 1908 || [[Lean theorem prover/Explainers/Why there is no type of all types|Why there is no type of all types]] || that the ramified theory was set out in a paper of 1908 || the &#039;&#039;Stanford Encyclopedia&#039;&#039; entry on Russell&#039;s paradox, read, cited beside it&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Two further works were read for one page and cited from their records on another. Hurkens&#039;s &amp;quot;A simplification of Girard&#039;s paradox&amp;quot; (1995) was read, in a copy on a university site, for [[Lean theorem prover/Foundations/Universes and Prop|Universes and Prop]], and is cited on [[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]] for its date. Coquand and Huet&#039;s &amp;quot;The calculus of constructions&amp;quot; (1988) was read, in a scan of the published article, for [[Lean theorem prover/Foundations/Universes and Prop|Universes and Prop]], and is cited on [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]] for its journal and year.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;What this costs.&#039;&#039;&#039; Eleven of the unread works are cited on the History pages, for dates, venues and attributions; the others support the history of an idea, or a classical result, on explainers and technical pages. The sharpest cost is on [[Lean theorem prover/Foundations/Inductive types and recursors|Inductive types and recursors]]: its account of why the Calculus of Constructions was extended with inductive definitions rests on the abstract of Paulin-Mohring&#039;s paper, not on the paper. The next is on [[Lean theorem prover/System/Metavariables and unification|Metavariables and unification]], where Goldfarb&#039;s result is stated as Miller reports it.&lt;br /&gt;
&lt;br /&gt;
== Read in part, or in another copy ==&lt;br /&gt;
&lt;br /&gt;
* The &#039;&#039;Nature&#039;&#039; article of 2021 was read in its headline, summary and first paragraph; the rest is behind a paywall.&lt;br /&gt;
* Carneiro&#039;s paper on Lean4Lean was read in its arXiv text: version 2 for [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]], [[Lean theorem prover/Foundations/Inductive types and recursors|Inductive types and recursors]] and [[Lean theorem prover/Foundations/Definitional equality|Definitional equality]], version 3 for the other pages that cite it. The pages that cite the version published in 2026 read the arXiv text as well.&lt;br /&gt;
* Some papers were read in copies held elsewhere than their publishers: Hurkens (1995) and Coquand and Huet (1988), for [[Lean theorem prover/Foundations/Universes and Prop|Universes and Prop]], on university sites; Milner&#039;s paper of 1978 on type polymorphism, for [[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]], in a course archive, in its opening pages; Abel and Coquand&#039;s paper on normalisation, for [[Lean theorem prover/Foundations/Definitional equality|Definitional equality]], in its arXiv source.&lt;br /&gt;
* De Bruijn&#039;s survey of Automath, his paper of 1970 and van Benthem Jutting&#039;s book of 1979 were read in scans with machine-read text, the paper of 1970 in its opening pages; de Bruijn&#039;s paper of 1972 on nameless dummies was read in its first two pages.&lt;br /&gt;
* The ACM&#039;s own pages refused automated access. The Turing Award citation on [[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]] is quoted from the announcement forwarded to the TYPES mailing list, and the software award named on [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]] rests on the Rocq site and on search results that showed the ACM&#039;s announcement.&lt;br /&gt;
&lt;br /&gt;
== The rules the edition followed ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;No citation from memory.&#039;&#039;&#039; Every work cited was checked: by opening it, or, for the works listed above as not read, through its bibliographic record. A detail that could not be checked was left out.&lt;br /&gt;
* &#039;&#039;&#039;Short quotations.&#039;&#039;&#039; Sources are paraphrased. The rule was to quote at most one short passage, of 25 words or fewer, from any one source on a page, in quotation marks and with its citation; Lean&#039;s own documentation and source, published under the Apache License, are quoted a little more freely. No quotation in the prose of the content pages is longer than 25 words.&lt;br /&gt;
* &#039;&#039;&#039;Every Lean fragment compiled.&#039;&#039;&#039; Each fragment is compiled with Lean 4.34.1, and each one meant to fail is checked to fail, as described above.&lt;br /&gt;
* &#039;&#039;&#039;Recent figures dated.&#039;&#039;&#039; Figures that change, such as the size of Mathlib or the state of a project, are given as of the date on which their source was read, and the citation carries that date. In all, 92 citations carry a date of reading.&lt;br /&gt;
* &#039;&#039;&#039;Versions named.&#039;&#039;&#039; A citation of the manual names its edition, and a citation of Lean&#039;s source names its tag.&lt;br /&gt;
&lt;br /&gt;
== Known gaps ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Closed or refused.&#039;&#039;&#039; No open copy was found of Gödel (1931), Diaconescu (1975), Goodman and Myhill (1978), Goldfarb (1981) or Paulin-Mohring (1993). The &#039;&#039;Nature&#039;&#039; article is behind a paywall. The ACM refused automated access to its award pages, and the journal&#039;s copies of Curry (1934) could not be fetched.&lt;br /&gt;
* &#039;&#039;&#039;Undated web pages.&#039;&#039;&#039; Of the cited web pages, 21, among them project descriptions, README files, pages of the Lean Kernel Arena and pages of Lean&#039;s API documentation, have neither a version nor a date of reading in their citations. They describe things that change, and the citation does not say which state of the page was read.&lt;br /&gt;
* &#039;&#039;&#039;Addresses marked &amp;quot;latest&amp;quot;.&#039;&#039;&#039; The citations at such addresses, described under Versions, will show other text as Lean moves on.&lt;br /&gt;
* &#039;&#039;&#039;Two editions of the manual.&#039;&#039;&#039; Six explainers cite the edition for 4.35.0 while the pages describe 4.34.1. The comparison above found no claim that depends on the difference, but the citations do not name the version described.&lt;br /&gt;
* &#039;&#039;&#039;Two versions of one paper.&#039;&#039;&#039; Carneiro&#039;s Lean4Lean paper was read in two versions of its arXiv text, and is cited both in that form and in its published form.&lt;br /&gt;
* &#039;&#039;&#039;Forms of citation.&#039;&#039;&#039; One work is sometimes cited in different forms on different pages. The [[Lean theorem prover/Bibliography|Bibliography]] gives one form for each and notes the differences that matter.&lt;br /&gt;
&lt;br /&gt;
== What would close the gaps ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;For the closed papers.&#039;&#039;&#039; Read the five papers in a library, and the &#039;&#039;Nature&#039;&#039; article in full. Each would confirm a date or an attribution. None would change what the pages say about Lean.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;For the versions.&#039;&#039;&#039; Cite the edition for 4.34.0 on the six explainers, and an edition by number in place of each address marked &amp;quot;latest&amp;quot;, so that every citation of the manual names the version the pages describe. Read Lean4Lean once, in one version, for every page that cites it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;For the web pages.&#039;&#039;&#039; Give each undated citation of a changing page the date on which it was read, or a versioned address where one exists.&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
* [[Lean theorem prover/Bibliography|Bibliography]]&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>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/Notation&amp;diff=6818</id>
		<title>Lean theorem prover/Notation</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Notation&amp;diff=6818"/>
		<updated>2026-10-15T19:35:49Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Notation}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
This page fixes the notation used across the edition. The Foundations pages write the rules&lt;br /&gt;
of Lean&#039;s type theory in the notation of the type-theory literature, inside formulas. Lean&lt;br /&gt;
writes many of the same things in its own syntax, inside code. The tables set the two side by&lt;br /&gt;
side, with a one-line meaning and the page on which each first appears in the reading order;&lt;br /&gt;
where the formula and the Lean syntax first appear on different pages, both are named. A dash&lt;br /&gt;
means that the notation has no counterpart on that side.&lt;br /&gt;
&lt;br /&gt;
The formulas follow Carneiro&#039;s presentation of Lean&#039;s type theory, as&lt;br /&gt;
[[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]]&lt;br /&gt;
explains; the Lean syntax is that of Lean 4.34.1.&lt;br /&gt;
&lt;br /&gt;
== Judgments and rules ==&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;judgment&#039;&#039;&#039; is a statement about the theory, made by its rules; it is not a proposition&lt;br /&gt;
inside Lean, and Lean has no syntax for asserting one. Lean shows judgments in what it prints:&lt;br /&gt;
&amp;lt;code&amp;gt;#check&amp;lt;/code&amp;gt; prints &amp;lt;code&amp;gt;e : A&amp;lt;/code&amp;gt;, and the display of a goal lists a context above&lt;br /&gt;
&amp;lt;code&amp;gt;⊢&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! in formulas !! in Lean !! meaning !! first used&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;\Gamma&amp;lt;/math&amp;gt; || the lines above &amp;lt;code&amp;gt;⊢&amp;lt;/code&amp;gt; in a goal || a &#039;&#039;&#039;context&#039;&#039;&#039;: variables with their types, &amp;lt;math&amp;gt;x_1 : A_1, \ldots, x_n : A_n&amp;lt;/math&amp;gt;, each type may mention the variables before it || [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;\vdash&amp;lt;/math&amp;gt; || &amp;lt;code&amp;gt;⊢&amp;lt;/code&amp;gt; || in a formula, &amp;quot;derives&amp;quot;; in a goal, it separates what may be used, above, from what must be shown, after it || formula: [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]]; goal: [[Lean theorem prover/Explainers/Induction, as the machine sees it|Induction, as the machine sees it]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;\Gamma \vdash e : A&amp;lt;/math&amp;gt; || &amp;lt;code&amp;gt;e : A&amp;lt;/code&amp;gt;, as &amp;lt;code&amp;gt;#check e&amp;lt;/code&amp;gt; prints it || the &#039;&#039;&#039;typing judgment&#039;&#039;&#039;: in the context &amp;lt;math&amp;gt;\Gamma&amp;lt;/math&amp;gt;, the term &amp;lt;math&amp;gt;e&amp;lt;/math&amp;gt; has type &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; || [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;\Gamma \vdash e \equiv e&#039;&amp;lt;/math&amp;gt; || – || &#039;&#039;&#039;definitional equality&#039;&#039;&#039;: &amp;lt;math&amp;gt;e&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;e&#039;&amp;lt;/math&amp;gt; are equal by computation and unfolding, with no proof; Lean tests it when it checks &amp;lt;code&amp;gt;rfl&amp;lt;/code&amp;gt; || [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;e \Leftrightarrow e&#039;&amp;lt;/math&amp;gt; || – || Carneiro&#039;s &#039;&#039;&#039;algorithmic definitional equality&#039;&#039;&#039;, the relation the Lean kernel&#039;s test decides; it implies &amp;lt;math&amp;gt;e \equiv e&#039;&amp;lt;/math&amp;gt; || [[Lean theorem prover/Foundations/Definitional equality|Definitional equality]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;\Gamma\ \mathrm{ok}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; || – || the context is well formed; the empty context || [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;\frac{J_1 \qquad J_2}{J}&amp;lt;/math&amp;gt; || – || an &#039;&#039;&#039;inference rule&#039;&#039;&#039;: from the judgments above the line, the one below || [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;B[a/x]&amp;lt;/math&amp;gt; || – || &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; with &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt; put in place of the variable &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; || [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Functions, types and universes ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! in formulas !! in Lean !! meaning !! first used&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;(x : A) \to B&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\Pi x : A.\, B&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\prod_{a \in A} B(a)&amp;lt;/math&amp;gt; || &amp;lt;code&amp;gt;(x : A) → B&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;∀ x : A, B&amp;lt;/code&amp;gt; || &#039;&#039;&#039;dependent function type&#039;&#039;&#039;: functions whose result type &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; may mention the argument &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;; Lean prints it with &amp;lt;code&amp;gt;∀&amp;lt;/code&amp;gt; when &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; is a proposition || formula: [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]], &amp;lt;math&amp;gt;\Pi&amp;lt;/math&amp;gt; at [[Lean theorem prover/Foundations/Dependent function types|Dependent function types]]; Lean: [[Lean theorem prover/Foundations/Dependent function types|Dependent function types]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;A \to B&amp;lt;/math&amp;gt; || &amp;lt;code&amp;gt;A → B&amp;lt;/code&amp;gt; || function type, when &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; does not mention the argument; implication, when &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; are propositions || [[Lean theorem prover/Explainers/Propositions as types|Propositions as types]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;\lambda x : A.\, e&amp;lt;/math&amp;gt; || &amp;lt;code&amp;gt;fun (x : A) =&amp;gt; e&amp;lt;/code&amp;gt;, also written &amp;lt;code&amp;gt;fun x ↦ e&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;λ x =&amp;gt; e&amp;lt;/code&amp;gt; || &#039;&#039;&#039;function abstraction&#039;&#039;&#039;: the function sending &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; to &amp;lt;math&amp;gt;e&amp;lt;/math&amp;gt; || formula: [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]]; Lean: [[Lean theorem prover/Explainers/What the axioms are|What the axioms are]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;f\,a&amp;lt;/math&amp;gt; || &amp;lt;code&amp;gt;f a&amp;lt;/code&amp;gt; || application of &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; to &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt; || [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;\mathrm{let}\ x : A := v;\ e&amp;lt;/math&amp;gt; || &amp;lt;code&amp;gt;let x : A := v; e&amp;lt;/code&amp;gt; || a local definition || [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;\mathrm{Sort}\,u&amp;lt;/math&amp;gt; || &amp;lt;code&amp;gt;Sort u&amp;lt;/code&amp;gt; || the &#039;&#039;&#039;universe&#039;&#039;&#039; at level &amp;lt;math&amp;gt;u&amp;lt;/math&amp;gt;, the type of the types at that level || formula: [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]]; Lean: [[Lean theorem prover/Explainers/Building things from constructors|Building things from constructors]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;\mathrm{Sort}\,0&amp;lt;/math&amp;gt; || &amp;lt;code&amp;gt;Prop&amp;lt;/code&amp;gt; || the universe of propositions || [[Lean theorem prover/Explainers/Propositions as types|Propositions as types]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;\mathrm{Sort}\,(u+1)&amp;lt;/math&amp;gt; || &amp;lt;code&amp;gt;Type u&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;Type&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;Type 0&amp;lt;/code&amp;gt; || the universes of data || [[Lean theorem prover/Explainers/Why there is no type of all types|Why there is no type of all types]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;\mathrm{U}_u&amp;lt;/math&amp;gt; || – || Carneiro&#039;s name for the universe written &amp;lt;math&amp;gt;\mathrm{Sort}\,u&amp;lt;/math&amp;gt; in this edition || [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;\mathrm{imax}\,u\,v&amp;lt;/math&amp;gt; || &amp;lt;code&amp;gt;imax u v&amp;lt;/code&amp;gt; || the level of a function type: &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; if &amp;lt;math&amp;gt;v = 0&amp;lt;/math&amp;gt;, otherwise &amp;lt;math&amp;gt;\max(u, v)&amp;lt;/math&amp;gt; || formula: [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]]; Lean: [[Lean theorem prover/Foundations/Universes and Prop|Universes and Prop]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;c.\{\bar u\}&amp;lt;/math&amp;gt; || &amp;lt;code&amp;gt;c.{u}&amp;lt;/code&amp;gt; || the constant &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; used at the universe levels &amp;lt;math&amp;gt;\bar u&amp;lt;/math&amp;gt; || formula: [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]]; Lean: [[Lean theorem prover/Explainers/Building things from constructors|Building things from constructors]]&lt;br /&gt;
|-&lt;br /&gt;
| – || &amp;lt;code&amp;gt;{x : A}&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[C A]&amp;lt;/code&amp;gt; || an &#039;&#039;&#039;implicit&#039;&#039;&#039; argument, filled in by unification; an &#039;&#039;&#039;instance-implicit&#039;&#039;&#039; argument, filled in by instance resolution || [[Lean theorem prover/Explainers/Building things from constructors|Building things from constructors]]; explained at [[Lean theorem prover/Foundations/Dependent function types|Dependent function types]]&lt;br /&gt;
|-&lt;br /&gt;
| – || &amp;lt;code&amp;gt;⟨a, b⟩&amp;lt;/code&amp;gt; || the &#039;&#039;&#039;anonymous constructor&#039;&#039;&#039;: a value of a type with one constructor, such as a pair or a proof of &amp;lt;code&amp;gt;p ∧ q&amp;lt;/code&amp;gt; || [[Lean theorem prover/Explainers/Propositions as types|Propositions as types]]&lt;br /&gt;
|-&lt;br /&gt;
| – || &amp;lt;code&amp;gt;A × B&amp;lt;/code&amp;gt; || the type of pairs || [[Lean theorem prover/Foundations/Definitional equality|Definitional equality]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;\Sigma x : A.\, B&amp;lt;/math&amp;gt; || &amp;lt;code&amp;gt;(x : A) × B&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Σ x : A, B&amp;lt;/code&amp;gt; || &#039;&#039;&#039;dependent pair&#039;&#039;&#039;: pairs whose second part has a type that depends on the first || named at [[Lean theorem prover/Foundations/Structural and well-founded recursion|Structural and well-founded recursion]]; no page writes the symbol&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;\mathrm{Nat.rec}&amp;lt;/math&amp;gt; || &amp;lt;code&amp;gt;Nat.rec&amp;lt;/code&amp;gt; || the &#039;&#039;&#039;recursor&#039;&#039;&#039; of the natural numbers, at once induction and primitive recursion || formula: [[Lean theorem prover/Foundations/Inductive types and recursors|Inductive types and recursors]]; Lean: [[Lean theorem prover/Explainers/Building things from constructors|Building things from constructors]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;\prec&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\mathrm{Acc}\;x&amp;lt;/math&amp;gt; || &amp;lt;code&amp;gt;WellFounded&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Acc&amp;lt;/code&amp;gt; || a well-founded relation; the proposition that &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; is accessible, the basis of well-founded recursion || [[Lean theorem prover/Foundations/Structural and well-founded recursion|Structural and well-founded recursion]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In Lean the dependent function type, function abstraction and the dependent pair are written&lt;br /&gt;
as in the second column; the reference manual gives the full syntax, including &amp;lt;code&amp;gt;↦&amp;lt;/code&amp;gt;&lt;br /&gt;
in place of &amp;lt;code&amp;gt;=&amp;gt;&amp;lt;/code&amp;gt;.&amp;lt;ref name=&amp;quot;rm-fun-terms&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, for Lean&lt;br /&gt;
4.34.0, lean-lang.org, 2026, section 13.3, &amp;quot;Functions&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/Terms/Functions/&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;rm-fun-types&amp;quot;&amp;gt;&#039;&#039;The&lt;br /&gt;
Lean Language Reference&#039;&#039;, for 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; Each line below&lt;br /&gt;
is accepted by Lean 4.34.1:&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;
example : Sort 0 = Prop := rfl&lt;br /&gt;
example : Sort 1 = Type := rfl&lt;br /&gt;
example : Type 1 = Sort 2 := rfl&lt;br /&gt;
example : (fun (x : Nat) =&amp;gt; x + 1) 2 = 3 := rfl&lt;br /&gt;
example : (fun (x : Nat) ↦ x + 1) 2 = 3 := rfl&lt;br /&gt;
example : (λ (x : Nat) =&amp;gt; x + 1) 2 = 3 := rfl&lt;br /&gt;
def pair : (n : Nat) × Fin (n + 1) := ⟨2, 0⟩&lt;br /&gt;
def pair&#039; : Σ n : Nat, Fin (n + 1) := ⟨2, 0⟩&lt;br /&gt;
&lt;br /&gt;
#check ∀ x : Nat, x = x&lt;br /&gt;
#check (x : Nat) → Fin (x + 1)&lt;br /&gt;
#check Nat → Nat&lt;br /&gt;
#check fun (x : Nat) =&amp;gt; x + 1&lt;br /&gt;
#check (Σ n : Nat, Fin (n + 1))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The five &amp;lt;code&amp;gt;#check&amp;lt;/code&amp;gt; lines print:&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;
∀ (x : Nat), x = x : Prop&lt;br /&gt;
(x : Nat) → Fin (x + 1) : Type&lt;br /&gt;
Nat → Nat : Type&lt;br /&gt;
fun x =&amp;gt; x + 1 : Nat → Nat&lt;br /&gt;
(n : Nat) × Fin (n + 1) : Type&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The same dependent function type is printed with &amp;lt;code&amp;gt;∀&amp;lt;/code&amp;gt; when its result is a&lt;br /&gt;
proposition and with &amp;lt;code&amp;gt;→&amp;lt;/code&amp;gt; otherwise, and Lean prints a dependent pair written with&lt;br /&gt;
&amp;lt;code&amp;gt;Σ&amp;lt;/code&amp;gt; in the form &amp;lt;code&amp;gt;(n : Nat) × …&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Logic ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! in formulas !! in Lean !! meaning !! first used&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;\forall x\, \phi&amp;lt;/math&amp;gt; || &amp;lt;code&amp;gt;∀ x : A, P x&amp;lt;/code&amp;gt; || for every &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;; a dependent function type into &amp;lt;code&amp;gt;Prop&amp;lt;/code&amp;gt; || formula: [[Lean theorem prover/Foundations/Classical logic from choice|Classical logic from choice]]; Lean: [[Lean theorem prover/Explainers/Induction, as the machine sees it|Induction, as the machine sees it]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;\exists x\, \phi&amp;lt;/math&amp;gt; || &amp;lt;code&amp;gt;∃ x : A, P x&amp;lt;/code&amp;gt;, the type &amp;lt;code&amp;gt;Exists&amp;lt;/code&amp;gt; || there is an &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;; proved by a witness and a proof, &amp;lt;code&amp;gt;⟨w, h⟩&amp;lt;/code&amp;gt; || formula: [[Lean theorem prover/Foundations/Classical logic from choice|Classical logic from choice]]; Lean: [[Lean theorem prover/Explainers/Automation and its limits|Automation and its limits]]&lt;br /&gt;
|-&lt;br /&gt;
| – || &amp;lt;code&amp;gt;p ∧ q&amp;lt;/code&amp;gt;, the type &amp;lt;code&amp;gt;And&amp;lt;/code&amp;gt; || and || [[Lean theorem prover/Explainers/Propositions as types|Propositions as types]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;p \lor q&amp;lt;/math&amp;gt; || &amp;lt;code&amp;gt;p ∨ q&amp;lt;/code&amp;gt;, the type &amp;lt;code&amp;gt;Or&amp;lt;/code&amp;gt; || or || formula: [[Lean theorem prover/Foundations/Classical logic from choice|Classical logic from choice]]; Lean: [[Lean theorem prover/Explainers/Propositions as types|Propositions as types]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;\neg p&amp;lt;/math&amp;gt; || &amp;lt;code&amp;gt;¬p&amp;lt;/code&amp;gt;, defined as &amp;lt;code&amp;gt;p → False&amp;lt;/code&amp;gt; || not || formula: [[Lean theorem prover/Foundations/Classical logic from choice|Classical logic from choice]]; Lean: [[Lean theorem prover/Explainers/What the axioms are|What the axioms are]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;a \leftrightarrow b&amp;lt;/math&amp;gt; || &amp;lt;code&amp;gt;p ↔ q&amp;lt;/code&amp;gt;, the type &amp;lt;code&amp;gt;Iff&amp;lt;/code&amp;gt; || if and only if || [[Lean theorem prover/Foundations/The three axioms|The three axioms]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;\mathrm{True}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\mathrm{False}&amp;lt;/math&amp;gt; || &amp;lt;code&amp;gt;True&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;False&amp;lt;/code&amp;gt; || the proposition with one proof, and the one with none || formula: [[Lean theorem prover/Foundations/Classical logic from choice|Classical logic from choice]]; Lean: &amp;lt;code&amp;gt;True&amp;lt;/code&amp;gt; at [[Lean theorem prover/Explainers/What the axioms are|What the axioms are]], &amp;lt;code&amp;gt;False&amp;lt;/code&amp;gt; at [[Lean theorem prover/Explainers/What has to be trusted|What has to be trusted]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;\neq&amp;lt;/math&amp;gt; || &amp;lt;code&amp;gt;a ≠ b&amp;lt;/code&amp;gt;, meaning &amp;lt;code&amp;gt;¬(a = b)&amp;lt;/code&amp;gt; || not equal || formula: [[Lean theorem prover/Foundations/Classical logic from choice|Classical logic from choice]]; Lean: [[Lean theorem prover/Explainers/Automation and its limits|Automation and its limits]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Each of these proofs is accepted by Lean 4.34.1; the last shows that &amp;lt;code&amp;gt;¬p&amp;lt;/code&amp;gt; is&lt;br /&gt;
&amp;lt;code&amp;gt;p → False&amp;lt;/code&amp;gt; by definition:&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;
example (p q : Prop) (hp : p) (hq : q) : p ∧ q := ⟨hp, hq⟩&lt;br /&gt;
example (p q : Prop) (hp : p) : p ∨ q := Or.inl hp&lt;br /&gt;
example (p q : Prop) (h : p → q) (hp : p) : q := h hp&lt;br /&gt;
example (p q : Prop) : p ∧ q ↔ q ∧ p := ⟨fun ⟨a, b⟩ =&amp;gt; ⟨b, a⟩, fun ⟨a, b⟩ =&amp;gt; ⟨b, a⟩⟩&lt;br /&gt;
example : ∀ n : Nat, n + 0 = n := fun _ =&amp;gt; rfl&lt;br /&gt;
example : ∃ n : Nat, n + 2 = 5 := ⟨3, rfl⟩&lt;br /&gt;
example : (2 : Nat) ≠ 3 := by decide&lt;br /&gt;
example (p : Prop) : (¬p) = (p → False) := rfl&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Equality ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! in formulas !! in Lean !! meaning !! first used&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;a = b&amp;lt;/math&amp;gt; || &amp;lt;code&amp;gt;a = b&amp;lt;/code&amp;gt;, the type &amp;lt;code&amp;gt;Eq a b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;propositional equality&#039;&#039;&#039;: a proposition, whose proofs are terms || formula: [[Lean theorem prover/Foundations/Propositional equality|Propositional equality]]; Lean: [[Lean theorem prover/Explainers/What the axioms are|What the axioms are]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;e \equiv e&#039;&amp;lt;/math&amp;gt; || – || definitional equality, the judgment above || [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;\mathrm{Eq.refl}\,a&amp;lt;/math&amp;gt; || &amp;lt;code&amp;gt;rfl&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Eq.refl a&amp;lt;/code&amp;gt; || the one constructor of equality: a proof of &amp;lt;math&amp;gt;a = a&amp;lt;/math&amp;gt; || formula: [[Lean theorem prover/Foundations/Propositional equality|Propositional equality]]; Lean: [[Lean theorem prover/Explainers/Two kinds of equality|Two kinds of equality]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;\mathrm{Eq.rec}&amp;lt;/math&amp;gt; || &amp;lt;code&amp;gt;Eq.rec&amp;lt;/code&amp;gt; || the eliminator of equality: what holds of &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt; holds of &amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt; when &amp;lt;math&amp;gt;a = b&amp;lt;/math&amp;gt; || [[Lean theorem prover/Foundations/Propositional equality|Propositional equality]]&lt;br /&gt;
|-&lt;br /&gt;
| – || &amp;lt;code&amp;gt;h ▸ e&amp;lt;/code&amp;gt; || &#039;&#039;&#039;substitution&#039;&#039;&#039;: &amp;lt;math&amp;gt;e&amp;lt;/math&amp;gt; carried along a proof &amp;lt;code&amp;gt;h : a = b&amp;lt;/code&amp;gt; || [[Lean theorem prover/Foundations/Propositional equality|Propositional equality]]&lt;br /&gt;
|-&lt;br /&gt;
| – || &amp;lt;code&amp;gt;a ≍ b&amp;lt;/code&amp;gt;, the type &amp;lt;code&amp;gt;HEq a b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;heterogeneous equality&#039;&#039;&#039;, between terms whose types may differ || [[Lean theorem prover/Foundations/Propositional equality|Propositional equality]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;\mathrm{Quot}\,r&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\mathrm{Quot.mk}\,r\,a&amp;lt;/math&amp;gt; || &amp;lt;code&amp;gt;Quot r&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Quot.mk r a&amp;lt;/code&amp;gt; || the quotient of a type by a relation &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt;, and the element of it that &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt; gives || formula: [[Lean theorem prover/Foundations/Quotient types|Quotient types]]; Lean: [[Lean theorem prover/Foundations/Propositional equality|Propositional equality]]&lt;br /&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;
example (a b : Nat) (h : a = b) (P : Nat → Prop) (hp : P a) : P b := h ▸ hp&lt;br /&gt;
example (n : Nat) (x : Fin n) : x ≍ x := HEq.rfl&lt;br /&gt;
#check @HEq&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean 4.34.1 accepts both and prints &amp;lt;code&amp;gt;@HEq : {α : Sort u_1} → α → {β : Sort u_1} → β → Prop&amp;lt;/code&amp;gt;:&lt;br /&gt;
the two sides of &amp;lt;code&amp;gt;≍&amp;lt;/code&amp;gt; may have different types.&lt;br /&gt;
&lt;br /&gt;
== Holes and unification ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! in formulas !! in Lean !! meaning !! first used&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;?m&amp;lt;/math&amp;gt; || &amp;lt;code&amp;gt;?m.12&amp;lt;/code&amp;gt; || a &#039;&#039;&#039;metavariable&#039;&#039;&#039;, a hole the elaborator has yet to fill || formula: [[Lean theorem prover/System/Metavariables and unification|Metavariables and unification]]; Lean: [[Lean theorem prover/Explainers/Holes and goals|Holes and goals]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;s =^{?} t&amp;lt;/math&amp;gt; || &amp;lt;code&amp;gt;s =?= t&amp;lt;/code&amp;gt; || a &#039;&#039;&#039;unification problem&#039;&#039;&#039;: find values of the metavariables that make the two sides definitionally equal || [[Lean theorem prover/System/Metavariables and unification|Metavariables and unification]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Metatheory ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! in formulas !! in Lean !! meaning !! first used&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;T \vdash \mathrm{Con}(S)&amp;lt;/math&amp;gt; || – || the theory &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; proves that the theory &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; is consistent || [[Lean theorem prover/Foundations/Consistency and the metatheory|Consistency and the metatheory]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;\mathrm{ZFC}_n&amp;lt;/math&amp;gt; || – || Zermelo–Fraenkel set theory with choice and &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; inaccessible cardinals || [[Lean theorem prover/Foundations/Consistency and the metatheory|Consistency and the metatheory]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;math&amp;gt;\mathrm{CIC}_n&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\mathrm{Lean}_n&amp;lt;/math&amp;gt; || – || the Calculus of Inductive Constructions, or Lean&#039;s type theory, with &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; universes || [[Lean theorem prover/Foundations/Consistency and the metatheory|Consistency and the metatheory]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Commands and keywords ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! in Lean !! meaning !! first used&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;example : A := e&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;theorem c : A := e&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;def c : A := e&amp;lt;/code&amp;gt; || a term &amp;lt;code&amp;gt;e&amp;lt;/code&amp;gt; of type &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;, unnamed, as a named theorem, or as a named definition || [[Lean theorem prover/Explainers/Propositions as types|Propositions as types]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;by&amp;lt;/code&amp;gt; || the term that follows is to be built by tactics || [[Lean theorem prover/Explainers/Types as specifications|Types as specifications]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;rfl&amp;lt;/code&amp;gt; || the proof of &amp;lt;code&amp;gt;a = a&amp;lt;/code&amp;gt;; it closes a goal whose two sides are definitionally equal || [[Lean theorem prover/Explainers/Two kinds of equality|Two kinds of equality]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;sorry&amp;lt;/code&amp;gt; || a placeholder for a missing proof, recorded as the axiom &amp;lt;code&amp;gt;sorryAx&amp;lt;/code&amp;gt; || [[Lean theorem prover/Explainers/What the axioms are|What the axioms are]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#check e&amp;lt;/code&amp;gt; || print the type of &amp;lt;code&amp;gt;e&amp;lt;/code&amp;gt; || [[Lean theorem prover/Explainers/Why there is no type of all types|Why there is no type of all types]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#print c&amp;lt;/code&amp;gt; || print the definition of &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt; || [[Lean theorem prover/Explainers/What the axioms are|What the axioms are]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#print axioms c&amp;lt;/code&amp;gt; || list the axioms that &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt; depends on || [[Lean theorem prover/Explainers/What the axioms are|What the axioms are]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#eval e&amp;lt;/code&amp;gt; || compute &amp;lt;code&amp;gt;e&amp;lt;/code&amp;gt; and print the result || [[Lean theorem prover/Explainers/Functions that always finish|Functions that always finish]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/Sources|Sources]], what was read for the edition.&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>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/Glossary&amp;diff=6817</id>
		<title>Lean theorem prover/Glossary</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Glossary&amp;diff=6817"/>
		<updated>2026-10-15T19:35:48Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Glossary}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
Terms the pages of this edition define, each where it is first set out in bold, with the page that defines it and, where there is one, the page that explains it in plain language. The definitions here are short; the pages carry the working ones, with their sources. Symbols are on [[Lean theorem prover/Notation|the notation page]].&lt;br /&gt;
&lt;br /&gt;
== A ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Automated theorem prover.&#039;&#039;&#039; A program built to find proofs by itself, for statements in a restricted form, rather than to check proofs that a person supplies. See [[Lean theorem prover/Explainers/What a proof assistant does|What a proof assistant does]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Automath.&#039;&#039;&#039; The formal language for mathematics, and the project around it, that N. G. de Bruijn designed at Eindhoven in the late 1960s; its checkers confirmed proofs written out in full. See [[Lean theorem prover/History/Automath|Automath]]; in plain language, [[Lean theorem prover/Explainers/Checking instead of convincing|Checking instead of convincing]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Axiom.&#039;&#039;&#039; A constant of a given type that is simply postulated; when its type is a proposition, an assumed proof of it. Lean cannot check that an axiom is consistent, and &amp;lt;code&amp;gt;#print axioms&amp;lt;/code&amp;gt; lists the axioms a theorem rests on. See [[Lean theorem prover/Foundations/The three axioms|The three axioms]]; in plain language, [[Lean theorem prover/Explainers/What the axioms are|What the axioms are]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Axiom K.&#039;&#039;&#039; Streicher&#039;s principle that every proof of &amp;lt;code&amp;gt;a = a&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;Eq.refl a&amp;lt;/code&amp;gt;. It is equivalent to uniqueness of identity proofs, and in Lean it holds by definition. See [[Lean theorem prover/Foundations/Propositional equality|Propositional equality]].&lt;br /&gt;
&lt;br /&gt;
== B ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Beta reduction.&#039;&#039;&#039; The rule that applying a function abstraction to an argument substitutes the argument for the bound variable. It is one of the reductions that make up definitional equality.&amp;lt;ref name=&amp;quot;gl-types&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, version for Lean 4.34.0, chapter 4, &amp;quot;The Type System&amp;quot;. [https://lean-lang.org/doc/reference/4.34.0/The-Type-System/ lean-lang.org/doc/reference/4.34.0/The-Type-System/], consulted 14 October 2026.&amp;lt;/ref&amp;gt; See [[Lean theorem prover/Foundations/Definitional equality|Definitional equality]] and [[Lean theorem prover/Foundations/Dependent function types|Dependent function types]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Blueprint.&#039;&#039;&#039; A tool written by Patrick Massot that links a human-readable account of a proof, lemma by lemma, to its Lean counterparts, and draws their dependency graph with the progress of each. See [[Lean theorem prover/Applications/The polynomial Freiman-Ruzsa conjecture|The polynomial Freiman-Ruzsa conjecture]].&lt;br /&gt;
&lt;br /&gt;
== C ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Calculus of Inductive Constructions.&#039;&#039;&#039; The Calculus of Constructions extended with primitive inductive definitions. Coq, now Rocq, was named after it. See [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Comparator.&#039;&#039;&#039; A tool that checks a proposed proof against a theorem statement written beforehand in a trusted setting: it compiles the proof in a sandbox, exports it, replays the export with the Lean kernel or an independent checker, and confirms that exactly the stated theorems were proved. See [[Lean theorem prover/System/Proof export and independent checkers|Proof export and independent checkers]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Condensed mathematics.&#039;&#039;&#039; The framework begun by Clausen and Scholze that proposes condensed sets in place of topological spaces in the foundations of mathematics. The theorem checked in the Liquid Tensor Experiment belongs to it. See [[Lean theorem prover/History/The Liquid Tensor Experiment|The Liquid Tensor Experiment]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Congruence closure.&#039;&#039;&#039; Grouping terms known to be equal, together with what follows from the rule that equal arguments give equal results. It is one of the methods of &amp;lt;code&amp;gt;grind&amp;lt;/code&amp;gt;. See [[Lean theorem prover/System/Decision procedures|Decision procedures]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Constructive logic.&#039;&#039;&#039; A logic in which a proof of &amp;quot;P or Q&amp;quot; must say which side holds, so that the law of the excluded middle is not available in general. Lean&#039;s logic without axioms is constructive. See [[Lean theorem prover/Foundations/Classical logic from choice|Classical logic from choice]]; in plain language, [[Lean theorem prover/Explainers/What the axioms are|What the axioms are]] and [[Lean theorem prover/Explainers/Propositions as types|Propositions as types]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Constructor.&#039;&#039;&#039; One of the rules that make the values of an inductive type. The values of the type are exactly those its constructors make. See [[Lean theorem prover/Foundations/Inductive types and recursors|Inductive types and recursors]]; in plain language, [[Lean theorem prover/Explainers/Building things from constructors|Building things from constructors]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Context.&#039;&#039;&#039; A list of variables with their types, each type able to mention the variables before it. A typing judgment is made in a context. See [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Conversion rule.&#039;&#039;&#039; The typing rule that a term of type &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; also has every type definitionally equal to &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;. It is where computation enters typing. See [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Course-of-values recursion.&#039;&#039;&#039; Structural recursion in which a call may use the results for any smaller argument, not only for the immediately smaller one. Lean provides it through the constructions &amp;lt;code&amp;gt;below&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;brecOn&amp;lt;/code&amp;gt;. See [[Lean theorem prover/Foundations/Structural and well-founded recursion|Structural and well-founded recursion]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Curry–Howard correspondence.&#039;&#039;&#039; Another name for propositions as types, after two of the logicians who found it. See [[Lean theorem prover/Explainers/Propositions as types|Propositions as types]].&lt;br /&gt;
&lt;br /&gt;
== D ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;de Bruijn criterion.&#039;&#039;&#039; The requirement that a proof assistant&#039;s proofs can be checked independently by a small program, one that a person can inspect; named after N. G. de Bruijn. In Lean the small program is the Lean kernel. See [[Lean theorem prover/Explainers/The small trusted core|The small trusted core]] and [[Lean theorem prover/Explainers/Checking instead of convincing|Checking instead of convincing]] and [[Lean theorem prover/History/Automath|Automath]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;de Bruijn factor.&#039;&#039;&#039; The ratio between the size of a formal text and the size of the informal original it renders, both compressed. For the Automath translation of Landau&#039;s &#039;&#039;Grundlagen&#039;&#039; it is about 3.7. See [[Lean theorem prover/History/Automath|Automath]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;de Bruijn index.&#039;&#039;&#039; A number standing for a bound variable: the count of binders between the variable and the binder that introduces it. In Lean the nearest binder has index 0. See [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]] and [[Lean theorem prover/System/Metaprogramming in Lean|Metaprogramming in Lean]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;decide&amp;lt;/code&amp;gt;.&#039;&#039;&#039; The tactic that proves a statement by finding a procedure that decides it and running it. It works when the statement has no unknowns and such a procedure is available. See [[Lean theorem prover/System/Decision procedures|Decision procedures]]; in plain language, [[Lean theorem prover/Explainers/Automation and its limits|Automation and its limits]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Decision procedure.&#039;&#039;&#039; An algorithm that settles every question in a fixed class with yes or no. In Lean it is useful only when its yes comes with evidence the Lean kernel accepts. See [[Lean theorem prover/System/Decision procedures|Decision procedures]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Default instance.&#039;&#039;&#039; An instance tried when a search for instances would otherwise fail without selecting one. It is why &amp;lt;code&amp;gt;fun x =&amp;gt; x + 1&amp;lt;/code&amp;gt; elaborates to a function on &amp;lt;code&amp;gt;Nat&amp;lt;/code&amp;gt;. See [[Lean theorem prover/System/Type classes and instance resolution|Type classes and instance resolution]] and [[Lean theorem prover/System/Elaboration|Elaboration]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Definitional equality.&#039;&#039;&#039; The equality that holds between two terms by computation and the unfolding of definitions, without proof. Lean&#039;s checker tests it for itself, and no proof records it.&amp;lt;ref name=&amp;quot;gl-types&amp;quot; /&amp;gt; See [[Lean theorem prover/Foundations/Definitional equality|Definitional equality]]; in plain language, [[Lean theorem prover/Explainers/Two kinds of equality|Two kinds of equality]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Delta reduction.&#039;&#039;&#039; The rule that a defined constant equals its definition.&amp;lt;ref name=&amp;quot;gl-types&amp;quot; /&amp;gt; See [[Lean theorem prover/Foundations/Definitional equality|Definitional equality]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Dependent function type.&#039;&#039;&#039; The type of functions whose result type may depend on the argument, written &amp;lt;code&amp;gt;(x : A) → B&amp;lt;/code&amp;gt;; also called a dependent product or Π-type. It is the only kind of function type in Lean&#039;s core theory: ordinary function types, &amp;quot;for all&amp;quot; and implication are special cases. See [[Lean theorem prover/Foundations/Dependent function types|Dependent function types]]; in plain language, [[Lean theorem prover/Explainers/Types as specifications|Types as specifications]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Dependent type.&#039;&#039;&#039; A type that depends on a value, such as the type of lists of a given length. See [[Lean theorem prover/Explainers/Types as specifications|Types as specifications]] and [[Lean theorem prover/Explainers/Propositions as types|Propositions as types]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;do-notation.&#039;&#039;&#039; Lean&#039;s syntax for writing programs that use a monad in an imperative style, with sequencing, mutable local variables, loops and early return. A &amp;lt;code&amp;gt;do&amp;lt;/code&amp;gt; block is translated into an ordinary term. See [[Lean theorem prover/System/Monads and do-notation|Monads and do-notation]].&lt;br /&gt;
&lt;br /&gt;
== E ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;E-matching.&#039;&#039;&#039; Instantiating a theorem by matching its pattern against terms, up to the equalities known so far. It is one of the methods of &amp;lt;code&amp;gt;grind&amp;lt;/code&amp;gt;. See [[Lean theorem prover/System/Decision procedures|Decision procedures]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Elaboration.&#039;&#039;&#039; The step that turns what a person types into a fully explicit term of Lean&#039;s core type theory, supplying omitted arguments, instances, coercions and universe levels. The program that does it, the elaborator, need not be trusted, because its output goes to the Lean kernel. See [[Lean theorem prover/System/Elaboration|Elaboration]]; in plain language, [[Lean theorem prover/Explainers/The small trusted core|The small trusted core]] and [[Lean theorem prover/Explainers/When Lean says no|When Lean says no]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;elan.&#039;&#039;&#039; The toolchain manager, which installs versions of Lean and selects the one a project names. A toolchain is the set of programs and files for one version of Lean. See [[Lean theorem prover/System/Lake and Lean projects|Lake and Lean projects]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Equational law.&#039;&#039;&#039; An identity that a binary operation may satisfy for all values of its variables, such as the commutative law. A magma is a set with one such operation and no further rules; one law implies another when every magma satisfying the first satisfies the second. See [[Lean theorem prover/Applications/The equational theories project|The equational theories project]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eta.&#039;&#039;&#039; For functions, the rule that &amp;lt;math&amp;gt;\lambda x.\, f\,x&amp;lt;/math&amp;gt; equals &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;; for structures, the rule that a value equals the constructor applied to its fields. Both are part of Lean&#039;s definitional equality. See [[Lean theorem prover/Foundations/Definitional equality|Definitional equality]] and [[Lean theorem prover/Foundations/Dependent function types|Dependent function types]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;External checker.&#039;&#039;&#039; A second program, written separately, that reads a proof exported from Lean and checks it again. See [[Lean theorem prover/System/Proof export and independent checkers|Proof export and independent checkers]]; in plain language, [[Lean theorem prover/Explainers/What has to be trusted|What has to be trusted]] and [[Lean theorem prover/Explainers/Checking a proof again later|Checking a proof again later]].&lt;br /&gt;
&lt;br /&gt;
== F ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Function extensionality.&#039;&#039;&#039; The principle that functions giving equal results on every argument are equal. In Lean it is a theorem, proved from quotients. See [[Lean theorem prover/Foundations/Propositional equality|Propositional equality]]; in plain language, [[Lean theorem prover/Explainers/What the axioms are|What the axioms are]].&lt;br /&gt;
&lt;br /&gt;
== G ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Global choice.&#039;&#039;&#039; The axiom &amp;lt;code&amp;gt;Classical.choice&amp;lt;/code&amp;gt;: from a proof that a type has a value, it gives a value of the type. See [[Lean theorem prover/Foundations/The three axioms|The three axioms]]; in plain language, [[Lean theorem prover/Explainers/What the axioms are|What the axioms are]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Goal.&#039;&#039;&#039; A statement still to be proved, with the hypotheses that may be used to prove it. In Lean&#039;s tactic framework each goal is a metavariable; the first in the list is the main goal. See [[Lean theorem prover/System/The tactic framework|The tactic framework]]; in plain language, [[Lean theorem prover/Explainers/Holes and goals|Holes and goals]] and [[Lean theorem prover/Explainers/What a proof assistant does|What a proof assistant does]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;grind&amp;lt;/code&amp;gt;.&#039;&#039;&#039; A tactic that collects facts in one shared store and works on them with several methods at once, among them congruence closure, E-matching, case splits and solvers for arithmetic. See [[Lean theorem prover/System/Decision procedures|Decision procedures]]; in plain language, [[Lean theorem prover/Explainers/Automation and its limits|Automation and its limits]].&lt;br /&gt;
&lt;br /&gt;
== H ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Heterogeneous equality.&#039;&#039;&#039; An equality between terms whose types are not known to be definitionally equal, written &amp;lt;code&amp;gt;a ≍ b&amp;lt;/code&amp;gt; in Lean 4.34.1. See [[Lean theorem prover/Foundations/Propositional equality|Propositional equality]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Higher-order unification.&#039;&#039;&#039; Unification in which a metavariable stands for a function applied to arguments. It is undecidable in general, and decidable for patterns, in which a metavariable is applied only to distinct bound variables. See [[Lean theorem prover/System/Metavariables and unification|Metavariables and unification]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hygiene.&#039;&#039;&#039; The property of Lean&#039;s macros that a name a macro introduces cannot capture a name the user wrote, nor the reverse. It is implemented by macro scopes, which tag each name a macro introduces. See [[Lean theorem prover/System/Syntax extension and hygienic macros|Syntax extension and hygienic macros]].&lt;br /&gt;
&lt;br /&gt;
== I ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Implicit argument.&#039;&#039;&#039; An argument the caller does not write. An implicit argument is filled by unification; a strict implicit one likewise, but only once a later explicit argument is given; an instance-implicit one by instance resolution. See [[Lean theorem prover/Foundations/Dependent function types|Dependent function types]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Impredicativity.&#039;&#039;&#039; The property of &amp;lt;code&amp;gt;Prop&amp;lt;/code&amp;gt; that a proposition may quantify over all propositions, or over types at any level, and still be a proposition. Its opposite, predicativity, holds for the universes &amp;lt;code&amp;gt;Type u&amp;lt;/code&amp;gt;. See [[Lean theorem prover/Foundations/Universes and Prop|Universes and Prop]]; in plain language, [[Lean theorem prover/Explainers/Why there is no type of all types|Why there is no type of all types]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Index.&#039;&#039;&#039; An argument of an inductive family that may differ from one constructor to another; a parameter is fixed across the whole definition. In &amp;lt;code&amp;gt;a = b&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; is an index. See [[Lean theorem prover/Foundations/Inductive types and recursors|Inductive types and recursors]] and [[Lean theorem prover/Foundations/Propositional equality|Propositional equality]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Induction hypothesis.&#039;&#039;&#039; In a proof by induction on the natural numbers, the assumption that the statement holds for &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;, used in the induction step to prove it for &amp;lt;math&amp;gt;k + 1&amp;lt;/math&amp;gt;; the base case is the proof for 0. See [[Lean theorem prover/Explainers/Induction, as the machine sees it|Induction, as the machine sees it]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Inductive family.&#039;&#039;&#039; An inductive definition with indices, which defines a whole family of types at once. The notion is Dybjer&#039;s. See [[Lean theorem prover/Foundations/Inductive types and recursors|Inductive types and recursors]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Inductive type.&#039;&#039;&#039; A type whose values are exactly those made by its constructors. Apart from functions, universes and quotient types, which are built into Lean, every type in Lean is an inductive type or is defined from these. See [[Lean theorem prover/Foundations/Inductive types and recursors|Inductive types and recursors]]; in plain language, [[Lean theorem prover/Explainers/Building things from constructors|Building things from constructors]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Instance.&#039;&#039;&#039; A definition registered for a type class, which the elaborator finds by itself when a term needs it; for example, the definition that says how to add two values of given types. See [[Lean theorem prover/System/Type classes and instance resolution|Type classes and instance resolution]]; in plain language, [[Lean theorem prover/Explainers/When Lean says no|When Lean says no]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Instance resolution.&#039;&#039;&#039; The search by which the elaborator finds instances, also called instance synthesis. Lean&#039;s is tabled. See [[Lean theorem prover/System/Type classes and instance resolution|Type classes and instance resolution]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Iota reduction.&#039;&#039;&#039; The rule that a recursor applied to a constructor reduces to the corresponding minor premise. It is part of definitional equality.&amp;lt;ref name=&amp;quot;gl-types&amp;quot; /&amp;gt; See [[Lean theorem prover/Foundations/Inductive types and recursors|Inductive types and recursors]] and [[Lean theorem prover/Foundations/Definitional equality|Definitional equality]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IR.&#039;&#039;&#039; The compiler&#039;s lower-level form of a definition, translated from LCNF, which Lean prints on request and which its interpreter runs. See [[Lean theorem prover/System/The compiler and runtime|The compiler and runtime]].&lt;br /&gt;
&lt;br /&gt;
== L ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Lake.&#039;&#039;&#039; The tool that ships with every version of Lean for compiling Lean code and fetching what a project depends on; a project organised for it is a Lake package. It records the exact version of each dependency in the file &amp;lt;code&amp;gt;lake-manifest.json&amp;lt;/code&amp;gt;. See [[Lean theorem prover/System/Lake and Lean projects|Lake and Lean projects]]; in plain language, [[Lean theorem prover/Explainers/A library of mathematics|A library of mathematics]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Large elimination.&#039;&#039;&#039; Eliminating a proof of a proposition into any universe, so as to produce data. Lean allows it only when the proposition is a syntactic subsingleton. See [[Lean theorem prover/Foundations/Proof irrelevance and subsingleton elimination|Proof irrelevance and subsingleton elimination]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Law of the excluded middle.&#039;&#039;&#039; The principle that every proposition is either true or false. It cannot be proved in Lean&#039;s logic without axioms; with choice and the two extensionality principles it can (Diaconescu&#039;s theorem). See [[Lean theorem prover/Foundations/Classical logic from choice|Classical logic from choice]]; in plain language, [[Lean theorem prover/Explainers/What the axioms are|What the axioms are]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;LCNF.&#039;&#039;&#039; Lean Compiler Normal Form: the compiler&#039;s representation of a definition in A-normal form, in which every intermediate result is bound to a name. See [[Lean theorem prover/System/The compiler and runtime|The compiler and runtime]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Lean kernel.&#039;&#039;&#039; The type checker that decides whether a definition, theorem, axiom or inductive type may enter Lean&#039;s environment, its table of definitions and theorems. It is the small part of Lean that has to be trusted. It has no termination checker and performs no unification.&amp;lt;ref name=&amp;quot;gl-kernel&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, version for Lean 4.34.0, section 2.3, &amp;quot;The Kernel&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/], consulted 14 October 2026.&amp;lt;/ref&amp;gt; See [[Lean theorem prover/System/The Lean kernel|The Lean kernel]]; in plain language, [[Lean theorem prover/Explainers/The small trusted core|The small trusted core]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Lean Kernel Arena.&#039;&#039;&#039; A site that runs checkers for Lean on the same exported tests, some to be accepted and some to be rejected, and publishes the results. See [[Lean theorem prover/System/Proof export and independent checkers|Proof export and independent checkers]]; in plain language, [[Lean theorem prover/Explainers/Checking a proof again later|Checking a proof again later]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;lean4export&amp;lt;/code&amp;gt;.&#039;&#039;&#039; A program that writes the constants of a Lean module, and everything they depend on, to a file of terms alone, for other checkers to read. See [[Lean theorem prover/System/Proof export and independent checkers|Proof export and independent checkers]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Lean4Lean.&#039;&#039;&#039; A type checker for Lean 4 written in Lean by Mario Carneiro, parts of which have been proved correct against a formalisation of Lean&#039;s type theory. See [[Lean theorem prover/System/Proof export and independent checkers|Proof export and independent checkers]]; in plain language, [[Lean theorem prover/Explainers/Checking a proof again later|Checking a proof again later]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;leanchecker&amp;lt;/code&amp;gt;.&#039;&#039;&#039; The program, part of the Lean toolchain, that replays every definition and theorem in compiled Lean files through the Lean kernel. See [[Lean theorem prover/System/Proof export and independent checkers|Proof export and independent checkers]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Locally nameless.&#039;&#039;&#039; The representation of terms with de Bruijn indices for bound variables and names for free ones, which Lean uses. See [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]].&lt;br /&gt;
&lt;br /&gt;
== M ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Macro.&#039;&#039;&#039; A rule that rewrites one piece of syntax into another before it is given meaning. Macro expansion is interleaved with elaboration, and Lean&#039;s macros are hygienic. See [[Lean theorem prover/System/Syntax extension and hygienic macros|Syntax extension and hygienic macros]] and [[Lean theorem prover/System/Elaboration|Elaboration]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Mathlib.&#039;&#039;&#039; The single library of mathematics formalised in Lean and maintained by its community, begun in 2017 for Lean 3 and later translated to Lean 4. See [[Lean theorem prover/Explainers/A library of mathematics|A library of mathematics]] and [[Lean theorem prover/Applications/Research mathematics|Research mathematics]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Measure.&#039;&#039;&#039; A quantity that must be smaller at every recursive call, named with &amp;lt;code&amp;gt;termination_by&amp;lt;/code&amp;gt;; it justifies a definition by well-founded recursion. See [[Lean theorem prover/Foundations/Structural and well-founded recursion|Structural and well-founded recursion]]; in plain language, [[Lean theorem prover/Explainers/Functions that always finish|Functions that always finish]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Metaprogram.&#039;&#039;&#039; A Lean program whose data is Lean itself: syntax, terms, goals and Lean&#039;s environment. Tactics and elaborators are metaprograms. See [[Lean theorem prover/System/Metaprogramming in Lean|Metaprogramming in Lean]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Metatheory.&#039;&#039;&#039; What can be proved about Lean&#039;s type theory rather than in it; chiefly its consistency, which has been proved, for the type theory of Lean 3, relative to set theory with inaccessible cardinals. See [[Lean theorem prover/Foundations/Consistency and the metatheory|Consistency and the metatheory]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Metavariable.&#039;&#039;&#039; A named hole in a term: a placeholder for a subterm not yet known, which may be filled only with a term whose free variables are in its local context. Metavariables are natural, synthetic or synthetic opaque, according to who may fill them. See [[Lean theorem prover/System/Metavariables and unification|Metavariables and unification]]; in plain language, [[Lean theorem prover/Explainers/Holes and goals|Holes and goals]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Monad.&#039;&#039;&#039; A type constructor, with operations for sequencing computations, that Lean uses to represent effects such as failure, state, input and output as values. See [[Lean theorem prover/System/Monads and do-notation|Monads and do-notation]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Motive.&#039;&#039;&#039; The argument of a recursor that says what is produced, or proved, for each value. A recursor also takes one minor premise for each constructor, and the major premise, the value the recursion runs on. See [[Lean theorem prover/Foundations/Inductive types and recursors|Inductive types and recursors]].&lt;br /&gt;
&lt;br /&gt;
== N ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;nanoda&amp;lt;/code&amp;gt;.&#039;&#039;&#039; A checker for exported Lean proofs written in Rust, developed independently of Lean. See [[Lean theorem prover/System/Proof export and independent checkers|Proof export and independent checkers]]; in plain language, [[Lean theorem prover/Explainers/Checking a proof again later|Checking a proof again later]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nested inductive type.&#039;&#039;&#039; An inductive type that occurs, in its own definition, as an argument of another inductive type, as in a tree whose nodes hold lists of subtrees. Lean&#039;s kernel accepts one by translating it into a mutual definition. See [[Lean theorem prover/Foundations/Inductive types and recursors|Inductive types and recursors]].&lt;br /&gt;
&lt;br /&gt;
== O ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;omega&amp;lt;/code&amp;gt;.&#039;&#039;&#039; The tactic for linear arithmetic over the integers and the natural numbers, after Pugh&#039;s omega test. See [[Lean theorem prover/System/Decision procedures|Decision procedures]]; in plain language, [[Lean theorem prover/Explainers/Automation and its limits|Automation and its limits]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Opaque constant.&#039;&#039;&#039; A constant with a type and no definition that the Lean kernel may unfold. A &amp;lt;code&amp;gt;partial&amp;lt;/code&amp;gt; definition enters the logic as one. See [[Lean theorem prover/Foundations/Structural and well-founded recursion|Structural and well-founded recursion]].&lt;br /&gt;
&lt;br /&gt;
== P ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;partial&amp;lt;/code&amp;gt;.&#039;&#039;&#039; A mark for a recursive definition whose termination is not proved: it is compiled as written, and enters the logic as an opaque constant. See [[Lean theorem prover/Foundations/Structural and well-founded recursion|Structural and well-founded recursion]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pattern matching.&#039;&#039;&#039; Defining a function by one case for each constructor of its argument&#039;s type. Lean checks that every case is covered. See [[Lean theorem prover/Explainers/Building things from constructors|Building things from constructors]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pre-definition.&#039;&#039;&#039; The form a recursive definition takes first, elaborated as if the core language had recursion. The compiler uses it, and termination analysis turns it into a non-recursive term for the Lean kernel. See [[Lean theorem prover/Foundations/Structural and well-founded recursion|Structural and well-founded recursion]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Proof assistant.&#039;&#039;&#039; A program that checks proofs written in a formal language, step by step, while a person writes them. A formal language is a notation with fixed rules for what counts as a statement and what counts as a valid step. See [[Lean theorem prover/Explainers/What a proof assistant does|What a proof assistant does]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Proof irrelevance.&#039;&#039;&#039; The rule that any two proofs of the same proposition are interchangeable. In Lean they are definitionally equal. The name goes back to the Automath project, in 1974. See [[Lean theorem prover/Foundations/Proof irrelevance and subsingleton elimination|Proof irrelevance and subsingleton elimination]]; in plain language, [[Lean theorem prover/Explainers/Propositions as types|Propositions as types]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Proof object.&#039;&#039;&#039; A complete record of a proof, in which every step is explicit, that a small program can check. See [[Lean theorem prover/Explainers/Checking instead of convincing|Checking instead of convincing]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Proof state.&#039;&#039;&#039; The list of goals at a point in a tactic proof. The proof is complete when the list is empty. See [[Lean theorem prover/Explainers/Holes and goals|Holes and goals]] and [[Lean theorem prover/Explainers/Tactics|Tactics]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Proposition.&#039;&#039;&#039; A statement. In Lean a proposition is a type in the universe &amp;lt;code&amp;gt;Prop&amp;lt;/code&amp;gt;, and its values are its proofs. See [[Lean theorem prover/Explainers/Propositions as types|Propositions as types]] and [[Lean theorem prover/Foundations/Universes and Prop|Universes and Prop]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Propositional equality.&#039;&#039;&#039; The proposition &amp;lt;code&amp;gt;a = b&amp;lt;/code&amp;gt;: an inductive family with a single constructor, whose proofs are terms. It differs from definitional equality, which the checker tests and no term records. See [[Lean theorem prover/Foundations/Propositional equality|Propositional equality]]; in plain language, [[Lean theorem prover/Explainers/Two kinds of equality|Two kinds of equality]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Propositional extensionality.&#039;&#039;&#039; The axiom &amp;lt;code&amp;gt;propext&amp;lt;/code&amp;gt;: propositions that imply each other are equal. See [[Lean theorem prover/Foundations/The three axioms|The three axioms]]; in plain language, [[Lean theorem prover/Explainers/What the axioms are|What the axioms are]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Propositions as types.&#039;&#039;&#039; The correspondence under which a statement is a type and a proof of it is a value of that type. See [[Lean theorem prover/Explainers/Propositions as types|Propositions as types]].&lt;br /&gt;
&lt;br /&gt;
== Q ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Quotient type.&#039;&#039;&#039; A type whose elements are those of an existing type, with every pair related by a given relation made equal. Quotients are primitive in Lean, with one axiom, quotient soundness (&amp;lt;code&amp;gt;Quot.sound&amp;lt;/code&amp;gt;). See [[Lean theorem prover/Foundations/Quotient types|Quotient types]]; in plain language, [[Lean theorem prover/Explainers/What the axioms are|What the axioms are]].&lt;br /&gt;
&lt;br /&gt;
== R ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ramified theory of types.&#039;&#039;&#039; The more elaborate of Russell&#039;s theories of types, set out in a paper of 1908. See [[Lean theorem prover/Explainers/Why there is no type of all types|Why there is no type of all types]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Recursor.&#039;&#039;&#039; The constant Lean derives from an inductive definition, which is at once the type&#039;s induction principle and its means of primitive recursion; also called its recursion principle. See [[Lean theorem prover/Foundations/Inductive types and recursors|Inductive types and recursors]]; in plain language, [[Lean theorem prover/Explainers/Building things from constructors|Building things from constructors]] and [[Lean theorem prover/Explainers/Induction, as the machine sees it|Induction, as the machine sees it]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Reducibility hint.&#039;&#039;&#039; The mark 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 &amp;lt;code&amp;gt;regular&amp;lt;/code&amp;gt; with a definitional height, that decides which side Lean&#039;s kernel unfolds first when it compares two terms. See [[Lean theorem prover/Foundations/Definitional equality|Definitional equality]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Reference counting.&#039;&#039;&#039; Lean&#039;s way of managing memory: each object counts the references to it and is freed when the count reaches zero. A value that is not shared may be changed in place, so code written as pure functions can run with updates in place. See [[Lean theorem prover/System/The compiler and runtime|The compiler and runtime]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Reflexivity.&#039;&#039;&#039; The principle that everything is equal to itself. The proof &amp;lt;code&amp;gt;rfl&amp;lt;/code&amp;gt; proves an equation exactly when the two sides are definitionally equal. See [[Lean theorem prover/Explainers/Two kinds of equality|Two kinds of equality]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Restricted elimination.&#039;&#039;&#039; The rule that a proof can be taken apart to produce data only when its proposition is a subsingleton. See [[Lean theorem prover/Foundations/Proof irrelevance and subsingleton elimination|Proof irrelevance and subsingleton elimination]] and [[Lean theorem prover/Foundations/Universes and Prop|Universes and Prop]].&lt;br /&gt;
&lt;br /&gt;
== S ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Setoid.&#039;&#039;&#039; A type with a chosen relation and a proof that the relation is reflexive, symmetric and transitive; Lean&#039;s &amp;lt;code&amp;gt;Quotient&amp;lt;/code&amp;gt; is the quotient by a setoid&#039;s relation. See [[Lean theorem prover/Foundations/Quotient types|Quotient types]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;simp&amp;lt;/code&amp;gt;.&#039;&#039;&#039; The simplifier: a tactic that rewrites the goal with the simp set, the theorems marked &amp;lt;code&amp;gt;@[simp]&amp;lt;/code&amp;gt;, each read as an equation from left to right. See [[Lean theorem prover/System/Decision procedures|Decision procedures]]; in plain language, [[Lean theorem prover/Explainers/Automation and its limits|Automation and its limits]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Specification.&#039;&#039;&#039; A precise statement of what is required of a program or a value. A type can serve as one. See [[Lean theorem prover/Explainers/Types as specifications|Types as specifications]] and [[Lean theorem prover/Applications/Software verification|Software verification]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Strict positivity.&#039;&#039;&#039; The condition that the type being defined occur in the argument types of its constructors only to the right of every arrow, or as an argument of another inductive type. Lean&#039;s kernel enforces it, because a type breaking it would prove &amp;lt;code&amp;gt;False&amp;lt;/code&amp;gt;. See [[Lean theorem prover/Foundations/Inductive types and recursors|Inductive types and recursors]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Structural recursion.&#039;&#039;&#039; Recursion in which every call is on a strict part of one fixed argument. Lean compiles it through the recursor, so no separate test of termination is needed. See [[Lean theorem prover/Foundations/Structural and well-founded recursion|Structural and well-founded recursion]]; in plain language, [[Lean theorem prover/Explainers/Functions that always finish|Functions that always finish]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Structure.&#039;&#039;&#039; An inductive type with exactly one constructor, whose arguments are called its fields. See [[Lean theorem prover/Explainers/Building things from constructors|Building things from constructors]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Subject reduction.&#039;&#039;&#039; The property that a term which type-checks still type-checks after it is reduced. Lean&#039;s typing, with the algorithmic definitional equality that the Lean kernel checks, lacks it. See [[Lean theorem prover/Foundations/Definitional equality|Definitional equality]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Subsingleton.&#039;&#039;&#039; A proposition that, by its shape, can have at most one proof. Subsingleton elimination is the permission such a proposition has to be eliminated into any universe. See [[Lean theorem prover/Foundations/Proof irrelevance and subsingleton elimination|Proof irrelevance and subsingleton elimination]] and [[Lean theorem prover/Foundations/Inductive types and recursors|Inductive types and recursors]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Subtype.&#039;&#039;&#039; The type of the values of a given type that have a given property, written &amp;lt;code&amp;gt;{x : A // p x}&amp;lt;/code&amp;gt;. Each of its values is a value together with a proof. See [[Lean theorem prover/Explainers/Types as specifications|Types as specifications]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Syntax quotation.&#039;&#039;&#039; Syntax written inside &amp;lt;code&amp;gt;`(...)&amp;lt;/code&amp;gt;, used in a macro to match syntax or to produce it; antiquotations inside it are the holes. Each grammar rule belongs to a syntax category, such as &amp;lt;code&amp;gt;term&amp;lt;/code&amp;gt;. See [[Lean theorem prover/System/Syntax extension and hygienic macros|Syntax extension and hygienic macros]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Synthetic metavariable.&#039;&#039;&#039; A metavariable that unification avoids assigning, because another procedure, usually instance resolution, is responsible for it; the elaborator uses them for postponed work. A synthetic opaque metavariable is never assigned by unification; goals are of this kind. See [[Lean theorem prover/System/Metavariables and unification|Metavariables and unification]] and [[Lean theorem prover/System/Elaboration|Elaboration]].&lt;br /&gt;
&lt;br /&gt;
== T ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tabled typeclass resolution.&#039;&#039;&#039; Lean&#039;s method of instance resolution, which keeps a table from each subgoal to the solutions already found for it and reuses them. Its authors proposed it to remove the exponential cost of diamonds in a hierarchy of classes and the loops caused by cycles of instances. See [[Lean theorem prover/System/Type classes and instance resolution|Type classes and instance resolution]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tactic.&#039;&#039;&#039; A program that constructs part of a proof term, acting on goals. The name is Milner&#039;s, from LCF: there a tactic was a function reducing a goal to subgoals, and tacticals combined tactics. See [[Lean theorem prover/System/The tactic framework|The tactic framework]] and [[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]]; in plain language, [[Lean theorem prover/Explainers/Tactics|Tactics]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Term.&#039;&#039;&#039; Anything in Lean&#039;s type theory: a number, a function, a type, a proposition, a proof. In a proof written as a term, the term is an expression whose type is the statement. See [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]]; in plain language, [[Lean theorem prover/Explainers/Tactics|Tactics]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Total function.&#039;&#039;&#039; A function defined on every argument, which returns in finitely many steps. Lean&#039;s logic treats every function as total. See [[Lean theorem prover/Foundations/Structural and well-founded recursion|Structural and well-founded recursion]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Transport.&#039;&#039;&#039; Obtaining, from a proof of &amp;lt;code&amp;gt;a = b&amp;lt;/code&amp;gt; and a term whose type mentions &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;, the same term at &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt;. It is derived from the eliminator of equality. See [[Lean theorem prover/Foundations/Propositional equality|Propositional equality]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Type class.&#039;&#039;&#039; A structure whose values, the instances, Lean finds by itself: a description of what a type must provide. See [[Lean theorem prover/System/Type classes and instance resolution|Type classes and instance resolution]]; in plain language, [[Lean theorem prover/Explainers/A library of mathematics|A library of mathematics]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Type inference.&#039;&#039;&#039; Computing a type for a term in a context. Type checking, by contrast, decides whether a term has a given type. Lean&#039;s kernel is built around inference. See [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Typing judgment.&#039;&#039;&#039; The basic statement of the theory, &amp;lt;math&amp;gt;\Gamma \vdash e : A&amp;lt;/math&amp;gt;: in the context &amp;lt;math&amp;gt;\Gamma&amp;lt;/math&amp;gt;, the term &amp;lt;math&amp;gt;e&amp;lt;/math&amp;gt; has type &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;. A term is well-typed when such a judgment can be derived for it. See [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]].&lt;br /&gt;
&lt;br /&gt;
== U ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Unification.&#039;&#039;&#039; The search for values of metavariables that make two terms definitionally equal. See [[Lean theorem prover/System/Metavariables and unification|Metavariables and unification]]; in plain language, [[Lean theorem prover/Explainers/Holes and goals|Holes and goals]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Uniqueness of identity proofs.&#039;&#039;&#039; The principle that any two proofs of &amp;lt;code&amp;gt;a = b&amp;lt;/code&amp;gt; are equal. In Lean it holds by definitional proof irrelevance. See [[Lean theorem prover/Foundations/Propositional equality|Propositional equality]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Universe.&#039;&#039;&#039; A type whose members are types; also called a sort.&amp;lt;ref name=&amp;quot;gl-universes&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, version for Lean 4.34.0, section 4.3, &amp;quot;Universes&amp;quot;. [https://lean-lang.org/doc/reference/4.34.0/The-Type-System/Universes/ lean-lang.org/doc/reference/4.34.0/The-Type-System/Universes/], consulted 14 October 2026.&amp;lt;/ref&amp;gt; Lean&#039;s universes &amp;lt;code&amp;gt;Sort u&amp;lt;/code&amp;gt; form a hierarchy without top, each a member of the next, with &amp;lt;code&amp;gt;Prop&amp;lt;/code&amp;gt; at the bottom; they are not cumulative. See [[Lean theorem prover/Foundations/Universes and Prop|Universes and Prop]]; in plain language, [[Lean theorem prover/Explainers/Why there is no type of all types|Why there is no type of all types]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;unsafe&amp;lt;/code&amp;gt;.&#039;&#039;&#039; A mark that frees a definition from Lean&#039;s restrictions, at the price that only other unsafe definitions may use it and no theorem may. See [[Lean theorem prover/Foundations/Structural and well-founded recursion|Structural and well-founded recursion]].&lt;br /&gt;
&lt;br /&gt;
== W ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Weak head normal form.&#039;&#039;&#039; The result of reducing a term at its head until no rule applies: a sort, a function type, an abstraction, a literal, a constructor application, or an application whose head cannot be unfolded or reduced. See [[Lean theorem prover/Foundations/Definitional equality|Definitional equality]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Well-founded recursion.&#039;&#039;&#039; Recursion justified by a quantity, or a well-founded relation, that decreases at every call. A relation is well-founded when it has no infinite descending chain. See [[Lean theorem prover/Foundations/Structural and well-founded recursion|Structural and well-founded recursion]]; in plain language, [[Lean theorem prover/Explainers/Functions that always finish|Functions that always finish]].&lt;br /&gt;
&lt;br /&gt;
== Z ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Zeta reduction.&#039;&#039;&#039; The rule that a local definition equals its body with the defined value substituted.&amp;lt;ref name=&amp;quot;gl-types&amp;quot; /&amp;gt; See [[Lean theorem prover/Foundations/Definitional equality|Definitional equality]].&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
* [[Lean theorem prover/Notation|Notation]]&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>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/Chronology&amp;diff=6816</id>
		<title>Lean theorem prover/Chronology</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Chronology&amp;diff=6816"/>
		<updated>2026-10-15T19:35:46Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Chronology}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
A timeline of Lean and of the work it grew from, from Automath to October 2026.&lt;br /&gt;
&lt;br /&gt;
Every entry is stated, with its source, on the page named in its last column, and this page&lt;br /&gt;
adds nothing to those pages. Dates are of first statement, first publication or first&lt;br /&gt;
version, as the entry says. The dates of Lean&#039;s versions are those of its version&lt;br /&gt;
notes.&amp;lt;ref name=&amp;quot;relnotes&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, &amp;quot;Release Notes&amp;quot;, list of versions&lt;br /&gt;
with their dates (read 14 October 2026). https://lean-lang.org/doc/reference/latest/releases/&amp;lt;/ref&amp;gt;&lt;br /&gt;
Where a page gives two dates for one event, both are given here.&lt;br /&gt;
&lt;br /&gt;
== Before Lean: 1966 to 2012 ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! date !! event !! page&lt;br /&gt;
|-&lt;br /&gt;
| 1966 or 1967 || &#039;&#039;&#039;Automath&#039;&#039;&#039; conceived by N. G. de Bruijn at Eindhoven; his own accounts give 1966 and early 1967 || [[Lean theorem prover/History/Automath|Automath]]&lt;br /&gt;
|-&lt;br /&gt;
| Dec 1968 || De Bruijn presents the Automath language at the Symposium on Automatic Demonstration, Versailles; printed 1970 || [[Lean theorem prover/History/Automath|Automath]]&lt;br /&gt;
|-&lt;br /&gt;
| 1969 || Dana Scott devises the logic for computable functions that LCF is named after; his manuscript is published in 1993 || [[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]]&lt;br /&gt;
|-&lt;br /&gt;
| 1971 || Per Martin-Löf&#039;s first type theory, an unpublished preprint, with a type of all types || [[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]]&lt;br /&gt;
|-&lt;br /&gt;
| 1971 to 1976 || I. Zandleven writes most of Automath&#039;s checking programs || [[Lean theorem prover/History/Automath|Automath]]&lt;br /&gt;
|-&lt;br /&gt;
| 1972 || Jean-Yves Girard&#039;s thesis shows a type of all types contradictory; Martin-Löf replaces it by a universe of small types (paper published 1998) || [[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]]&lt;br /&gt;
|-&lt;br /&gt;
| 1972 || De Bruijn proposes writing bound variables as numbers, the &#039;&#039;&#039;de Bruijn indices&#039;&#039;&#039; Lean&#039;s terms still use || [[Lean theorem prover/History/Automath|Automath]]&lt;br /&gt;
|-&lt;br /&gt;
| May 1972 || Robin Milner&#039;s report on &#039;&#039;&#039;Stanford LCF&#039;&#039;&#039; || [[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]]&lt;br /&gt;
|-&lt;br /&gt;
| c. 1973 || Milner begins Edinburgh LCF: a protected type of theorems, and tactics || [[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]]&lt;br /&gt;
|-&lt;br /&gt;
| Jul 1973 || Martin-Löf at the Logic Colloquium, Bristol: a hierarchy of universes and an identity type; printed 1975 || [[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]]&lt;br /&gt;
|-&lt;br /&gt;
| 1974 || The name &#039;&#039;&#039;proof irrelevance&#039;&#039;&#039; appears in an Automath report || [[Lean theorem prover/History/Automath|Automath]]&lt;br /&gt;
|-&lt;br /&gt;
| 1976 || L. S. van Benthem Jutting&#039;s translation of Landau&#039;s &#039;&#039;Grundlagen der Analysis&#039;&#039; into Automath, in a five-volume report; his thesis 1977, published 1979 || [[Lean theorem prover/History/Automath|Automath]]&lt;br /&gt;
|-&lt;br /&gt;
| 1978 || ML, the metalanguage of LCF, described at the Symposium on Principles of Programming Languages; Milner&#039;s paper on polymorphic type inference || [[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]]&lt;br /&gt;
|-&lt;br /&gt;
| 1979 || &#039;&#039;Edinburgh LCF&#039;&#039;, by Gordon, Milner and Wadsworth || [[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]]&lt;br /&gt;
|-&lt;br /&gt;
| 1979 || Martin-Löf, &amp;quot;Constructive mathematics and computer programming&amp;quot;, Hannover; the extensional theory; published 1982 || [[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]]&lt;br /&gt;
|-&lt;br /&gt;
| 1980 || De Bruijn&#039;s survey of the Automath project || [[Lean theorem prover/History/Automath|Automath]]&lt;br /&gt;
|-&lt;br /&gt;
| Jun 1980 || Martin-Löf&#039;s Padua lectures, published in 1984 as &#039;&#039;Intuitionistic Type Theory&#039;&#039; || [[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]]&lt;br /&gt;
|-&lt;br /&gt;
| 1983 to 1985 || The first type checker for the Theory of Constructions, mostly Gérard Huet&#039;s work || [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]]&lt;br /&gt;
|-&lt;br /&gt;
| Jun 1984 || Coquand and Huet present a preliminary version of the calculus at Sophia-Antipolis || [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]]&lt;br /&gt;
|-&lt;br /&gt;
| 31 Jan 1985 || Thierry Coquand defends his thesis on the Theory of Constructions || [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]]&lt;br /&gt;
|-&lt;br /&gt;
| c. 1985 || Cambridge LCF, by Lawrence Paulson; described in his book of 1987 || [[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]]&lt;br /&gt;
|-&lt;br /&gt;
| 1986 || Nuprl, a proof assistant for an extensional type theory, described in a book; Martin-Löf recasts his theory in a logical framework || [[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]]&lt;br /&gt;
|-&lt;br /&gt;
| May 1986 || &#039;&#039;&#039;The Calculus of Constructions&#039;&#039;&#039;, under that name, in an INRIA report; in &#039;&#039;Information and Computation&#039;&#039; 1988 || [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]]&lt;br /&gt;
|-&lt;br /&gt;
| 1988 || Version 4.7 of the system later named Coq keeps its proof checker, the Constructive Engine, apart as a trusted core; HOL88 appears about the same year || [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]], [[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]]&lt;br /&gt;
|-&lt;br /&gt;
| 1989 || Inductive types added as primitives: the &#039;&#039;&#039;Calculus of Inductive Constructions&#039;&#039;&#039;, by the Coq manual&#039;s date; the paper, presented at COLOG-88, is published in 1990 || [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]]&lt;br /&gt;
|-&lt;br /&gt;
| end of 1989 || The system is named Coq, with version 5.1 || [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]]&lt;br /&gt;
|-&lt;br /&gt;
| 1991 || Milner receives the ACM Turing Award; the citation names LCF and ML || [[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]]&lt;br /&gt;
|-&lt;br /&gt;
| 1993 || Christine Paulin-Mohring sets out the rules of the Calculus of Inductive Constructions || [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]]&lt;br /&gt;
|-&lt;br /&gt;
| 1994 || &#039;&#039;Selected Papers on Automath&#039;&#039;; the ALF proof editor || [[Lean theorem prover/History/Automath|Automath]], [[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]]&lt;br /&gt;
|-&lt;br /&gt;
| 1995 || Antonius Hurkens publishes a simplified form of Girard&#039;s paradox || [[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]]&lt;br /&gt;
|-&lt;br /&gt;
| 2002 || Freek Wiedijk&#039;s new Automath checker checks the &#039;&#039;Grundlagen&#039;&#039; translation in 0.6 seconds || [[Lean theorem prover/History/Automath|Automath]]&lt;br /&gt;
|-&lt;br /&gt;
| 2007 || Ulf Norell&#039;s thesis designs and implements a new Agda || [[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Lean 1 to Lean 3: 2013 to 2022 ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! date !! event !! page&lt;br /&gt;
|-&lt;br /&gt;
| 2013 || &#039;&#039;&#039;Lean&#039;&#039;&#039; begun by Leonardo de Moura at Microsoft Research || [[Lean theorem prover/History/Lean 1 to Lean 3|Lean 1 to Lean 3]]&lt;br /&gt;
|-&lt;br /&gt;
| 2013 || The ACM Software System Award goes to the team that first developed Coq || [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]]&lt;br /&gt;
|-&lt;br /&gt;
| 16 Jun 2014 || Lean 0.1, the first version || [[Lean theorem prover/History/Lean 1 to Lean 3|Lean 1 to Lean 3]]&lt;br /&gt;
|-&lt;br /&gt;
| 2015 || &#039;&#039;&#039;&amp;quot;The Lean Theorem Prover (system description)&amp;quot;&#039;&#039;&#039;, CADE-25, describing the version now called Lean 2 || [[Lean theorem prover/History/Lean 1 to Lean 3|Lean 1 to Lean 3]]&lt;br /&gt;
|-&lt;br /&gt;
| 2016 || Maryna Viazovska proves that the &amp;lt;math&amp;gt;E_8&amp;lt;/math&amp;gt; lattice gives the densest sphere packing in eight dimensions || [[Lean theorem prover/Applications/Research mathematics|Research mathematics]]&lt;br /&gt;
|-&lt;br /&gt;
| 20 Jan 2017 || Lean 3.0.0 || [[Lean theorem prover/History/Lean 1 to Lean 3|Lean 1 to Lean 3]]&lt;br /&gt;
|-&lt;br /&gt;
| 2017 || Metaprogramming in Lean 3: tactics written in Lean itself || [[Lean theorem prover/History/Lean 1 to Lean 3|Lean 1 to Lean 3]]&lt;br /&gt;
|-&lt;br /&gt;
| summer 2017 || &#039;&#039;&#039;mathlib&#039;&#039;&#039; begins, from the core library of Lean 3 || [[Lean theorem prover/History/Mathlib and its community|Mathlib and its community]]&lt;br /&gt;
|-&lt;br /&gt;
| 2018 || Work on Lean 4 begins || [[Lean theorem prover/History/Lean 4|Lean 4]]&lt;br /&gt;
|-&lt;br /&gt;
| 18 Jan 2019 || Lean 3.4.2, the last official version of Lean 3 || [[Lean theorem prover/History/Lean 1 to Lean 3|Lean 1 to Lean 3]]&lt;br /&gt;
|-&lt;br /&gt;
| 2019 || Mario Carneiro&#039;s account of Lean&#039;s type theory || [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]]&lt;br /&gt;
|-&lt;br /&gt;
| 26 Dec 2019 || Lean 3.5.0c, the first version maintained by the community || [[Lean theorem prover/History/Lean 1 to Lean 3|Lean 1 to Lean 3]]&lt;br /&gt;
|-&lt;br /&gt;
| Jan 2020 || &amp;quot;The Lean Mathematical Library&amp;quot;, by the mathlib Community, at CPP in New Orleans || [[Lean theorem prover/History/Mathlib and its community|Mathlib and its community]]&lt;br /&gt;
|-&lt;br /&gt;
| 5 Dec 2020 || Peter Scholze sets the &#039;&#039;&#039;Liquid Tensor Experiment&#039;&#039;&#039; challenge || [[Lean theorem prover/History/The Liquid Tensor Experiment|The Liquid Tensor Experiment]]&lt;br /&gt;
|-&lt;br /&gt;
| early 2021 || Lean 4 made public || [[Lean theorem prover/History/Lean 4|Lean 4]]&lt;br /&gt;
|-&lt;br /&gt;
| 2021 || &#039;&#039;&#039;&amp;quot;The Lean 4 Theorem Prover and Programming Language&amp;quot;&#039;&#039;&#039;, CADE-28 || [[Lean theorem prover/History/Lean 4|Lean 4]]&lt;br /&gt;
|-&lt;br /&gt;
| 2021 || The miniF2F benchmark of formal competition problems || [[Lean theorem prover/Applications/Machine learning and theorem proving|Machine learning and theorem proving]]&lt;br /&gt;
|-&lt;br /&gt;
| 28 May 2021 || The proof of Theorem 9.4, the one result Scholze had been worried about, is formalised || [[Lean theorem prover/History/The Liquid Tensor Experiment|The Liquid Tensor Experiment]]&lt;br /&gt;
|-&lt;br /&gt;
| Dec 2021 || Plan for porting mathlib, then over 700,000 lines, to Lean 4 with Mathport || [[Lean theorem prover/History/Lean 4|Lean 4]]&lt;br /&gt;
|-&lt;br /&gt;
| 14 Jul 2022 || The Liquid Tensor Experiment completed || [[Lean theorem prover/History/The Liquid Tensor Experiment|The Liquid Tensor Experiment]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Lean 4: 2023 to October 2026 ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! date !! event !! page&lt;br /&gt;
|-&lt;br /&gt;
| 24 May 2023 || Lean 3.51.1c, the last community version of Lean 3 || [[Lean theorem prover/History/Lean 1 to Lean 3|Lean 1 to Lean 3]]&lt;br /&gt;
|-&lt;br /&gt;
| Jul 2023 || De Moura and Sebastian Ullrich found the &#039;&#039;&#039;Lean Focused Research Organization&#039;&#039;&#039; || [[Lean theorem prover/History/Lean since 2023|Lean since 2023]]&lt;br /&gt;
|-&lt;br /&gt;
| 16 Jul 2023 || The port of mathlib to Lean 4 declared complete || [[Lean theorem prover/History/Lean 4|Lean 4]]&lt;br /&gt;
|-&lt;br /&gt;
| 8 Sep 2023 || &#039;&#039;&#039;Lean 4.0.0&#039;&#039;&#039;, the first stable version; a new version about every month follows || [[Lean theorem prover/History/Lean 4|Lean 4]]&lt;br /&gt;
|-&lt;br /&gt;
| 9 Nov 2023 || Gowers, Green, Manners and Tao post their proof of the polynomial Freiman–Ruzsa conjecture in characteristic 2 || [[Lean theorem prover/Applications/The polynomial Freiman-Ruzsa conjecture|The polynomial Freiman-Ruzsa conjecture]]&lt;br /&gt;
|-&lt;br /&gt;
| 5 Dec 2023 || The formalisation of that proof is complete, three weeks after it began || [[Lean theorem prover/Applications/The polynomial Freiman-Ruzsa conjecture|The polynomial Freiman-Ruzsa conjecture]]&lt;br /&gt;
|-&lt;br /&gt;
| Dec 2023 || Start of the Fermat&#039;s Last Theorem project, by the Lean FRO&#039;s timeline; announced April 2024 || [[Lean theorem prover/History/Lean since 2023|Lean since 2023]], [[Lean theorem prover/Applications/The Fermat&#039;s Last Theorem project|The Fermat&#039;s Last Theorem project]]&lt;br /&gt;
|-&lt;br /&gt;
| Mar 2024 || Sidharth Hariharan and Viazovska begin formalising the eight-dimensional sphere packing || [[Lean theorem prover/Applications/Research mathematics|Research mathematics]]&lt;br /&gt;
|-&lt;br /&gt;
| 2024 || HepLean, later part of Physlib, begins || [[Lean theorem prover/Applications/Physics in Lean|Physics in Lean]]&lt;br /&gt;
|-&lt;br /&gt;
| Jul 2024 || Google DeepMind reports that AlphaProof, with a second system for geometry, reached silver-medal standard at the International Mathematical Olympiad || [[Lean theorem prover/Applications/Machine learning and theorem proving|Machine learning and theorem proving]]&lt;br /&gt;
|-&lt;br /&gt;
| 25 Sep 2024 || Terence Tao proposes the &#039;&#039;&#039;equational theories project&#039;&#039;&#039; || [[Lean theorem prover/Applications/The equational theories project|The equational theories project]]&lt;br /&gt;
|-&lt;br /&gt;
| Oct 2024 || The Fermat project&#039;s research council fellowship begins, to run until September 2029 || [[Lean theorem prover/Applications/The Fermat&#039;s Last Theorem project|The Fermat&#039;s Last Theorem project]]&lt;br /&gt;
|-&lt;br /&gt;
| Dec 2024 || Kevin Buzzard reports the problem met in a 1965 paper on divided powers sorted out, and the Fermat project back on track || [[Lean theorem prover/Applications/The Fermat&#039;s Last Theorem project|The Fermat&#039;s Last Theorem project]]&lt;br /&gt;
|-&lt;br /&gt;
| 12 Mar 2025 || Version 9.0 of the Rocq Prover completes the renaming of Coq || [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]]&lt;br /&gt;
|-&lt;br /&gt;
| 14 Apr 2025 || The equational theories project reaches its primary goal: all 22,028,942 implications decided || [[Lean theorem prover/Applications/The equational theories project|The equational theories project]]&lt;br /&gt;
|-&lt;br /&gt;
| 2025 || Lean receives the ACM SIGPLAN Programming Languages Software Award; the 2015 system description receives the CADE Skolem Award || [[Lean theorem prover/History/Lean since 2023|Lean since 2023]]&lt;br /&gt;
|-&lt;br /&gt;
| Jul 2025 || Gifts of $5 million each to the Lean FRO and to Mathlib announced, with a Mathlib Initiative to be set up || [[Lean theorem prover/History/Mathlib and its community|Mathlib and its community]]&lt;br /&gt;
|-&lt;br /&gt;
| 14 Aug 2025 || Lean 4.22.0: a new compiler, and the &amp;lt;code&amp;gt;grind&amp;lt;/code&amp;gt; tactic || [[Lean theorem prover/History/Lean since 2023|Lean since 2023]]&lt;br /&gt;
|-&lt;br /&gt;
| Nov 2025 || AlphaProof&#039;s method published in &#039;&#039;Nature&#039;&#039; || [[Lean theorem prover/Applications/Machine learning and theorem proving|Machine learning and theorem proving]]&lt;br /&gt;
|-&lt;br /&gt;
| Dec 2025 || The equational theories project&#039;s paper, with 34 authors || [[Lean theorem prover/Applications/The equational theories project|The equational theories project]]&lt;br /&gt;
|-&lt;br /&gt;
| Feb 2026 || The formal proof of sphere packing in dimension 8 completed, its final stages by an autoformalisation model || [[Lean theorem prover/Applications/Research mathematics|Research mathematics]]&lt;br /&gt;
|-&lt;br /&gt;
| Jul 2026 || Microsoft&#039;s SymCrypt code verified in Lean is in preview versions of Windows || [[Lean theorem prover/Applications/Software verification|Software verification]]&lt;br /&gt;
|-&lt;br /&gt;
| 22 Jul 2026 || Lean 4.32.1 fixes a soundness bug in the Lean kernel open to malicious metaprograms || [[Lean theorem prover/History/Lean since 2023|Lean since 2023]]&lt;br /&gt;
|-&lt;br /&gt;
| 25 Jul 2026 || A false &amp;quot;disproof&amp;quot; of the Collatz conjecture, exploiting a bug in the Lean kernel, is published || [[Lean theorem prover/History/Lean since 2023|Lean since 2023]]&lt;br /&gt;
|-&lt;br /&gt;
| 28 Jul 2026 || The exploit reduced to a short proof of &amp;lt;code&amp;gt;False&amp;lt;/code&amp;gt; and reported; Lean 4.32.2 fixes it || [[Lean theorem prover/History/Lean since 2023|Lean since 2023]]&lt;br /&gt;
|-&lt;br /&gt;
| Aug 2026 || A dataset of Lean statements of 50 theorems from the &#039;&#039;Annals of Mathematics&#039;&#039; announced || [[Lean theorem prover/Applications/Research mathematics|Research mathematics]]&lt;br /&gt;
|-&lt;br /&gt;
| 4 Sep 2026 || Anthropic announces a machine-written formal proof of Fermat&#039;s Last Theorem || [[Lean theorem prover/Applications/The Fermat&#039;s Last Theorem project|The Fermat&#039;s Last Theorem project]]&lt;br /&gt;
|-&lt;br /&gt;
| Sep 2026 || The Lean FRO moves to six-month roadmaps, with independent checking planned as a routine step || [[Lean theorem prover/History/Lean since 2023|Lean since 2023]]&lt;br /&gt;
|-&lt;br /&gt;
| 24 Sep 2026 || &#039;&#039;&#039;Lean 4.34.1&#039;&#039;&#039;, the version with which this edition&#039;s code is checked || [[Lean theorem prover/History/Lean since 2023|Lean since 2023]]&lt;br /&gt;
|-&lt;br /&gt;
| 12 Oct 2026 || Lean 4.35.0 || [[Lean theorem prover/History/Lean since 2023|Lean since 2023]]&lt;br /&gt;
|-&lt;br /&gt;
| Oct 2026 || This wiki&#039;s framework for testing physical hypotheses is being restated in Lean, with Lean 4.34.1 pinned || [[Lean theorem prover/Applications/Principia Machina|Principia Machina]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/Glossary|Glossary]], the edition&#039;s terms.&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>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/Applications/Principia_Machina&amp;diff=6815</id>
		<title>Lean theorem prover/Applications/Principia Machina</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Applications/Principia_Machina&amp;diff=6815"/>
		<updated>2026-10-15T19:35:45Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Principia Machina}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
&#039;&#039;&#039;Principia Machina&#039;&#039;&#039; is this wiki&#039;s framework for testing physical hypotheses, restated in Lean 4. Its first version, [[The Principia Machina]], stays on the wiki as history; the second is being written as Lean definitions and theorems. This page describes the framework, and the reasons for the move, only as far as the wiki&#039;s own account, [[Principia Machina/Lean transition|the move to Lean]], states them, with that account&#039;s status as of 14 October 2026.&amp;lt;ref name=&amp;quot;lt&amp;quot;&amp;gt;&amp;quot;Principia Machina: the move to Lean&amp;quot;, the page [[Principia Machina/Lean transition]] on this wiki, status as of 14 October 2026.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The framework ==&lt;br /&gt;
&lt;br /&gt;
The framework exists so that anyone can check a result afterwards. A piece of research starts from a sealed set of laws and assumptions. Its derivations show every step and count every assumption. Its results stand only while nothing contradicts them. AI agents may do much of the work without being trusted for it.&amp;lt;ref name=&amp;quot;lt&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Version 2 names its parts with words rather than three-letter codes:&amp;lt;ref name=&amp;quot;lt&amp;quot; /&amp;gt;&lt;br /&gt;
* the &#039;&#039;&#039;Starting Set&#039;&#039;&#039;: the laws, assumptions, boundaries and constants a piece of research starts from;&lt;br /&gt;
* the &#039;&#039;&#039;Correspondence Table&#039;&#039;&#039;: the dictionary between the Starting Set and what is measured;&lt;br /&gt;
* the &#039;&#039;&#039;Criteria Set&#039;&#039;&#039;: the declared yardsticks and tests;&lt;br /&gt;
* the &#039;&#039;&#039;Research Assembly&#039;&#039;&#039;: the three together, sealed;&lt;br /&gt;
* &#039;&#039;&#039;Custos&#039;&#039;&#039;: the thin server extension that guards the wiki;&lt;br /&gt;
* the &#039;&#039;&#039;Calculator&#039;&#039;&#039;: the one compiled program, &amp;lt;code&amp;gt;pcalc&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Each of these words except Custos also names a part of the Lean sources, such as &amp;lt;code&amp;gt;Principia.StartingSet&amp;lt;/code&amp;gt; for the Starting Set. The authority rules do not change: the Declarer declares each version and each admission, the Operator runs every action on the wiki and its host, no agent handles a secret, and nothing is deleted.&amp;lt;ref name=&amp;quot;lt&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Why Lean ==&lt;br /&gt;
&lt;br /&gt;
In version 1 three things were kept apart. The rules were written in prose. The computation existed in two hand-written copies, PHP for the server and Python for agents, which 6,786 test cases held identical. Many checks were left to a reader&#039;s judgement.&amp;lt;ref name=&amp;quot;lt&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean 4 is three things in one language: a precise way to state rules, a programming language that compiles to native programs, and a proof checker, the Lean kernel, which accepts a result only when it is proved.&amp;lt;ref name=&amp;quot;lt&amp;quot; /&amp;gt;&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&amp;quot;, in &#039;&#039;Automated Deduction – CADE 28&#039;&#039;, Lecture Notes in Computer Science 12699, Springer, 2021, pp. 625–635. doi:10.1007/978-3-030-79876-5_37&amp;lt;/ref&amp;gt; The account of the move pairs each aim of the framework with what Lean provides for it; among the pairs:&amp;lt;ref name=&amp;quot;lt&amp;quot; /&amp;gt;&lt;br /&gt;
* results anyone can check afterwards: the Lean kernel checks every proof, whoever wrote it;&lt;br /&gt;
* a sealed Starting Set: definitions and hypotheses, named in every statement that uses them;&lt;br /&gt;
* derivations that count every assumption: a proof cites each definition, lemma and hypothesis it uses, and Lean lists the axioms beneath it;&lt;br /&gt;
* checks the server runs, not a person: the same definitions compile to a program, the Calculator;&lt;br /&gt;
* AI agents who need not be trusted: the Lean kernel judges the proof, not its author.&lt;br /&gt;
&lt;br /&gt;
== One Calculator for the server and every agent ==&lt;br /&gt;
&lt;br /&gt;
Version 2 writes the rules once, as Lean definitions and theorems. The same sources compile to one program, the Calculator, which serves both the wiki&#039;s server and every agent. Version 1 needed a corpus of tests to show that its two calculators agreed; with one program the two sides agree by construction.&amp;lt;ref name=&amp;quot;lt&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Custos keeps what MediaWiki forces into PHP: its hooks, its API surface and its job queue, together with the forms, the meter and the page writes. Every computation is a call into the Calculator, and the program&#039;s digest is checked before each call.&amp;lt;ref name=&amp;quot;lt&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The Lean kernel as the proof gate ==&lt;br /&gt;
&lt;br /&gt;
The first version to be declared is to be the Principia Framework Specification 1.0.0 with the Calculator 1.0.0, and it must meet eight criteria. One of them is &#039;&#039;&#039;the proof gate&#039;&#039;&#039;: nothing is accepted with an unfinished proof (&amp;lt;code&amp;gt;sorry&amp;lt;/code&amp;gt;), a new axiom, &amp;lt;code&amp;gt;native_decide&amp;lt;/code&amp;gt; or unsafe code, and a machine enforces this, not a reviewer. Another asks for key properties to be proved, at least these: every digest&#039;s input encoding is one-to-one; every zone and record survives a round trip through its text form; the yardstick rules never rank a refuted record above a sound one, never improve a rank for an added assumption, and never let a measurement strike a derivation; and the server&#039;s first three admission lanes are never refused for lack of budget.&amp;lt;ref name=&amp;quot;lt&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Version 1 had two check classes, INSPECTION and MECHANICAL. Version 2 adds a third, &#039;&#039;&#039;PROVED&#039;&#039;&#039;: a property the Lean kernel has checked once, for every input. A derivation may take one of three forms, and the server records the highest form it actually checked:&amp;lt;ref name=&amp;quot;lt&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Form !! Checked by !! Class recorded&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PROSE&amp;lt;/code&amp;gt; || a person or an agent || INSPECTION&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;STRUCTURED&amp;lt;/code&amp;gt; || the Calculator || MECHANICAL&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;KERNEL&amp;lt;/code&amp;gt; || the Lean kernel || PROVED&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A form the server cannot yet check is recorded as prose, never as checked. Structured derivations come in the first version; derivations checked by the Lean kernel follow once a checker for them has been shown to run within the host&#039;s limits.&amp;lt;ref name=&amp;quot;lt&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Specification pages from the sources ==&lt;br /&gt;
&lt;br /&gt;
In version 1 the specification was prose, separate from the code that computed it. In version 2 the specification is the source code. The specification pages are generated from the same Lean sources as the Calculator, so the published rules and the program that applies them come from one text and cannot drift apart.&amp;lt;ref name=&amp;quot;lt&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== A small example ==&lt;br /&gt;
&lt;br /&gt;
The account of the move solves a two-doors riddle twice, once in ordinary mathematics and once in Lean, and shows the whole Lean file.&amp;lt;ref name=&amp;quot;lt&amp;quot; /&amp;gt; In a shortened form, two guards stand at two doors; one always tells the truth, the other always lies; and the strategy is to ask either guard whether the other would say the left door is safe, then take the right door on &amp;quot;yes&amp;quot; and the left on &amp;quot;no&amp;quot;:&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;
inductive Door where&lt;br /&gt;
  | left&lt;br /&gt;
  | right&lt;br /&gt;
  deriving DecidableEq, Repr&lt;br /&gt;
&lt;br /&gt;
inductive Guard where&lt;br /&gt;
  | truthful&lt;br /&gt;
  | liar&lt;br /&gt;
  deriving DecidableEq, Repr&lt;br /&gt;
&lt;br /&gt;
def Guard.other : Guard → Guard&lt;br /&gt;
  | .truthful =&amp;gt; .liar&lt;br /&gt;
  | .liar     =&amp;gt; .truthful&lt;br /&gt;
&lt;br /&gt;
def Guard.says : Guard → Bool → Bool&lt;br /&gt;
  | .truthful, b =&amp;gt; b&lt;br /&gt;
  | .liar,     b =&amp;gt; !b&lt;br /&gt;
&lt;br /&gt;
def safeIs (s d : Door) : Bool := decide (s = d)&lt;br /&gt;
&lt;br /&gt;
def heard (g : Guard) (s : Door) : Bool :=&lt;br /&gt;
  g.says (g.other.says (safeIs s .left))&lt;br /&gt;
&lt;br /&gt;
def choose : Bool → Door&lt;br /&gt;
  | true  =&amp;gt; .right&lt;br /&gt;
  | false =&amp;gt; .left&lt;br /&gt;
&lt;br /&gt;
theorem choose_is_safe (g : Guard) (s : Door) : choose (heard g s) = s := by&lt;br /&gt;
  cases g &amp;amp;lt;;&amp;gt; cases s &amp;amp;lt;;&amp;gt; rfl&lt;br /&gt;
&lt;br /&gt;
#print axioms choose_is_safe&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The proof splits into the four worlds that cannot be told apart (which guard is asked, which door is safe) and checks each by computation. Lean 4.34.1 accepts it and prints &amp;lt;code&amp;gt;&#039;choose_is_safe&#039; does not depend on any axioms&amp;lt;/code&amp;gt;. The account then changes the riddle, replacing the liar with a guard who lies or tells the truth by a hidden coin; Lean refuses the old theorem and names the four worlds in which the strategy fails, and a sharper statement is then proved.&amp;lt;ref name=&amp;quot;lt&amp;quot; /&amp;gt; That cycle of a cheap, specific refusal followed by a revised hypothesis is what the framework wants from Lean.&lt;br /&gt;
&lt;br /&gt;
== Where it stands ==&lt;br /&gt;
&lt;br /&gt;
As of 14 October 2026, Phase 0 of seven, the development setup, is under way, and Phase 1 has begun beside it. No physics machinery has been ported yet, by design: Phase 0 ports one small part of version 1, the digest input encoding, as its test subject, and the port itself is the work of Phase 2.&amp;lt;ref name=&amp;quot;lt&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Phase 0 has pinned Lean 4.34.1; written a first Lean library holding the digest input encoding with three theorems, the Calculator &amp;lt;code&amp;gt;pcalc&amp;lt;/code&amp;gt;, and a test runner over a first corpus of six cases, all passing; and set up the proof gate, an audit of the axioms behind every definition and theorem, with seven checked and no failures.&amp;lt;ref name=&amp;quot;lt&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first test of Phase 1, T1, has run. Its outcome is that the Calculator is started as a command rather than inside a web request: one Calculator still serves both sides, and Custos calls it outside the web request rather than during it.&amp;lt;ref name=&amp;quot;lt&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Questions still open include whether to use core Lean or the Mathlib library, which brings real-number analysis at the cost of a large cache of compiled files, and how SHA-256 and Unicode normalisation are to be provided.&amp;lt;ref name=&amp;quot;lt&amp;quot; /&amp;gt; The steps by which a sponsored AI agent is certified are carried over from version 1 and are to be built in Phases 3 to 5; no agent has yet been admitted, and only the Declarer admits.&amp;lt;ref name=&amp;quot;lt&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== What Lean does not do here ==&lt;br /&gt;
&lt;br /&gt;
The account of the move states the limits as plainly as the gains.&amp;lt;ref name=&amp;quot;lt&amp;quot; /&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Lean proves the model, not the world.&#039;&#039;&#039; If the definitions misread the situation, the theorems are true of the wrong one. Version 1&#039;s rule still holds: internal consistency is not veracity, and comparison with the world happens outside the proof.&lt;br /&gt;
* &#039;&#039;&#039;A proof checker is not a reviewer.&#039;&#039;&#039; It confirms that a proof proves its statement, not that the statement was the right one to make; see [[Lean theorem prover/Explainers/Stating the right thing|Stating the right thing]].&lt;br /&gt;
* &#039;&#039;&#039;Real-number physics needs a library.&#039;&#039;&#039; Uncertainties and equations over the real numbers need Mathlib, which version 2 has not yet chosen; see [[Lean theorem prover/Applications/Physics in Lean|Physics in Lean]] and [[Lean theorem prover/Explainers/Lean and physics|Lean and physics]].&lt;br /&gt;
* &#039;&#039;&#039;It costs more to write than to read.&#039;&#039;&#039; The riddle&#039;s prose solution is one paragraph; its Lean file is 133 lines with comments. The cost falls as definitions are reused.&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
* [[Lean theorem prover/Chronology|Chronology]], the dated events of the edition.&lt;br /&gt;
* [[Principia Machina/Lean transition|The move to Lean]], the full account, with the riddle worked step by step.&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>PMA Publisher</name></author>
	</entry>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/Applications/Physics_in_Lean&amp;diff=6814</id>
		<title>Lean theorem prover/Applications/Physics in Lean</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Applications/Physics_in_Lean&amp;diff=6814"/>
		<updated>2026-10-15T19:35:44Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Physics in Lean}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
Physics is formalised in Lean less than mathematics, but the work has a library of its own, &#039;&#039;&#039;Physlib&#039;&#039;&#039;, and a growing list of results. This page describes that library and its origins, a few results formalised so far, and what a Lean proof can and cannot say about physics. The plain-language companion is [[Lean theorem prover/Explainers/Lean and physics|Lean and physics]].&lt;br /&gt;
&lt;br /&gt;
== Physlib ==&lt;br /&gt;
&lt;br /&gt;
Physlib is an open-source, community project to digitalise results from physics into Lean 4: definitions, theorems, lemmas and calculations, organised by area of physics and documented in physical terms. It is maintained under the Lean community and builds on Mathlib.&amp;lt;ref name=&amp;quot;readme&amp;quot;&amp;gt;The Physlib community, &amp;quot;Physlib: The Lean Physics Library&amp;quot;, project description, read 14 October 2026. https://github.com/leanprover-community/physlib&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It began in 2024 as &#039;&#039;&#039;HepLean&#039;&#039;&#039;, a project to digitalise high energy physics, described by Joseph Tooby-Smith. His paper on it proposed four uses: making existing results easier to find, creating new results with automated and AI methods, reviewing papers for mathematical correctness, and new ways of teaching. It demonstrated the approach on CKM matrices in flavour physics, on local anomaly cancellation, and on Higgs physics.&amp;lt;ref name=&amp;quot;heplean&amp;quot;&amp;gt;Joseph Tooby-Smith, &amp;quot;HepLean: Digitalising high energy physics&amp;quot;, &#039;&#039;Computer Physics Communications&#039;&#039; 308 (2025), 109457. doi:10.1016/j.cpc.2024.109457. arXiv:2405.08863&amp;lt;/ref&amp;gt; The project was later renamed &#039;&#039;&#039;PhysLean&#039;&#039;&#039;, and Physlib was formed by merging PhysLean with the quantum-information library Lean-QuantumInfo.&amp;lt;ref name=&amp;quot;readme&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;site&amp;quot;&amp;gt;Physlib, &amp;quot;About Physlib&amp;quot;, project website, read 14 October 2026. https://physlib.io/about&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As of October 2026 its main part is divided into areas that include classical mechanics, classical field theory, electromagnetism, relativity, quantum mechanics, quantum field theory, statistical mechanics, thermodynamics, condensed matter, cosmology, fluid dynamics, optics, particle physics and string theory, with a separate part for quantum information.&amp;lt;ref name=&amp;quot;readme&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The project states its own rules. It is for mainstream physics only; it is not tied to any one axiomatisation of physics, such as axiomatic quantum field theory, so that it can accommodate different starting points; and its content is reviewed for reuse and readability. Another part, PhyslibAlpha, has a lighter review so that larger contributions, including AI-generated ones, can come in more easily; even that review checks, among other things, that no axioms are added.&amp;lt;ref name=&amp;quot;readme&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Some results ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Index notation.&#039;&#039;&#039; Physicists write tensors with indices, as in &amp;lt;math&amp;gt;T^{\mu}{}_{\nu}&amp;lt;/math&amp;gt;, and contract them by repeating an index. Tooby-Smith gave what he describes as the first formally verified implementation of this notation in Lean 4, built on ideas from category theory, so that calculations can be written in the form physicists use and still be checked.&amp;lt;ref name=&amp;quot;index&amp;quot;&amp;gt;Joseph Tooby-Smith, &amp;quot;Formalization of physics index notation in Lean 4&amp;quot;, arXiv:2411.07667, November 2024. https://arxiv.org/abs/2411.07667&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The generalised quantum Stein&#039;s lemma.&#039;&#039;&#039; This result in quantum hypothesis testing gives relative entropy an operational meaning in quantum resource theories. An earlier proof was found to have a gap, and Hayashi and Yamasaki gave a corrected one in 2024. Alex Meiburg, Leonardo A. Lessa and Rodolfo R. Soldati formalised that proof in Lean, drawing on topology, analysis and operator algebra; the formalisation exposed minor imprecisions, which they corrected, and led them to a more precise definition of a quantum resource theory.&amp;lt;ref name=&amp;quot;stein&amp;quot;&amp;gt;Alex Meiburg, Leonardo A. Lessa and Rodolfo R. Soldati, &amp;quot;A Formalization of the Generalized Quantum Stein&#039;s Lemma in Lean&amp;quot;, arXiv:2510.08672, October 2025. https://arxiv.org/abs/2510.08672&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== What a proof about physics says ==&lt;br /&gt;
&lt;br /&gt;
A Lean theorem about physics is a theorem about a mathematical model. The small example below models an elastic collision of two bodies of equal mass on a line, in which the velocities are exchanged, and proves that momentum and kinetic energy are the same after the collision as before. It uses whole numbers because core Lean has no real numbers; those come from Mathlib.&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;
/-- Two bodies of equal mass on a line, by their velocities (whole numbers here). -/&lt;br /&gt;
structure Pair where&lt;br /&gt;
  v₁ : Int&lt;br /&gt;
  v₂ : Int&lt;br /&gt;
&lt;br /&gt;
/-- The model of an elastic collision of equal masses: the velocities are exchanged. -/&lt;br /&gt;
def collide (p : Pair) : Pair := ⟨p.v₂, p.v₁⟩&lt;br /&gt;
&lt;br /&gt;
def momentum (m : Int) (p : Pair) : Int := m * p.v₁ + m * p.v₂&lt;br /&gt;
&lt;br /&gt;
/-- Twice the kinetic energy, to stay within whole numbers. -/&lt;br /&gt;
def twiceEnergy (m : Int) (p : Pair) : Int := m * (p.v₁ * p.v₁) + m * (p.v₂ * p.v₂)&lt;br /&gt;
&lt;br /&gt;
theorem momentum_conserved (m : Int) (p : Pair) :&lt;br /&gt;
    momentum m (collide p) = momentum m p := by&lt;br /&gt;
  simp only [momentum, collide]&lt;br /&gt;
  exact Int.add_comm _ _&lt;br /&gt;
&lt;br /&gt;
theorem energy_conserved (m : Int) (p : Pair) :&lt;br /&gt;
    twiceEnergy m (collide p) = twiceEnergy m p := by&lt;br /&gt;
  simp only [twiceEnergy, collide]&lt;br /&gt;
  exact Int.add_comm _ _&lt;br /&gt;
&lt;br /&gt;
#print axioms momentum_conserved&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean 4.34.1 accepts both theorems and prints &amp;lt;code&amp;gt;&#039;momentum_conserved&#039; depends on axioms: [propext]&amp;lt;/code&amp;gt;. What has been proved is that the model conserves both quantities. Whether real bodies exchange their velocities when they collide is a question for experiment, and Lean does not touch it. This wiki&#039;s [[Principia Machina/Lean transition|account of the move to Lean]] states the same rule for its own framework: Lean proves the model, not the world, and internal consistency is not veracity.&amp;lt;ref name=&amp;quot;lt&amp;quot;&amp;gt;&amp;quot;Principia Machina: the move to Lean&amp;quot;, the page [[Principia Machina/Lean transition]] on this wiki, status as of 14 October 2026.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== What is within reach ==&lt;br /&gt;
&lt;br /&gt;
Within reach are the parts of physics that are already mathematics: definitions, symmetries, conservation laws, exact calculations, and theorems about models whose mathematics Mathlib supports. Equations and uncertainties over the real numbers need Mathlib, which brings real analysis with it.&amp;lt;ref name=&amp;quot;lt&amp;quot; /&amp;gt; Parts of physics whose mathematics is not settled are harder. A result that physicists derive by methods with no rigorous foundation cannot be proved in Lean until a foundation is chosen. Physlib, for its part, does not tie itself to any one axiomatisation.&amp;lt;ref name=&amp;quot;readme&amp;quot; /&amp;gt; In every case the hardest step is the one Lean cannot check: whether the Lean definitions say what the physicist means. [[Lean theorem prover/Explainers/Stating the right thing|Stating the right thing]] treats that problem in general.&lt;br /&gt;
&lt;br /&gt;
This wiki&#039;s own framework for testing physical hypotheses is moving to Lean, with the choice of Mathlib still open;&amp;lt;ref name=&amp;quot;lt&amp;quot; /&amp;gt; see [[Lean theorem prover/Applications/Principia Machina|Principia Machina]]. Its version 1 surveyed Lean, Mathlib and Physlib among physics tools on [[The Principia Machina/Tools/Physlib|a page of its own]].&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
* [[Lean theorem prover/Applications/Principia Machina|Principia Machina]], this wiki&#039;s framework and its move to Lean.&lt;br /&gt;
* [[Lean theorem prover/Explainers/Lean and physics|Lean and physics]], the plain-language companion.&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>PMA Publisher</name></author>
	</entry>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/Applications/Machine_learning_and_theorem_proving&amp;diff=6813</id>
		<title>Lean theorem prover/Applications/Machine learning and theorem proving</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Applications/Machine_learning_and_theorem_proving&amp;diff=6813"/>
		<updated>2026-10-15T19:35:43Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Machine learning and theorem proving}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
Machine-learning systems now write Lean proofs, from competition problems to large formalisations of research mathematics. Lean&#039;s role in this work is that of the checker: a proof that the Lean kernel accepts is correct whoever, or whatever, wrote it. This page describes the benchmarks the field uses, the main results so far, why the check matters, and what it leaves open, chiefly whether the statement that was proved is the statement that was meant.&lt;br /&gt;
&lt;br /&gt;
== Why a checker matters ==&lt;br /&gt;
&lt;br /&gt;
A language model can write text that looks like a proof and is not. Read by a person, such output costs time to check and may still mislead. Written in Lean, the same output is either accepted by the Lean kernel or refused, and an accepted proof is correct relative to Lean&#039;s axioms and the stated theorem, whatever produced it. Microsoft&#039;s SymCrypt team states the arrangement plainly: AI agents help draft its proofs, Lean&#039;s small trusted kernel checks every one of them, and an agent&#039;s proof counts only if Lean accepts it.&amp;lt;ref name=&amp;quot;symcrypt&amp;quot;&amp;gt;Son Ho, Cédric Fournet, Antoine Delignat-Lavaud, Samuel Lee, Jason Fisher and Jessica Krynitsky, &amp;quot;Verifying Rust cryptography in SymCrypt, from standards to code&amp;quot;, Microsoft Research Blog, 13 July 2026. https://www.microsoft.com/en-us/research/blog/verifying-rust-cryptography-in-symcrypt-from-standards-to-code/&amp;lt;/ref&amp;gt; Kevin Buzzard has made the same point: when machine-written mathematics comes with Lean code, that code at least guarantees that the argument is correct, so a reader can be more confident that the time spent reading it is not wasted.&amp;lt;ref name=&amp;quot;annals&amp;quot;&amp;gt;Kevin Buzzard, &amp;quot;The Annals Challenge&amp;quot;, &#039;&#039;Xena&#039;&#039; (blog), 13 August 2026. https://xenaproject.wordpress.com/2026/08/13/the-annals-challenge/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The check has a second use. Because Lean decides automatically whether a proof is correct, it can grade a learning system&#039;s attempts without a person, and a system can learn from its own verified successes; DeepMind&#039;s AlphaProof, described below, feeds the proofs it finds back into its training in this way.&amp;lt;ref name=&amp;quot;dmblog&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Benchmarks ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;miniF2F&#039;&#039;&#039;, published in 2021 by Kunhao Zheng, Jesse Michael Han and Stanislas Polu, is a set of 488 formal problem statements drawn from the AIME and AMC competitions, the International Mathematical Olympiad, and high-school and undergraduate courses. It was written for Metamath and Lean, with partial coverage of Isabelle and HOL Light, so that systems built on different provers could be compared.&amp;lt;ref name=&amp;quot;minif2f&amp;quot;&amp;gt;Kunhao Zheng, Jesse Michael Han and Stanislas Polu, &amp;quot;MiniF2F: a cross-system benchmark for formal Olympiad-level mathematics&amp;quot;, International Conference on Learning Representations (ICLR), 2022. arXiv:2109.00110&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;LeanDojo&#039;&#039;&#039;, by Kaiyu Yang and colleagues, is an open-source toolkit that extracts data from Lean and lets a program interact with Lean as a user would, step by step. Its benchmark contains 98,734 theorems and proofs from Lean&#039;s mathematical library, split so as to test whether a system can use library lemmas it never saw in training. With it the authors trained ReProver, a prover that retrieves relevant lemmas from the library before proposing a step.&amp;lt;ref name=&amp;quot;leandojo&amp;quot;&amp;gt;Kaiyu Yang, Aidan M. Swope, Alex Gu, Rahul Chalamala, Peiyang Song, Shixing Yu, Saad Godil, Ryan Prenger and Anima Anandkumar, &amp;quot;LeanDojo: Theorem Proving with Retrieval-Augmented Language Models&amp;quot;, NeurIPS 2023 Datasets and Benchmarks Track. arXiv:2306.15626&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Competition mathematics ==&lt;br /&gt;
&lt;br /&gt;
At the International Mathematical Olympiad of 2024, Google DeepMind&#039;s AlphaProof proved two algebra problems and one number theory problem, including the hardest problem of the contest, in Lean; a separate system, AlphaGeometry 2, solved the geometry problem. Together they scored 28 of 42 points, the standard of a silver medal. The problems were translated into formal language by hand, and some solutions took up to three days rather than the nine hours allowed to contestants.&amp;lt;ref name=&amp;quot;dmblog&amp;quot;&amp;gt;Google DeepMind, &amp;quot;AI achieves silver-medal standard solving International Mathematical Olympiad problems&amp;quot;, 25 July 2024. https://deepmind.google/discover/blog/ai-solves-imo-problems-at-silver-medal-level/&amp;lt;/ref&amp;gt; The method was published in &#039;&#039;Nature&#039;&#039; in November 2025: AlphaProof learns by reinforcement learning, in the manner of AlphaZero, from millions of problems that were translated into Lean automatically, and for the hardest problems it generates and learns from variants of the problem while solving it.&amp;lt;ref name=&amp;quot;nature&amp;quot;&amp;gt;Thomas Hubert, Rishi Mehta, Laurent Sartran, et al., &amp;quot;Olympiad-level formal mathematical reasoning with reinforcement learning&amp;quot;, &#039;&#039;Nature&#039;&#039; 651, pp. 607–613, published online 12 November 2025. doi:10.1038/s41586-025-09833-y&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At the 2025 Olympiad two companies announced results in Lean: ByteDance&#039;s Seed Prover, at silver-medal level or at gold with additional attempts, and Harmonic&#039;s system, at gold-medal level, both by their own accounts. Buzzard pointed out that the Olympiad set no rules for machine entrants, that the companies marked their own work, and that neither company said how the answers to the problems that ask for a value were given to its system.&amp;lt;ref name=&amp;quot;imo2025&amp;quot;&amp;gt;Kevin Buzzard, &amp;quot;AI at IMO 2025: a round-up&amp;quot;, &#039;&#039;Xena&#039;&#039; (blog), 3 August 2025. https://xenaproject.wordpress.com/2025/08/03/ai-at-imo-2025-a-round-up/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Research mathematics ==&lt;br /&gt;
&lt;br /&gt;
By 2026 machine systems were completing large formalisations of research mathematics. The formal proof of sphere packing in dimension 8 was finished in February 2026, its final stages carried out by Math, Inc.&#039;s autoformalisation model Gauss.&amp;lt;ref name=&amp;quot;packing&amp;quot;&amp;gt;Sidharth Hariharan, Christopher Birkbeck, Seewoo Lee, Ho Kiu Gareth Ma, Bhavik Mehta, Auguste Poiroux and Maryna Viazovska, &amp;quot;Progress in Formalizing Sphere Packing in Dimension 8&amp;quot;, arXiv:2604.23468, April 2026. https://arxiv.org/abs/2604.23468&amp;lt;/ref&amp;gt; In September 2026 Anthropic announced a complete formal proof of Fermat&#039;s Last Theorem, about 13 million lines of Lean written in some 11 days by agents of its model Claude, with mathematical input from people limited, by the company&#039;s account, to occasional high-level instructions.&amp;lt;ref name=&amp;quot;anthropic&amp;quot;&amp;gt;Anthropic, &amp;quot;Formalizing Fermat&#039;s Last Theorem&amp;quot;, 4 September 2026. https://www.anthropic.com/research/formalizing-fermats-last-theorem&amp;lt;/ref&amp;gt; Both are described on [[Lean theorem prover/Applications/Research mathematics|Research mathematics]], and the second in full, with Buzzard&#039;s assessment of it, on [[Lean theorem prover/Applications/The Fermat&#039;s Last Theorem project|The Fermat&#039;s Last Theorem project]]. Not every project found language models useful: in the [[Lean theorem prover/Applications/The equational theories project|equational theories project]], automated theorem provers did most of the work, and on the hardest cases the participants found that language models offered nothing beyond what they could propose themselves.&amp;lt;ref name=&amp;quot;etp&amp;quot;&amp;gt;Matthew Bolan, Joachim Breitner, Jose Brox, et al. (34 authors, including Terence Tao), &amp;quot;The Equational Theories Project: Advancing Collaborative Mathematical Research at Scale&amp;quot;, arXiv:2512.07087, December 2025, section 11. https://arxiv.org/abs/2512.07087&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== What the check does not cover ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;What the proof rests on.&#039;&#039;&#039; A proof can be accepted because it assumes what it should prove. The command &amp;lt;code&amp;gt;#print axioms&amp;lt;/code&amp;gt; lists every axiom a theorem depends on, so an assumption slipped in by the author shows up:&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;
/-- An assumption slipped in by whoever wrote the proof. -/&lt;br /&gt;
axiom shortcut : ∀ n : Nat, n * 0 = 1&lt;br /&gt;
&lt;br /&gt;
theorem claimed (n : Nat) : n * 0 = 1 := shortcut n&lt;br /&gt;
&lt;br /&gt;
#print axioms claimed&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean 4.34.1 accepts this and prints &amp;lt;code&amp;gt;&#039;claimed&#039; depends on axioms: [shortcut]&amp;lt;/code&amp;gt;. A proof left unfinished with &amp;lt;code&amp;gt;sorry&amp;lt;/code&amp;gt; is caught the same way: Lean warns, and the list shows &amp;lt;code&amp;gt;sorryAx&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Whether the statement is the one meant.&#039;&#039;&#039; This is the harder limit. Lean checks that the proof proves the theorem as written; it cannot check that the theorem as written says what the problem meant. A mistyped hypothesis can make a theorem true for no interesting reason:&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;
/-- Intended: &amp;quot;a number below 10 is at most 9&amp;quot;. The hypothesis was mistyped as `x &amp;amp;lt; 0`,&lt;br /&gt;
which no natural number satisfies, so the theorem says nothing at all. -/&lt;br /&gt;
theorem vacuous (x : Nat) (h : x &amp;amp;lt; 0) : x ≤ 9 := by&lt;br /&gt;
  omega&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean accepts it without comment. Translating a problem into Lean is itself a source of such errors, and translation, Buzzard notes, is not uniquely determined by the problem. Olympiad problems that ask for a value raise a further difficulty: a system must not be allowed to answer &amp;quot;the value is whatever satisfies the condition&amp;quot;, so the answer is usually supplied first and then proved, and that formal question has to be checked against the original.&amp;lt;ref name=&amp;quot;imo2025&amp;quot; /&amp;gt; In May 2026 Buzzard judged that automatic formalisation could not yet reliably, on its own, formalise definitions correctly or state theorems idiomatically.&amp;lt;ref name=&amp;quot;workshop&amp;quot;&amp;gt;Kevin Buzzard, &amp;quot;Formalizing Fermat workshop&amp;quot;, &#039;&#039;Xena&#039;&#039; (blog), 15 May 2026. https://xenaproject.wordpress.com/2026/05/15/formalizing-fermat-workshop/&amp;lt;/ref&amp;gt; One remedy is to compare the proved statement with one written independently. The machine-written proof of Fermat&#039;s Last Theorem was checked in both of the ways described here: its announcement reports that it uses only Lean&#039;s three standard axioms, and that a comparison tool confirmed that the statement proved matches the one already in Mathlib.&amp;lt;ref name=&amp;quot;anthropic&amp;quot; /&amp;gt; Buzzard ran the comparison again himself, and also had an AI agent list everything in the code that was neither a definition nor a proof, then inspected the roughly 100 lines it found, an approach he called not perfect.&amp;lt;ref name=&amp;quot;beaten&amp;quot;&amp;gt;Kevin Buzzard, &amp;quot;FLT: Anthropic has beaten me to it&amp;quot;, &#039;&#039;Xena&#039;&#039; (blog), 4 September 2026. https://xenaproject.wordpress.com/2026/09/04/flt-anthropic-has-beaten-me-to-it/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The checker itself.&#039;&#039;&#039; The guarantee is only as good as the Lean kernel and the hardware and software it runs on; [[Lean theorem prover/Explainers/What has to be trusted|What has to be trusted]] sets out that list, and [[Lean theorem prover/Explainers/Stating the right thing|Stating the right thing]] treats the statement problem in general.&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
* [[Lean theorem prover/Applications/Physics in Lean|Physics in Lean]].&lt;br /&gt;
* [[Lean theorem prover/Explainers/Checking instead of convincing|Checking instead of convincing]].&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>PMA Publisher</name></author>
	</entry>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/Applications/Teaching_with_Lean&amp;diff=6812</id>
		<title>Lean theorem prover/Applications/Teaching with Lean</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Applications/Teaching_with_Lean&amp;diff=6812"/>
		<updated>2026-10-15T19:35:41Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Teaching with Lean}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
Lean is used to teach mathematical proof, the logic behind it, and programming. This page describes the main free materials, from a puzzle game for beginners to textbooks for undergraduates and researchers, and some university courses built on them. It also says what a proof checker adds to teaching and what it does not.&lt;br /&gt;
&lt;br /&gt;
== What a proof checker gives a learner ==&lt;br /&gt;
&lt;br /&gt;
A student writing a proof on paper waits for a teacher to mark it. A student writing a proof in Lean is answered at once: each step is accepted, or refused with the goal that is still open (see [[Lean theorem prover/Explainers/Holes and goals|Holes and goals]]). The checker never tires, and it does not accept a step because it looks plausible. It cannot tell a student whether a proof is well written or why it works; those remain the teacher&#039;s work.&lt;br /&gt;
&lt;br /&gt;
== The Natural Number Game ==&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Natural Number Game&#039;&#039;&#039; is a browser game that teaches the first steps of proof in Lean. It starts from a definition of the natural numbers made from zero and a successor operation, and asks the player to prove facts about them in order: first that 2 + 2 = 4, then that &amp;lt;math&amp;gt;x + y = y + x&amp;lt;/math&amp;gt;, and so on through a sequence of &amp;quot;worlds&amp;quot;, each made of levels that are theorems.&amp;lt;ref name=&amp;quot;nngsrc&amp;quot;&amp;gt;Kevin Buzzard, Jon Eugster et al., &#039;&#039;Natural Number Game&#039;&#039;, Lean 4 version, game text and credits. https://github.com/leanprover-community/NNG4&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game was written for Lean 3 by Kevin Buzzard and Mohammad Pedramfar. Its Lean 4 version is credited to Buzzard and Jon Eugster, on a game engine by Alexander Bentkamp, Eugster and Patrick Massot.&amp;lt;ref name=&amp;quot;nngsrc&amp;quot; /&amp;gt; It runs on the Lean Game Server, which also hosts games maintained by other authors, among them a set theory game (Dan Velleman), a real analysis game (Alex Kontorovich) and &#039;&#039;Reintroduction to Proofs&#039;&#039; (Emily Riehl).&amp;lt;ref name=&amp;quot;gameserver&amp;quot;&amp;gt;Alexander Bentkamp, Jon Eugster et al., &amp;quot;Lean 4 Game&amp;quot;, the source of the Lean Game Server: project description and list of hosted games, read 14 October 2026. https://github.com/leanprover-community/lean4game&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A small piece in the game&#039;s style shows the idea. The natural numbers are defined from scratch, addition is defined by recursion on its second argument, and adding zero on the left then needs a proof by induction:&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;
inductive MyNat where&lt;br /&gt;
  | zero : MyNat&lt;br /&gt;
  | succ : MyNat → MyNat&lt;br /&gt;
&lt;br /&gt;
namespace MyNat&lt;br /&gt;
&lt;br /&gt;
def add : MyNat → MyNat → MyNat&lt;br /&gt;
  | a, zero   =&amp;gt; a&lt;br /&gt;
  | a, succ b =&amp;gt; succ (add a b)&lt;br /&gt;
&lt;br /&gt;
/-- Adding zero on the right is the definition; on the left it needs induction. -/&lt;br /&gt;
theorem zero_add (n : MyNat) : add zero n = n := by&lt;br /&gt;
  induction n with&lt;br /&gt;
  | zero =&amp;gt; rfl&lt;br /&gt;
  | succ k ih =&amp;gt; rw [add, ih]&lt;br /&gt;
&lt;br /&gt;
end MyNat&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean 4.34.1 accepts it. A beginner who offers &amp;lt;code&amp;gt;rfl&amp;lt;/code&amp;gt; as the whole proof is refused: Lean reports that the left-hand side, &amp;lt;code&amp;gt;zero.add n&amp;lt;/code&amp;gt;, is not definitionally equal to the right-hand side, &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;. The definition of addition says nothing directly about &amp;lt;code&amp;gt;add zero n&amp;lt;/code&amp;gt; while &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt; is unknown. That refusal is the point at which induction is learned. The explainer [[Lean theorem prover/Explainers/Induction, as the machine sees it|Induction, as the machine sees it]] says more.&lt;br /&gt;
&lt;br /&gt;
== Textbooks ==&lt;br /&gt;
&lt;br /&gt;
The standard free books are published by the Lean community and the Lean developers.&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Theorem Proving in Lean 4&#039;&#039;&#039;&#039;&#039;, by Jeremy Avigad, Leonardo de Moura, Soonho Kong and Sebastian Ullrich, with contributions from the community, teaches Lean&#039;s logic itself: dependent type theory, propositions and proofs, tactics, inductive types, structures, type classes and the axioms.&amp;lt;ref name=&amp;quot;tpil&amp;quot;&amp;gt;Jeremy Avigad, Leonardo de Moura, Soonho Kong and Sebastian Ullrich, &#039;&#039;Theorem Proving in Lean 4&#039;&#039;, online book, read 14 October 2026. https://lean-lang.org/theorem_proving_in_lean4/&amp;lt;/ref&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Mathematics in Lean&#039;&#039;&#039;&#039;&#039;, by Avigad and Patrick Massot, teaches how to do mathematics with Mathlib, in chapters running from basic logic and number theory through structures, algebra and linear algebra to topology, differential calculus, and integration and measure theory.&amp;lt;ref name=&amp;quot;mil&amp;quot;&amp;gt;Jeremy Avigad and Patrick Massot, &#039;&#039;Mathematics in Lean&#039;&#039;, online book, read 14 October 2026. https://leanprover-community.github.io/mathematics_in_lean/&amp;lt;/ref&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Functional Programming in Lean&#039;&#039;&#039;&#039;&#039;, by David Thrane Christiansen, is a free book on Lean as a programming language, from its basics through type classes, monads and dependent types to proofs about programs and performance.&amp;lt;ref name=&amp;quot;fpil&amp;quot;&amp;gt;David Thrane Christiansen, &#039;&#039;Functional Programming in Lean&#039;&#039;, online book, read 14 October 2026. https://lean-lang.org/functional_programming_in_lean/&amp;lt;/ref&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Logic and Proof&#039;&#039;&#039;&#039;&#039;, written by Avigad, Lewis and van Doorn and adapted to Lean 4 by Hua, is an introduction to symbolic logic and mathematical proof. Its stated goals are that a reader learn to write clear proofs, to model deductive proof formally, and to use an interactive proof assistant.&amp;lt;ref name=&amp;quot;lap&amp;quot;&amp;gt;J. Avigad, J. Hua, R. Y. Lewis and F. van Doorn, &#039;&#039;Logic and Proof&#039;&#039;, online textbook, Lean 4 edition, read 14 October 2026. https://leanprover-community.github.io/logic_and_proof/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== University courses ==&lt;br /&gt;
&lt;br /&gt;
Two published course texts show Lean in use at different levels.&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;The Mechanics of Proof&#039;&#039;&#039;&#039;&#039;, by Heather Macbeth, was written for the course Math 2001 at Fordham University and is aimed at the early university level. It describes itself as a book about writing careful, rigorous proofs, and it is paired with Lean code throughout, with an appendix on moving on to mainstream Lean.&amp;lt;ref name=&amp;quot;mop&amp;quot;&amp;gt;Heather Macbeth, &#039;&#039;The Mechanics of Proof&#039;&#039;, online book for Math 2001, Fordham University, 2022–2024. https://hrmacbeth.github.io/math2001/&amp;lt;/ref&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Formalising Mathematics&#039;&#039;&#039;&#039;&#039;, by Kevin Buzzard, is the handbook for his course of that name at Imperial College London, aimed at students with some mathematical background, such as those in the final year of a mathematics degree. It teaches how to formalise mathematics in Lean using Mathlib, and includes a catalogue of basic tactics.&amp;lt;ref name=&amp;quot;fm&amp;quot;&amp;gt;Kevin Buzzard, &#039;&#039;Formalising Mathematics&#039;&#039;, course handbook, Imperial College London, 2024 edition. https://www.ma.imperial.ac.uk/~buzzard/xena/formalising-mathematics-2024/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Courses are offered elsewhere too; this page lists only those whose published materials could be checked.&lt;br /&gt;
&lt;br /&gt;
== How quickly mathematicians learn ==&lt;br /&gt;
&lt;br /&gt;
The authors of the formalisation of perfectoid spaces reported that mathematicians without training in computer science can become proficient with a proof assistant within a short time.&amp;lt;ref name=&amp;quot;perfectoid&amp;quot;&amp;gt;Kevin Buzzard, Johan Commelin and Patrick Massot, &amp;quot;Formalising perfectoid spaces&amp;quot;, in &#039;&#039;CPP 2020: Proceedings of the 9th ACM SIGPLAN International Conference on Certified Programs and Proofs&#039;&#039;, 2020, pp. 299–312. doi:10.1145/3372885.3373830. arXiv:1910.12320&amp;lt;/ref&amp;gt; Buzzard hoped that his Fermat project would be a good source of smaller Lean projects for doctoral students in number theory who want to learn the language.&amp;lt;ref name=&amp;quot;general&amp;quot;&amp;gt;Kevin Buzzard, &amp;quot;A Lean formalisation of Fermat&#039;s Last Theorem&amp;quot; (the project&#039;s general information), written December 2023. https://github.com/ImperialCollegeLondon/FLT/blob/main/GENERAL.md&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== What it does not teach ==&lt;br /&gt;
&lt;br /&gt;
Lean checks that a proof is correct. It does not show which proof is clearest, and a proof written for Lean can be longer and harder to read than one written for people. Course texts such as Macbeth&#039;s present themselves as books about writing careful, rigorous proofs, with Lean as the companion that checks them.&amp;lt;ref name=&amp;quot;mop&amp;quot; /&amp;gt; The gap between a proof that Lean accepts and a proof a reader understands is discussed in [[Lean theorem prover/Explainers/Checking instead of convincing|Checking instead of convincing]].&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
* [[Lean theorem prover/Applications/Machine learning and theorem proving|Machine learning and theorem proving]].&lt;br /&gt;
* [[Lean theorem prover/Explainers/What a proof assistant does|What a proof assistant does]], for a reader starting from the beginning.&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>PMA Publisher</name></author>
	</entry>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/Applications/Software_verification&amp;diff=6811</id>
		<title>Lean theorem prover/Applications/Software verification</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Applications/Software_verification&amp;diff=6811"/>
		<updated>2026-10-15T19:35:40Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Software verification}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
Because Lean is a programming language as well as a proof checker, the same file can hold a program, a precise statement of what the program should do, and a proof that it does it. This page describes three industrial uses of Lean for software: Amazon&#039;s Cedar policy language, Amazon&#039;s SampCert library for differential privacy, and Microsoft&#039;s verified cryptography in SymCrypt. For each it says what &amp;quot;verified&amp;quot; covers and what it does not, since the word means something different in each case.&lt;br /&gt;
&lt;br /&gt;
== Specify, then prove ==&lt;br /&gt;
&lt;br /&gt;
To verify a program is to prove that it meets a &#039;&#039;&#039;specification&#039;&#039;&#039;, a precise statement of its intended behaviour. In Lean both the program and the specification are written as Lean definitions, and the claim that one meets the other is a theorem. The proof says nothing about any other program, and nothing about properties the specification leaves out. Two questions therefore come with every claim of verified software: which code was the proof about, and what does the specification say?&lt;br /&gt;
&lt;br /&gt;
== Cedar ==&lt;br /&gt;
&lt;br /&gt;
Cedar is a language for writing authorisation policies, developed at Amazon Web Services: rules that say which users may take which actions on which resources.&amp;lt;ref name=&amp;quot;oopsla&amp;quot;&amp;gt;Joseph W. Cutler, Craig Disselkoen, Aaron Eline, et al., &amp;quot;Cedar: A New Language for Expressive, Fast, Safe, and Analyzable Authorization&amp;quot;, &#039;&#039;Proceedings of the ACM on Programming Languages&#039;&#039; 8 (OOPSLA1), 2024, pp. 670–697. doi:10.1145/3649835&amp;lt;/ref&amp;gt; Its developers wrote executable models of Cedar&#039;s evaluator, authoriser and validator in Lean, and these models serve as Cedar&#039;s specification. They proved properties of the models, among them that a satisfied &amp;lt;code&amp;gt;forbid&amp;lt;/code&amp;gt; policy always leads to a denial, that a request is denied when no &amp;lt;code&amp;gt;permit&amp;lt;/code&amp;gt; policy is satisfied, that the order of the policies does not matter, that a policy accepted by the validator never produces a type error, and that every function terminates.&amp;lt;ref name=&amp;quot;vgd&amp;quot;&amp;gt;Craig Disselkoen, Aaron Eline, Shaobo He, et al., &amp;quot;How We Built Cedar: A Verification-Guided Approach&amp;quot;, in &#039;&#039;Companion Proceedings of the 32nd ACM International Conference on the Foundations of Software Engineering (FSE Companion &#039;24)&#039;&#039;, 2024. doi:10.1145/3663529.3663854. arXiv:2407.01688&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The shape of such a proof can be shown in a few lines. The block below is a toy authoriser in the same style, not Cedar&#039;s model: a request is allowed when some permit policy applies and no forbid policy does, and the theorem proves the first of the properties above for every list of policies and every request.&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;
inductive Effect where&lt;br /&gt;
  | permit&lt;br /&gt;
  | forbid&lt;br /&gt;
  deriving DecidableEq&lt;br /&gt;
&lt;br /&gt;
/-- A policy: its effect, and the requests it applies to. -/&lt;br /&gt;
structure Policy (Req : Type) where&lt;br /&gt;
  effect  : Effect&lt;br /&gt;
  applies : Req → Bool&lt;br /&gt;
&lt;br /&gt;
inductive Decision where&lt;br /&gt;
  | allow&lt;br /&gt;
  | deny&lt;br /&gt;
  deriving DecidableEq, Repr&lt;br /&gt;
&lt;br /&gt;
def satisfied {Req : Type} (e : Effect) (ps : List (Policy Req)) (r : Req) :&lt;br /&gt;
    List (Policy Req) :=&lt;br /&gt;
  ps.filter (fun p =&amp;gt; p.effect == e &amp;amp;amp;&amp;amp;amp; p.applies r)&lt;br /&gt;
&lt;br /&gt;
/-- Allow when some permit policy applies and no forbid policy does. -/&lt;br /&gt;
def isAuthorized {Req : Type} (ps : List (Policy Req)) (r : Req) : Decision :=&lt;br /&gt;
  if (satisfied .forbid ps r).isEmpty &amp;amp;amp;&amp;amp;amp; !(satisfied .permit ps r).isEmpty&lt;br /&gt;
  then .allow else .deny&lt;br /&gt;
&lt;br /&gt;
/-- If any forbid policy applies, the request is denied. -/&lt;br /&gt;
theorem forbid_trumps_permit {Req : Type} (ps : List (Policy Req)) (r : Req)&lt;br /&gt;
    (p : Policy Req) (hp : p ∈ ps) (hf : p.effect = .forbid) (ha : p.applies r = true) :&lt;br /&gt;
    isAuthorized ps r = .deny := by&lt;br /&gt;
  have hmem : p ∈ satisfied .forbid ps r := by&lt;br /&gt;
    simp [satisfied, hp, hf, ha]&lt;br /&gt;
  have hne : (satisfied .forbid ps r).isEmpty = false := by&lt;br /&gt;
    cases h : satisfied .forbid ps r with&lt;br /&gt;
    | nil =&amp;gt; simp [h] at hmem&lt;br /&gt;
    | cons _ _ =&amp;gt; rfl&lt;br /&gt;
  simp [isAuthorized, hne]&lt;br /&gt;
&lt;br /&gt;
#print axioms forbid_trumps_permit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean 4.34.1 accepts the proof and prints &amp;lt;code&amp;gt;&#039;forbid_trumps_permit&#039; depends on axioms: [propext]&amp;lt;/code&amp;gt;, one of Lean&#039;s three standard axioms, which the simplifier used.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;What is verified, and what is not.&#039;&#039;&#039; The proofs are about the Lean models. The code that runs in production is written separately, in Rust, for speed and for useful error messages among other reasons, and it is not proved correct. It is checked against the Lean model by &#039;&#039;&#039;differential random testing&#039;&#039;&#039;: large numbers of generated inputs are given to both, and any difference in output is a bug in one of them. Parts of the Rust code that the model does not cover, such as the parser, are tested for properties instead.&amp;lt;ref name=&amp;quot;vgd&amp;quot; /&amp;gt; The team reported running millions of such tests every night, and releasing a new version of Cedar only when the models, the proofs and the tests are all up to date.&amp;lt;ref name=&amp;quot;awsblog&amp;quot;&amp;gt;Kesha Hietala and Emina Torlak, &amp;quot;Lean Into Verified Software Development&amp;quot;, AWS Open Source Blog, 8 April 2024. https://aws.amazon.com/blogs/opensource/lean-into-verified-software-development/&amp;lt;/ref&amp;gt; The proofs found four bugs in the validator; the testing found 21 more in various parts of Cedar.&amp;lt;ref name=&amp;quot;vgd&amp;quot; /&amp;gt; The Lean models, 1,673 lines in all, are about an order of magnitude smaller than their Rust counterparts; the proofs about them run to 5,714 lines.&amp;lt;ref name=&amp;quot;vgd&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== SampCert ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Differential privacy&#039;&#039;&#039; is a mathematical guarantee that the published result of a computation reveals little about any one person in the data. It is usually achieved by adding carefully calibrated random noise. SampCert is a Lean library, with over 12,000 lines of proof that make heavy use of Mathlib, that formalises the theory of differential privacy in several of its variants, gives a framework for building and composing private mechanisms, and contains verified algorithms for sampling from the discrete Laplace and Gaussian distributions. Its authors write that it is used in the differential privacy offerings of Amazon Web Services.&amp;lt;ref name=&amp;quot;sampcert&amp;quot;&amp;gt;Markus de Medeiros, Muhammad Naveed, Tancrède Lepoint, Temesghen Kahsai, Tristan Ravitch, Stefan Zetzsche, Anjali Joshi, Joseph Tassarotti, Aws Albarghouthi and Jean-Baptiste Tristan, &amp;quot;Verified Foundations for Differential Privacy&amp;quot;, &#039;&#039;Proceedings of the ACM on Programming Languages&#039;&#039; 9 (PLDI), 2025, pp. 1094–1118. doi:10.1145/3729294. arXiv:2412.01671&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;What is verified, and what is not.&#039;&#039;&#039; The samplers are written in a small probabilistic language inside Lean, and the proofs show that they produce the intended distributions. Running them needs code outside the proofs. One route compiles them through Lean&#039;s interface to C++, which adds five functions, 57 lines of C++, to what must be trusted; randomness comes from reading bytes from the operating system&#039;s random source, and the conversion of those bytes into uniform samples is itself written and verified in Lean. The authors point out that such external functions cannot make Lean&#039;s logic unsound, but that Lean gives no formal guarantee about the behaviour of the compiled program. The route used for deployment translates the samplers through the Dafny language into Python.&amp;lt;ref name=&amp;quot;sampcert&amp;quot; /&amp;gt; The proofs therefore cover the algorithms; the translation, the C++ functions and the random source are trusted.&lt;br /&gt;
&lt;br /&gt;
== SymCrypt ==&lt;br /&gt;
&lt;br /&gt;
SymCrypt is Microsoft&#039;s cryptographic library. Its team now writes new implementations in Rust and verifies them in Lean with &#039;&#039;&#039;Aeneas&#039;&#039;&#039;, a tool that translates Rust code into a pure functional model in Lean.&amp;lt;ref name=&amp;quot;symcrypt&amp;quot;&amp;gt;Son Ho, Cédric Fournet, Antoine Delignat-Lavaud, Samuel Lee, Jason Fisher and Jessica Krynitsky, &amp;quot;Verifying Rust cryptography in SymCrypt, from standards to code&amp;quot;, Microsoft Research Blog, 13 July 2026. https://www.microsoft.com/en-us/research/blog/verifying-rust-cryptography-in-symcrypt-from-standards-to-code/&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;aeneas&amp;quot;&amp;gt;Son Ho and Jonathan Protzenko, &amp;quot;Aeneas: Rust verification by functional translation&amp;quot;, &#039;&#039;Proceedings of the ACM on Programming Languages&#039;&#039; 6 (ICFP), 2022, pp. 711–741. doi:10.1145/3547647&amp;lt;/ref&amp;gt; The first verified components are the key-encapsulation scheme ML-KEM and SHA-3, the standard family of functions that compute digests. A verified function is proved to refine a Lean specification written to follow the public standard: on inputs that meet stated preconditions, it returns what the specification returns. AI agents help draft specifications and proofs; a proof counts only when Lean accepts it, and a specification an agent helped to draft is audited by people. As of July 2026 the verified code was in preview versions of Windows.&amp;lt;ref name=&amp;quot;symcrypt&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;What is verified, and what is not.&#039;&#039;&#039; The proofs are about the Lean model that Aeneas produces from the Rust code, so the faithfulness of that translation is trusted. Some low-level wrappers, such as those that expose platform instructions, are described by small, carefully reviewed Lean specifications rather than proved, and the project&#039;s dashboards list such trusted models and the remaining assumptions for developers.&amp;lt;ref name=&amp;quot;symcrypt&amp;quot; /&amp;gt; The blog post does not claim proofs about timing or other side channels.&lt;br /&gt;
&lt;br /&gt;
== What the three have in common ==&lt;br /&gt;
&lt;br /&gt;
In each case Lean checks a proof about a model, and the link between the model and the code that runs is made by other means: testing in Cedar, a small trusted compilation layer in SampCert, an automatic translation in SymCrypt. That link and the specification itself are where the remaining risk lies. The general point is made in [[Lean theorem prover/Explainers/Types as specifications|Types as specifications]] and [[Lean theorem prover/Explainers/What has to be trusted|What has to be trusted]].&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
* [[Lean theorem prover/Applications/Teaching with Lean|Teaching with Lean]].&lt;br /&gt;
* [[Lean theorem prover/Explainers/Programs and proofs in one language|Programs and proofs in one language]], on why one language can do both.&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>PMA Publisher</name></author>
	</entry>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/Applications/The_equational_theories_project&amp;diff=6810</id>
		<title>Lean theorem prover/Applications/The equational theories project</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Applications/The_equational_theories_project&amp;diff=6810"/>
		<updated>2026-10-15T19:35:39Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:The equational theories project}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
The &#039;&#039;&#039;equational theories project&#039;&#039;&#039; was an online collaboration, proposed by Terence Tao in September 2024, to settle every implication between 4,694 simple algebraic laws. It ended with all 22,028,942 implications decided, on the strength of proofs and refutations checked by Lean.&amp;lt;ref name=&amp;quot;etp&amp;quot;&amp;gt;Matthew Bolan, Joachim Breitner, Jose Brox, et al. (34 authors, including Terence Tao), &amp;quot;The Equational Theories Project: Advancing Collaborative Mathematical Research at Scale&amp;quot;, arXiv:2512.07087, December 2025 (revised 16 December 2025). https://arxiv.org/abs/2512.07087&amp;lt;/ref&amp;gt; It was also an experiment in how mathematicians, automated provers and a proof checker can share one piece of research. This page describes the question, the scale, the tools and the result.&lt;br /&gt;
&lt;br /&gt;
== The question ==&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;magma&#039;&#039;&#039; is a set with one binary operation, written here &amp;lt;math&amp;gt;x \diamond y&amp;lt;/math&amp;gt;, and no further rules. An &#039;&#039;&#039;equational law&#039;&#039;&#039; is an identity that the operation may satisfy for all values of its variables: the commutative law &amp;lt;math&amp;gt;x \diamond y = y \diamond x&amp;lt;/math&amp;gt; is one, the associative law another. One law &#039;&#039;&#039;implies&#039;&#039;&#039; another when every magma that satisfies the first also satisfies the second.&amp;lt;ref name=&amp;quot;etp&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Tao proposed the project on his blog on 25 September 2024. He suggested taking every law in which the operation appears at most four times, up to renaming of variables and the symmetry of equality, and finding out which of them imply which.&amp;lt;ref name=&amp;quot;proposal&amp;quot;&amp;gt;Terence Tao, &amp;quot;A pilot project in universal algebra to explore new ways to collaborate and use machine assistance?&amp;quot;, &#039;&#039;What&#039;s new&#039;&#039; (blog), 25 September 2024. https://terrytao.wordpress.com/2024/09/25/a-pilot-project-in-universal-algebra-to-explore-new-ways-to-collaborate-and-use-machine-assistance/&amp;lt;/ref&amp;gt; There are 4,694 such laws, so there are &amp;lt;math&amp;gt;4694 \times 4693 = 22{,}028{,}942&amp;lt;/math&amp;gt; ordered pairs of distinct laws to decide. No algorithm can decide such implications in general, and even for short laws some known implications had needed long computer-assisted proofs. A second goal was added as the work went on: to decide the same implications for finite magmas only, where the answers can differ.&amp;lt;ref name=&amp;quot;etp&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== How it was done ==&lt;br /&gt;
&lt;br /&gt;
Each claim had to be entered as Lean code, so that it could be checked mechanically rather than read by a moderator; the paper notes that review by people, as in earlier online collaborations, would not have scaled to over twenty million statements.&amp;lt;ref name=&amp;quot;etp&amp;quot; /&amp;gt; Contributors claimed tasks from a shared dashboard, and every submission was checked automatically to compile.&amp;lt;ref name=&amp;quot;etp&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Two kinds of result were needed. An implication is proved by deriving the second law from the first. A non-implication is refuted by exhibiting a magma that satisfies the first law but not the second. Both kinds fit in a few lines of Lean. The block below defines a magma and states three laws, proves that the law &amp;lt;math&amp;gt;x = y \diamond z&amp;lt;/math&amp;gt; implies that all elements are equal, and refutes the claim that commutativity implies associativity with a two-element magma, the operation &amp;quot;not both&amp;quot; on the truth values:&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;
class Magma (G : Type) where&lt;br /&gt;
  op : G → G → G&lt;br /&gt;
&lt;br /&gt;
infixl:65 &amp;quot; ◇ &amp;quot; =&amp;gt; Magma.op&lt;br /&gt;
&lt;br /&gt;
def SingletonLaw (G : Type) [Magma G] : Prop := ∀ x y : G, x = y&lt;br /&gt;
def CommutativeLaw (G : Type) [Magma G] : Prop := ∀ x y : G, x ◇ y = y ◇ x&lt;br /&gt;
def AssociativeLaw (G : Type) [Magma G] : Prop := ∀ x y z : G, x ◇ (y ◇ z) = (x ◇ y) ◇ z&lt;br /&gt;
def CollapseLaw (G : Type) [Magma G] : Prop := ∀ x y z : G, x = y ◇ z&lt;br /&gt;
&lt;br /&gt;
/-- An implication: the law x = y ◇ z forces every element to equal every other. -/&lt;br /&gt;
theorem collapse_implies_singleton (G : Type) [Magma G] (h : CollapseLaw G) :&lt;br /&gt;
    SingletonLaw G := by&lt;br /&gt;
  intro a b&lt;br /&gt;
  calc a = a ◇ a := h a a a&lt;br /&gt;
    _ = b := (h b a a).symm&lt;br /&gt;
&lt;br /&gt;
/-- A refutation: on the two truth values, &amp;quot;not both&amp;quot; is commutative but not associative. -/&lt;br /&gt;
instance nand : Magma Bool where&lt;br /&gt;
  op a b := !(a &amp;amp;amp;&amp;amp;amp; b)&lt;br /&gt;
&lt;br /&gt;
theorem commutative_not_implies_associative :&lt;br /&gt;
    ∃ (G : Type) (_ : Magma G), CommutativeLaw G ∧ ¬ AssociativeLaw G := by&lt;br /&gt;
  refine ⟨Bool, nand, ?_, ?_⟩&lt;br /&gt;
  · intro x y&lt;br /&gt;
    cases x &amp;amp;lt;;&amp;gt; cases y &amp;amp;lt;;&amp;gt; rfl&lt;br /&gt;
  · intro h&lt;br /&gt;
    exact absurd (h true true false) (by decide)&lt;br /&gt;
&lt;br /&gt;
#print axioms collapse_implies_singleton&lt;br /&gt;
#print axioms commutative_not_implies_associative&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean 4.34.1 accepts both theorems and reports that neither depends on any axioms. The project&#039;s own code worked the same way at scale, with a custom magma class and a command that generated each numbered law.&amp;lt;ref name=&amp;quot;etp&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Most of the work was done by machines, and most of the machine output was not trusted directly. Tao&#039;s proposal already named the automated prover Prover9 for implications and the model finder Mace4 for counterexamples, with their output to be converted into Lean.&amp;lt;ref name=&amp;quot;proposal&amp;quot; /&amp;gt; In the event the project used several automated theorem provers, among them Vampire, and SAT solvers such as Kissat. For proofs found by Vampire, contributors implemented its inference steps as Lean tactics, so that each proof could be replayed and checked by Lean. Rules of order and of duality cut the work sharply: only 10,657 of the true implications needed a direct proof, the rest following from those.&amp;lt;ref name=&amp;quot;etp&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Large language models played a small part. They helped write code for the project&#039;s user interfaces and completed Lean code during formalisation, and in one case a chat model guessed a complete rewriting system for a law, which was then verified formally. For the hardest implications, the authors found that such models offered nothing beyond what the human participants could already propose.&amp;lt;ref name=&amp;quot;etp&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The result ==&lt;br /&gt;
&lt;br /&gt;
The project reached its primary goal on 14 April 2025. Counting each law&#039;s implication of itself, 8,178,279 of the 22,033,636 possible implications (37.12 per cent) are true and 13,855,357 (62.88 per cent) are false. Lean checked a generating set of 10,657 proofs and 586,925 refutations; the step from these to the whole graph, by transitivity and duality, is carried out by programs outside Lean, though the authors note that it could in principle be done inside it. Some refutations needed new constructions; the hardest single one took several months and just over 4,000 lines of Lean from several contributors.&amp;lt;ref name=&amp;quot;etp&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For finite magmas, all but two implications were settled, one and its mirror image under reversing the operation. The authors were unable to prove or refute that pair and tentatively conjecture that the implication is false.&amp;lt;ref name=&amp;quot;etp&amp;quot; /&amp;gt; The work also turned up new structures. Finite magmas satisfying one of the laws, which the authors call weak central groupoids, have been observed always to have &amp;lt;math&amp;gt;n^2&amp;lt;/math&amp;gt; or &amp;lt;math&amp;gt;2n^2&amp;lt;/math&amp;gt; elements, a pattern they report without proof.&amp;lt;ref name=&amp;quot;etp&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The account of the project was posted in December 2025 as a paper with 34 authors.&amp;lt;ref name=&amp;quot;etp&amp;quot; /&amp;gt; It reports the mathematics and also the organisation: how tasks were assigned, how automated output was turned into checked proofs, and how a proof checker let many people contribute to one result without each contribution being read by a person.&lt;br /&gt;
&lt;br /&gt;
== What it showed ==&lt;br /&gt;
&lt;br /&gt;
The project took the method of [[Lean theorem prover/Applications/The polynomial Freiman-Ruzsa conjecture|the polynomial Freiman–Ruzsa formalisation]] to a far larger number of statements, citing that project as its precedent and automating the assignment of tasks that had been done by hand there.&amp;lt;ref name=&amp;quot;etp&amp;quot; /&amp;gt; Lean&#039;s role was that of a common referee. A human proof, a proof replayed from an automated prover and a counterexample found by a SAT solver all entered on the same terms: they counted once Lean had checked them. What Lean cannot check is whether the laws were stated as intended, which is the subject of [[Lean theorem prover/Explainers/Stating the right thing|Stating the right thing]].&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
* [[Lean theorem prover/Applications/Software verification|Software verification]], where the same checker is applied to programs.&lt;br /&gt;
* [[Lean theorem prover/Explainers/Automation and its limits|Automation and its limits]], on what automated tactics can and cannot do.&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>PMA Publisher</name></author>
	</entry>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/Applications/The_Fermat%27s_Last_Theorem_project&amp;diff=6809</id>
		<title>Lean theorem prover/Applications/The Fermat&#039;s Last Theorem project</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Applications/The_Fermat%27s_Last_Theorem_project&amp;diff=6809"/>
		<updated>2026-10-15T19:35:38Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:The Fermat&#039;s Last Theorem project}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
The &#039;&#039;&#039;Fermat&#039;s Last Theorem project&#039;&#039;&#039; is a multi-author, open-source effort, led by Kevin Buzzard at Imperial College London, to formalise in Lean a proof of Fermat&#039;s Last Theorem.&amp;lt;ref name=&amp;quot;readme&amp;quot;&amp;gt;Kevin Buzzard et al., &amp;quot;Fermat&#039;s Last Theorem&amp;quot; (project page and README), Imperial College London, read 14 October 2026. https://imperialcollegelondon.github.io/FLT/ and https://github.com/ImperialCollegeLondon/FLT&amp;lt;/ref&amp;gt; This page describes its aims, its method and its state as of October 2026, including the separate, machine-written formalisation of the theorem announced in September 2026.&lt;br /&gt;
&lt;br /&gt;
== The theorem and the proof ==&lt;br /&gt;
&lt;br /&gt;
Fermat&#039;s Last Theorem says that if &amp;lt;math&amp;gt;x, y, z, n&amp;lt;/math&amp;gt; are positive integers and &amp;lt;math&amp;gt;n \ge 3&amp;lt;/math&amp;gt;, then &amp;lt;math&amp;gt;x^n + y^n&amp;lt;/math&amp;gt; never equals &amp;lt;math&amp;gt;z^n&amp;lt;/math&amp;gt;. Fermat raised it in 1637; Andrew Wiles, assisted by Richard Taylor, settled it more than 350 years later. Although the statement is about counting numbers, every known proof uses much deeper mathematics: elliptic curves, modular forms, finite flat group schemes and Galois representations, among other things. Written out in full from the axioms, any known proof would run to several thousand pages.&amp;lt;ref name=&amp;quot;general&amp;quot;&amp;gt;Kevin Buzzard, &amp;quot;A Lean formalisation of Fermat&#039;s Last Theorem&amp;quot; (the project&#039;s general information), written December 2023. https://github.com/ImperialCollegeLondon/FLT/blob/main/GENERAL.md&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Aims ==&lt;br /&gt;
&lt;br /&gt;
The project is funded by a fellowship from the Engineering and Physical Sciences Research Council, &amp;quot;Formalising Fermat&amp;quot; (EP/Y022904/1), worth £934,043, which runs from October 2024 to September 2029.&amp;lt;ref name=&amp;quot;ukri&amp;quot;&amp;gt;UK Research and Innovation, Gateway to Research, &amp;quot;Formalising Fermat&amp;quot;, grant EP/Y022904/1, principal investigator Kevin Buzzard, Imperial College London. https://gtr.ukri.org/projects?ref=EP%2FY022904%2F1&amp;lt;/ref&amp;gt; Buzzard announced it on the Lean community&#039;s blog in April 2024.&amp;lt;ref name=&amp;quot;announce&amp;quot;&amp;gt;Kevin Buzzard, &amp;quot;The Fermat&#039;s Last Theorem Project&amp;quot;, Lean community blog, 30 April 2024. https://leanprover-community.github.io/blog/posts/FLT-announcement/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first goal is not the whole theorem. It is to reduce Fermat&#039;s Last Theorem to claims that mathematicians knew by the end of the 1980s, which would then be assumed rather than proved.&amp;lt;ref name=&amp;quot;announce&amp;quot; /&amp;gt; The grant&#039;s own summary puts the same aim another way: to formalise much of the mathematics of a modern proof, and so to reduce the task to formalising results from the 1980s.&amp;lt;ref name=&amp;quot;ukri&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Buzzard gave several reasons for the work. Many standard objects of modern number theory had not been defined in Lean or in any other theorem prover, so many recent results could not even be stated, let alone proved; the project would have to define them. Foundational material would go into Mathlib, Lean&#039;s mathematical library. And when he wrote, in December 2023, Fermat&#039;s Last Theorem was the one problem left unformalised on Freek Wiedijk&#039;s list of 100 challenge theorems for computer formalisation.&amp;lt;ref name=&amp;quot;general&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Method ==&lt;br /&gt;
&lt;br /&gt;
The proof being formalised is not Wiles&#039;s original. It is a modern variant of the Wiles and Taylor–Wiles argument that borrows heavily from the ideas of Khare and Wintenberger, and its route was planned almost entirely by Richard Taylor in discussions with Buzzard.&amp;lt;ref name=&amp;quot;readme&amp;quot; /&amp;gt; At its heart is still the idea, proved by Wiles in crucial cases, that a certain deformation ring &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; is isomorphic to a Hecke algebra &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&amp;lt;ref name=&amp;quot;general&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The project is organised with a blueprint, the LaTeX map of the proof whose dependency graph shows which pieces are done, a method described on [[Lean theorem prover/Applications/The polynomial Freiman-Ruzsa conjecture|the polynomial Freiman–Ruzsa conjecture]]. It works from both ends at once: down from the main theorem, stating the large claims to be assumed, and up from the basics, adding general material to Mathlib, with the aim of meeting in the middle.&amp;lt;ref name=&amp;quot;general&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Formalisation checks the literature as well as the proof. In 2024 the work on divided powers, on which the theory of crystalline cohomology relies, met a problem in the literature: a lemma in a 1965 paper by Norbert Roby appeared to be false, and the gap blocked a definition the project needed. Antoine Chambert-Loir and María Inés de Frutos-Fernández were formalising the theory; Chambert-Loir worked on a repair, and by December 2024 Buzzard reported the issues sorted out and the project back on track. In the same period Andrew Yang proved in Lean an abstract result of commutative algebra on which the &amp;lt;math&amp;gt;R = T&amp;lt;/math&amp;gt; step depends.&amp;lt;ref name=&amp;quot;going&amp;quot;&amp;gt;Kevin Buzzard, &amp;quot;Fermat&#039;s Last Theorem — how it&#039;s going&amp;quot;, &#039;&#039;Xena&#039;&#039; (blog), 11 December 2024. https://xenaproject.wordpress.com/2024/12/11/fermats-last-theorem-how-its-going/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In 2026 Buzzard gave a lecture course of eleven lectures on the proof&#039;s route, and announced a workshop in London for July 2026, funded by the company Logos Research, to find out which parts of the proof AI tools could formalise. In May 2026 he judged that such tools could not yet reliably formalise definitions correctly, or state theorems in the idiom of Mathlib, without help.&amp;lt;ref name=&amp;quot;workshop&amp;quot;&amp;gt;Kevin Buzzard, &amp;quot;Formalizing Fermat workshop&amp;quot;, &#039;&#039;Xena&#039;&#039; (blog), 15 May 2026. https://xenaproject.wordpress.com/2026/05/15/formalizing-fermat-workshop/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== A complete formal proof by other means ==&lt;br /&gt;
&lt;br /&gt;
On 4 September 2026 Anthropic announced a complete formal proof of Fermat&#039;s Last Theorem in Lean, produced, by its account, in about 11 days by dozens of instances of its model Claude working largely on their own on Prove2Me, a collaborative formalisation platform from Columbia University. The proof follows the 1995 exposition of Wiles&#039;s argument by Henri Darmon, Fred Diamond and Richard Taylor.&amp;lt;ref name=&amp;quot;beaten&amp;quot; /&amp;gt; It is about 13 million lines of Lean, proves some 30,300 theorems of which about 29,500 are used in the final proof, rests only on Lean&#039;s three standard axioms, and adapts pieces of the Imperial project and of an earlier formalisation of the theorem for regular primes. A comparison tool confirmed that the statement proved matches Mathlib&#039;s own statement of Fermat&#039;s Last Theorem.&amp;lt;ref name=&amp;quot;anthropic&amp;quot;&amp;gt;Anthropic, &amp;quot;Formalizing Fermat&#039;s Last Theorem&amp;quot;, 4 September 2026. https://www.anthropic.com/research/formalizing-fermats-last-theorem&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Buzzard compiled the code and ran the comparison himself, and reported that it checks out; he also described the proof as gigantic, over 13.4 million lines that take nearly twenty times as long to compile as Mathlib. He noted that the formalisation follows the early literature and adds nothing new mathematically, and that it closes Wiedijk&#039;s list.&amp;lt;ref name=&amp;quot;beaten&amp;quot;&amp;gt;Kevin Buzzard, &amp;quot;FLT: Anthropic has beaten me to it&amp;quot;, &#039;&#039;Xena&#039;&#039; (blog), 4 September 2026. https://xenaproject.wordpress.com/2026/09/04/flt-anthropic-has-beaten-me-to-it/&amp;lt;/ref&amp;gt; Its route is the older one, not the modern proof the Imperial project follows.&amp;lt;ref name=&amp;quot;beaten&amp;quot; /&amp;gt; In answer to readers who asked whether the program could have exploited a flaw in Lean, he described asking an AI agent to list everything in the code that was neither a definition nor a proof, and inspecting the roughly 100 lines it found, which he concluded only defined a convenience tactic; he added that this was not a perfect approach.&amp;lt;ref name=&amp;quot;beaten&amp;quot; /&amp;gt; What the Lean kernel&#039;s check does and does not establish is the subject of [[Lean theorem prover/Explainers/What has to be trusted|What has to be trusted]].&lt;br /&gt;
&lt;br /&gt;
== State as of October 2026 ==&lt;br /&gt;
&lt;br /&gt;
The machine-written proof goes further than the grant&#039;s first goal, since it proves the whole theorem rather than reducing it to the 1980s. Buzzard wrote that it does not discharge the project&#039;s other commitments: to add the fundamental objects of modern number theory to Mathlib, which is continuing, and to produce a document through which people can explore the modern proof.&amp;lt;ref name=&amp;quot;beaten&amp;quot; /&amp;gt; The project page still describes the work as ongoing, led by Buzzard and funded until September 2029.&amp;lt;ref name=&amp;quot;readme&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
* [[Lean theorem prover/Applications/The equational theories project|The equational theories project]], a collaboration on a different scale.&lt;br /&gt;
* [[Lean theorem prover/Applications/Machine learning and theorem proving|Machine learning and theorem proving]], for machine-written proofs in general.&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>PMA Publisher</name></author>
	</entry>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/Applications/The_polynomial_Freiman-Ruzsa_conjecture&amp;diff=6808</id>
		<title>Lean theorem prover/Applications/The polynomial Freiman-Ruzsa conjecture</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Applications/The_polynomial_Freiman-Ruzsa_conjecture&amp;diff=6808"/>
		<updated>2026-10-15T19:35:36Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:The polynomial Freiman-Ruzsa conjecture}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
The &#039;&#039;&#039;polynomial Freiman–Ruzsa conjecture&#039;&#039;&#039;, also called &#039;&#039;&#039;Marton&#039;s conjecture&#039;&#039;&#039;, is a statement in additive combinatorics about sets that are nearly closed under addition. In November 2023 W. T. Gowers, Ben Green, Freddie Manners and Terence Tao proved it in characteristic 2, and in about three weeks a group of volunteers led by Tao checked the proof in Lean. This page describes the result, how the checking was organised, and what it found.&lt;br /&gt;
&lt;br /&gt;
== The statement ==&lt;br /&gt;
&lt;br /&gt;
Take the strings of &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; bits, added place by place with 1 + 1 = 0; mathematicians write this space &amp;lt;math&amp;gt;\mathbb{F}_2^n&amp;lt;/math&amp;gt;. For a set &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; of such strings, &amp;lt;math&amp;gt;A + A&amp;lt;/math&amp;gt; is the set of all sums of two of its elements. If &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; is a subspace, adding gives nothing new and &amp;lt;math&amp;gt;A + A = A&amp;lt;/math&amp;gt;. The conjecture says the converse holds in a robust form: if &amp;lt;math&amp;gt;A + A&amp;lt;/math&amp;gt; is not much larger than &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, then &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; is close to a subspace.&lt;br /&gt;
&lt;br /&gt;
In the form Tao gave on his blog: if &amp;lt;math&amp;gt;|A + A| \le K|A|&amp;lt;/math&amp;gt;, then &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; can be covered by at most &amp;lt;math&amp;gt;2K^{12}&amp;lt;/math&amp;gt; translates of a subspace &amp;lt;math&amp;gt;H&amp;lt;/math&amp;gt; with &amp;lt;math&amp;gt;|H| \le |A|&amp;lt;/math&amp;gt;.&amp;lt;ref name=&amp;quot;taoblog&amp;quot;&amp;gt;Terence Tao, &amp;quot;On a conjecture of Marton&amp;quot;, &#039;&#039;What&#039;s new&#039;&#039; (blog), 13 November 2023. https://terrytao.wordpress.com/2023/11/13/on-a-conjecture-of-marton/&amp;lt;/ref&amp;gt; What matters is that the number of translates is bounded by a power of &amp;lt;math&amp;gt;K&amp;lt;/math&amp;gt;; the best earlier bound, which Tao attributes to Konyagin, grew faster than any power.&amp;lt;ref name=&amp;quot;taoblog&amp;quot; /&amp;gt; The conjecture connects a simple test on sums with algebraic structure, and it has links to areas such as coding theory and cryptography; &#039;&#039;Quanta Magazine&#039;&#039; reported that Gil Kalai had called it &amp;quot;a holy grail&amp;quot; of the field.&amp;lt;ref name=&amp;quot;quanta&amp;quot;&amp;gt;Leila Sloman, &amp;quot;&#039;A-Team&#039; of Math Proves a Critical Link Between Addition and Sets&amp;quot;, &#039;&#039;Quanta Magazine&#039;&#039;, 6 December 2023. https://www.quantamagazine.org/a-team-of-math-proves-a-critical-link-between-addition-and-sets-20231206/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The proof ==&lt;br /&gt;
&lt;br /&gt;
The paper &amp;quot;On a conjecture of Marton&amp;quot; was posted on 9 November 2023 and revised on 12 December 2023.&amp;lt;ref name=&amp;quot;arxiv&amp;quot;&amp;gt;W. T. Gowers, Ben Green, Freddie Manners and Terence Tao, &amp;quot;On a conjecture of Marton&amp;quot;, arXiv:2311.05762, 9 November 2023 (revised 12 December 2023). https://arxiv.org/abs/2311.05762&amp;lt;/ref&amp;gt; Its argument works with the entropy of random variables, in Shannon&#039;s sense, rather than with Fourier analysis, and it proceeds by induction on a doubling constant defined through entropy.&amp;lt;ref name=&amp;quot;taoblog&amp;quot; /&amp;gt; It was published in the &#039;&#039;Annals of Mathematics&#039;&#039; in 2025.&amp;lt;ref name=&amp;quot;annals&amp;quot;&amp;gt;W. T. Gowers, Ben Green, Freddie Manners and Terence Tao, &amp;quot;On a conjecture of Marton&amp;quot;, &#039;&#039;Annals of Mathematics&#039;&#039; 201 (2025), no. 2, pp. 515–549. doi:10.4007/annals.2025.201.2.5&amp;lt;/ref&amp;gt; In April 2024 the same four authors extended the method to abelian groups of bounded torsion.&amp;lt;ref name=&amp;quot;torsion&amp;quot;&amp;gt;W. T. Gowers, Ben Green, Freddie Manners and Terence Tao, &amp;quot;Marton&#039;s Conjecture in abelian groups with bounded torsion&amp;quot;, arXiv:2404.02244, 2 April 2024. https://arxiv.org/abs/2404.02244&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The formalisation ==&lt;br /&gt;
&lt;br /&gt;
In his blog post of 13 November 2023 Tao wrote that he planned to formalise the paper in Lean 4.&amp;lt;ref name=&amp;quot;taoblog&amp;quot; /&amp;gt; The project was started by Tao, Yaël Dillies and Bhavik Mehta, and less than a week after its launch a significant part of the paper was already formalised in full or in part.&amp;lt;ref name=&amp;quot;tour&amp;quot;&amp;gt;Terence Tao, &amp;quot;Formalizing the proof of PFR in Lean4 using Blueprint: a short tour&amp;quot;, &#039;&#039;What&#039;s new&#039;&#039; (blog), 18 November 2023. https://terrytao.wordpress.com/2023/11/18/formalizing-the-proof-of-pfr-in-lean4-using-blueprint-a-short-tour/&amp;lt;/ref&amp;gt; About 25 volunteers took part.&amp;lt;ref name=&amp;quot;quanta&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The work was organised with &#039;&#039;&#039;Blueprint&#039;&#039;&#039;, a tool written by Patrick Massot. A blueprint is a human-readable LaTeX version of the proof in which each definition and lemma is linked to its Lean counterpart. From it the tool draws a dependency graph: lemmas appear as bubbles and definitions as rectangles, and the colours show progress. Green means fully formalised; blue means the statement is formalised and its proof is ready to be formalised. When a proof compiles, its author marks it done in the LaTeX by hand, since the tool does not check that mark itself.&amp;lt;ref name=&amp;quot;tour&amp;quot; /&amp;gt; Tasks were handed out on the Lean community&#039;s chat forum: Tao posted threads of outstanding tasks, contributors claimed them first come, first served, and he kept the list up to date by hand.&amp;lt;ref name=&amp;quot;etp&amp;quot;&amp;gt;Matthew Bolan, Joachim Breitner, Jose Brox, et al. (34 authors, including Terence Tao), &amp;quot;The Equational Theories Project: Advancing Collaborative Mathematical Research at Scale&amp;quot;, arXiv:2512.07087, December 2025, section 4.5. https://arxiv.org/abs/2512.07087&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On 5 December 2023 Tao announced that the project had succeeded after three weeks: every node of the dependency graph was green, and Lean reported that the conjecture follows from the standard axioms.&amp;lt;ref name=&amp;quot;mastodon&amp;quot;&amp;gt;Terence Tao, post on Mathstodon, 5 December 2023. https://mathstodon.xyz/@tao/111526765350663641&amp;lt;/ref&amp;gt; The formalisation found a few minor typos in the paper.&amp;lt;ref name=&amp;quot;quanta&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The final statement, as it stands in the project&#039;s Lean files, uses the Mathlib library and is shown here without its proof:&amp;lt;ref name=&amp;quot;pfrsite&amp;quot;&amp;gt;Terence Tao, Yaël Dillies et al., &amp;quot;The Polynomial Freiman-Ruzsa Conjecture&amp;quot; (project page, with blueprint and Lean source), read 14 October 2026. https://teorth.github.io/pfr/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;lean lean-mathlib&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 PFR_conjecture {G : Type*} [AddCommGroup G] [Module (ZMod 2) G]&lt;br /&gt;
    {A : Set G} {K : ℝ} (hA₀ : A.Nonempty) (Afin : A.Finite)&lt;br /&gt;
    (hA : (A + A).ncard ≤ K * A.ncard) :&lt;br /&gt;
    ∃ (H : Submodule (ZMod 2) G) (c : Set G), c.Finite ∧ (H : Set G).Finite ∧&lt;br /&gt;
      Nat.card c &amp;amp;lt; 2 * K ^ 12 ∧ (H : Set G).ncard ≤ A.ncard ∧ A ⊆ c + H := by&lt;br /&gt;
  -- the proof follows in the project&#039;s files&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Read in words: &amp;lt;code&amp;gt;G&amp;lt;/code&amp;gt; is any space of the kind described above, a vector space over the two-element field; &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; is a finite, nonempty set in it whose sum set has at most &amp;lt;code&amp;gt;K&amp;lt;/code&amp;gt; times as many elements; then there are a subspace &amp;lt;code&amp;gt;H&amp;lt;/code&amp;gt;, no larger than &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;, and a finite set &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt; of fewer than &amp;lt;math&amp;gt;2K^{12}&amp;lt;/math&amp;gt; shifts, such that &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; lies inside &amp;lt;code&amp;gt;c + H&amp;lt;/code&amp;gt;. Every hypothesis is written out. The hypothesis that &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; is nonempty is one example: it was added to the Lean statement before it appeared in the blueprint&#039;s LaTeX.&amp;lt;ref name=&amp;quot;tour&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== After the main result ==&lt;br /&gt;
&lt;br /&gt;
When the main goal was reached, a second stage formalised several consequences of the theorem and an argument of Jyun-Jie Liao that lowers the exponent from 12 to 11; the project page records that stage as complete, and names among the theorems its Lean files prove both the extension to groups of bounded torsion and a further refinement of Liao&#039;s that lowers the exponent to 9.&amp;lt;ref name=&amp;quot;pfrsite&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== What it showed ==&lt;br /&gt;
&lt;br /&gt;
The blueprint divided a paper of some 35 journal pages&amp;lt;ref name=&amp;quot;annals&amp;quot; /&amp;gt; into small nodes, each of which a contributor could take on without mastering the whole argument, while Lean checked that the pieces fitted together. In that arrangement the organisers did not need to trust a contribution, only Lean&#039;s verdict on it. The [[Lean theorem prover/Applications/The equational theories project|equational theories project]] cites this project as its precedent and automated the claiming of tasks that had been done by hand here.&amp;lt;ref name=&amp;quot;etp&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The formalisation did not change the mathematics; the errors it found were minor typos.&amp;lt;ref name=&amp;quot;quanta&amp;quot; /&amp;gt; What it changed was the evidence: a reader who doubts the theorem can check the Lean proof instead of the paper.&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
* [[Lean theorem prover/Applications/The Fermat&#039;s Last Theorem project|The Fermat&#039;s Last Theorem project]], a far larger formalisation organised the same way.&lt;br /&gt;
* [[Lean theorem prover/Applications/Research mathematics|Research mathematics]], for other formalised results.&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>PMA Publisher</name></author>
	</entry>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/Applications/Research_mathematics&amp;diff=6807</id>
		<title>Lean theorem prover/Applications/Research mathematics</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Applications/Research_mathematics&amp;diff=6807"/>
		<updated>2026-10-15T19:35:35Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Research mathematics}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
Since about 2019 working mathematicians have used Lean to formalise current research, not only textbook material. This page gives an overview: a few of the results that have been formalised, the reasons mathematicians give for doing it, and the limits of what it establishes. Three projects have pages of their own: [[Lean theorem prover/Applications/The polynomial Freiman-Ruzsa conjecture|the polynomial Freiman–Ruzsa conjecture]], [[Lean theorem prover/Applications/The Fermat&#039;s Last Theorem project|the Fermat&#039;s Last Theorem project]] and [[Lean theorem prover/Applications/The equational theories project|the equational theories project]].&lt;br /&gt;
&lt;br /&gt;
== The library underneath ==&lt;br /&gt;
&lt;br /&gt;
Almost all of this work rests on &#039;&#039;&#039;Mathlib&#039;&#039;&#039;, a single library of mathematics formalised in Lean and maintained by its community. Its authors describe it as built on dependent type theory, focused on classical mathematics, organised around a large hierarchy of structures, and run as a distributed, community project.&amp;lt;ref name=&amp;quot;mathlib&amp;quot;&amp;gt;The mathlib Community, &amp;quot;The Lean mathematical library&amp;quot;, in &#039;&#039;Proceedings of the 9th ACM SIGPLAN International Conference on Certified Programs and Proofs (CPP 2020)&#039;&#039;, 2020. arXiv:1910.09336. doi:10.1145/3372885.3373824&amp;lt;/ref&amp;gt; A research project usually adds new definitions and theorems on top of it, and moves the general ones into it later. Its history is told in [[Lean theorem prover/History/Mathlib and its community|Mathlib and its community]].&lt;br /&gt;
&lt;br /&gt;
== Some formalised results ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Perfectoid spaces.&#039;&#039;&#039; Peter Scholze introduced perfectoid spaces in 2012. Kevin Buzzard, Johan Commelin and Patrick Massot formalised enough topology, algebra and geometry in Lean to define them. Their point was that a proof assistant can handle the complexity of advanced definitions, not only long proofs about simple objects.&amp;lt;ref name=&amp;quot;perfectoid&amp;quot;&amp;gt;Kevin Buzzard, Johan Commelin and Patrick Massot, &amp;quot;Formalising perfectoid spaces&amp;quot;, in &#039;&#039;CPP 2020: Proceedings of the 9th ACM SIGPLAN International Conference on Certified Programs and Proofs&#039;&#039;, 2020, pp. 299–312. doi:10.1145/3372885.3373830. arXiv:1910.12320&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Liquid vector spaces.&#039;&#039;&#039; In December 2020 Scholze challenged the Lean community to check a theorem of his and Dustin Clausen&#039;s in the theory of condensed mathematics. The formalisation was completed on 14 July 2022.&amp;lt;ref name=&amp;quot;lte&amp;quot;&amp;gt;The mathlib community, &amp;quot;Completion of the Liquid Tensor Experiment&amp;quot;, Lean community blog, 15 July 2022. https://leanprover-community.github.io/blog/posts/lte-final/&amp;lt;/ref&amp;gt; The story is told in [[Lean theorem prover/History/The Liquid Tensor Experiment|The Liquid Tensor Experiment]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sphere eversion.&#039;&#039;&#039; Massot, Floris van Doorn and Oliver Nash formalised the local h-principle for first-order, open, ample differential relations, a result of Gromov from 1973, and derived from it Smale&#039;s theorem that a sphere can be turned inside out through immersions. They took it as evidence that geometric mathematics, not only algebra, can be formalised.&amp;lt;ref name=&amp;quot;eversion&amp;quot;&amp;gt;Patrick Massot, Floris van Doorn and Oliver Nash, &amp;quot;Formalising the h-principle and sphere eversion&amp;quot;, arXiv:2210.07746, October 2022. https://arxiv.org/abs/2210.07746&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Carleson&#039;s theorem.&#039;&#039;&#039; Carleson&#039;s theorem says that the Fourier series of a continuous periodic function converges to it at almost every point. A team of 17 authors wrote a blueprint that reduces it to a new, more general theorem on doubling metric measure spaces due to harmonic analysts in Bonn, and proves that theorem.&amp;lt;ref name=&amp;quot;carleson&amp;quot; /&amp;gt; Its final version, revised in August 2025, is presented as a guide to the accompanying Lean code.&amp;lt;ref name=&amp;quot;carlesonbp&amp;quot;&amp;gt;Lars Becker, María Inés de Frutos-Fernández, Leo Diedering, Floris van Doorn, Sébastien Gouëzel, et al., &amp;quot;A blueprint for the formalization of Carleson&#039;s theorem on convergence of Fourier series&amp;quot;, arXiv:2405.06423, May 2024 (revised 6 August 2025). https://arxiv.org/abs/2405.06423&amp;lt;/ref&amp;gt; The project&#039;s description states that the proof has been formalised and names the Lean theorems for the classical statement and for both general forms.&amp;lt;ref name=&amp;quot;carleson&amp;quot;&amp;gt;Floris van Doorn et al., &amp;quot;Formalization of a generalized Carleson&#039;s theorem&amp;quot; (project description, read 13 October 2026). https://github.com/fpvandoorn/carleson&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sphere packing in dimension 8.&#039;&#039;&#039; In 2016 Maryna Viazovska proved that the &amp;lt;math&amp;gt;E_8&amp;lt;/math&amp;gt; lattice gives the densest packing of equal spheres in eight dimensions. In March 2024 Sidharth Hariharan and Viazovska began formalising the proof in Lean. The main result was formally verified in February 2026, with the final stages carried out by Gauss, an autoformalisation model of the company Math, Inc.&amp;lt;ref name=&amp;quot;packing&amp;quot;&amp;gt;Sidharth Hariharan, Christopher Birkbeck, Seewoo Lee, Ho Kiu Gareth Ma, Bhavik Mehta, Auguste Poiroux and Maryna Viazovska, &amp;quot;Progress in Formalizing Sphere Packing in Dimension 8&amp;quot;, arXiv:2604.23468, April 2026 (revised May 2026). https://arxiv.org/abs/2604.23468&amp;lt;/ref&amp;gt; EPFL reported in March 2026 that, after the team had written a detailed blueprint and progressively translated it into Lean, Gauss&#039;s help let the dimension 8 case be wrapped up in five days, and the considerably larger case of dimension 24 in two weeks.&amp;lt;ref name=&amp;quot;epfl&amp;quot;&amp;gt;EPFL, &amp;quot;Prof. Viazovska&#039;s proofs of sphere packing formalized with AI&amp;quot;, EPFL news, March 2026. https://actu.epfl.ch/news/prof-viazovska-s-proofs-of-sphere-packing-formaliz/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Why mathematicians do it ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;To settle a doubt.&#039;&#039;&#039; Scholze&#039;s liquid tensor challenge centred on one theorem in his notes with Clausen, the only result in them that he was worried about. The check confirmed the argument but found a few small gaps, all repairable, of the kind he had feared. He also reported that the work showed him why the argument works, which he had not understood when he set the challenge.&amp;lt;ref name=&amp;quot;scholze&amp;quot;&amp;gt;Peter Scholze, &amp;quot;Half a year of the Liquid Tensor Experiment: amazing developments&amp;quot;, guest post on &#039;&#039;Xena&#039;&#039; (blog), 5 June 2021. https://xenaproject.wordpress.com/2021/06/05/half-a-year-of-the-liquid-tensor-experiment-amazing-developments/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;To find errors in the literature.&#039;&#039;&#039; Formalisation cannot pass over a gap. The Fermat project found a lemma in a 1965 paper on divided powers that appeared to be false, and the gap had to be repaired before the work could go on.&amp;lt;ref name=&amp;quot;flt&amp;quot;&amp;gt;Kevin Buzzard, &amp;quot;Fermat&#039;s Last Theorem — how it&#039;s going&amp;quot;, &#039;&#039;Xena&#039;&#039; (blog), 11 December 2024. https://xenaproject.wordpress.com/2024/12/11/fermats-last-theorem-how-its-going/&amp;lt;/ref&amp;gt; In August 2026 a team led by Buzzard announced a dataset of Lean statements of 50 theorems published in the &#039;&#039;Annals of Mathematics&#039;&#039; in the 2020s. He reported that the work had already found several typos that made main theorems false as printed, four of them in papers by Fields medallists, and that each of those four was a missing hypothesis.&amp;lt;ref name=&amp;quot;annals&amp;quot;&amp;gt;Kevin Buzzard, &amp;quot;The Annals Challenge&amp;quot;, &#039;&#039;Xena&#039;&#039; (blog), 13 August 2026. https://xenaproject.wordpress.com/2026/08/13/the-annals-challenge/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;To collaborate without trusting every contributor.&#039;&#039;&#039; In the polynomial Freiman–Ruzsa and equational theories projects, people who had not read the whole argument contributed pieces, and Lean, not an organiser, decided whether each piece was correct.&amp;lt;ref name=&amp;quot;etp&amp;quot;&amp;gt;Matthew Bolan, Joachim Breitner, Jose Brox, et al. (34 authors, including Terence Tao), &amp;quot;The Equational Theories Project: Advancing Collaborative Mathematical Research at Scale&amp;quot;, arXiv:2512.07087, December 2025. https://arxiv.org/abs/2512.07087&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;To be able to state modern mathematics at all.&#039;&#039;&#039; Buzzard&#039;s team stated the main theorems of about 20 per cent of the papers that the &#039;&#039;Annals&#039;&#039; has published since 2020. Many others mention objects, such as cuspidal automorphic representations, that Mathlib does not yet define, so their statements cannot be written in Lean until those definitions are built.&amp;lt;ref name=&amp;quot;annals&amp;quot; /&amp;gt; The Fermat project gave the same gap as one of its reasons: many standard objects of modern number theory had not been defined in any theorem prover.&amp;lt;ref name=&amp;quot;general&amp;quot;&amp;gt;Kevin Buzzard, &amp;quot;A Lean formalisation of Fermat&#039;s Last Theorem&amp;quot; (the project&#039;s general information), written December 2023. https://github.com/ImperialCollegeLondon/FLT/blob/main/GENERAL.md&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;To check machine-written mathematics.&#039;&#039;&#039; Buzzard has argued that a proof which comes with Lean code at least guarantees that the argument is correct, so that a reader of AI-generated mathematics can be more confident that the reading is not wasted.&amp;lt;ref name=&amp;quot;annals&amp;quot; /&amp;gt; The use of Lean as a checker for machine-generated proofs is the subject of [[Lean theorem prover/Applications/Machine learning and theorem proving|Machine learning and theorem proving]].&lt;br /&gt;
&lt;br /&gt;
== What it does not establish ==&lt;br /&gt;
&lt;br /&gt;
A formal proof establishes that the Lean statement follows from Lean&#039;s axioms. It does not establish that the Lean statement says what the paper meant; that has to be read by people, and it is the hard part when the definitions are new. Buzzard concedes that formalisation by machine forgoes a gain that formalisation by hand has historically brought: teaching people new abstractions.&amp;lt;ref name=&amp;quot;annals&amp;quot; /&amp;gt; Formalising a known proof need not add new mathematics either: Buzzard wrote of the machine-written proof of Fermat&#039;s Last Theorem that it follows the literature faithfully and adds nothing.&amp;lt;ref name=&amp;quot;beaten&amp;quot;&amp;gt;Kevin Buzzard, &amp;quot;FLT: Anthropic has beaten me to it&amp;quot;, &#039;&#039;Xena&#039;&#039; (blog), 4 September 2026. https://xenaproject.wordpress.com/2026/09/04/flt-anthropic-has-beaten-me-to-it/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
* [[Lean theorem prover/Applications/The polynomial Freiman-Ruzsa conjecture|The polynomial Freiman–Ruzsa conjecture]], a research result checked within weeks of its proof.&lt;br /&gt;
* [[Lean theorem prover/Explainers/Stating the right thing|Stating the right thing]], on the limit named above.&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>PMA Publisher</name></author>
	</entry>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/History/Lean_since_2023&amp;diff=6806</id>
		<title>Lean theorem prover/History/Lean since 2023</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/History/Lean_since_2023&amp;diff=6806"/>
		<updated>2026-10-15T19:35:34Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Lean since 2023}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
Since 2023 Lean has been developed by a non-profit organisation set up for the purpose, with a new version roughly every month. This page covers that organisation, the versions and the automation added to them, the growth of the work done in Lean, and two flaws found in Lean&#039;s kernel in July 2026, with the response to them. It describes the state of things in October 2026.&lt;br /&gt;
&lt;br /&gt;
== The Lean Focused Research Organization ==&lt;br /&gt;
&lt;br /&gt;
In July 2023 Leonardo de Moura and Sebastian Ullrich launched the Lean Focused Research Organization (FRO), a non-profit within Convergent Research. It was supported at the start by the Simons Foundation International, the Alfred P. Sloan Foundation and Richard Merkin, and the Lean reference manual reports that it now has more than ten employees.&amp;lt;ref name=&amp;quot;refhist&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, section 1.1 &amp;quot;History&amp;quot;, for version 4.34.0 of Lean. https://lean-lang.org/doc/reference/4.34.0/Introduction/&amp;lt;/ref&amp;gt; De Moura leads it as chief architect and Ullrich as head of engineering.&amp;lt;ref name=&amp;quot;froabout&amp;quot;&amp;gt;Lean FRO, &amp;quot;About&amp;quot; page, with its timeline &amp;quot;A Brief History of Lean&amp;quot; (read 14 October 2026). https://lean-lang.org/fro/about/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The FRO states its mission as improving Lean&#039;s critical systems and guiding Lean towards long-term self-sustainability. Its listed areas of focus include scalability, usability, proof automation and documentation.&amp;lt;ref name=&amp;quot;frohome&amp;quot;&amp;gt;Lean FRO, home page, &amp;quot;Vision&amp;quot; and &amp;quot;Mission&amp;quot; (read 14 October 2026). https://lean-lang.org/fro/&amp;lt;/ref&amp;gt; It published a roadmap for each year of its work from August 2023. From September 2026 it moved to six-month roadmaps, saying that the field was changing too quickly to plan a year ahead.&amp;lt;ref name=&amp;quot;roadmaps&amp;quot;&amp;gt;Lean FRO, &amp;quot;Roadmap&amp;quot; (index of the roadmaps from August 2023). https://lean-lang.org/fro/roadmap/&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;y41&amp;quot;&amp;gt;Lean FRO, &amp;quot;The Lean FRO Year 4 - Part 1 Roadmap&amp;quot;, covering September 2026 to February 2027. https://lean-lang.org/fro/roadmap/y4-1/&amp;lt;/ref&amp;gt; In July 2025 Alex Gerko, founder of XTX Markets, announced gifts of $5 million to the FRO and $5 million to Mathlib.&amp;lt;ref name=&amp;quot;rpgift&amp;quot;&amp;gt;Renaissance Philanthropy, &amp;quot;Lean FRO and Mathlib receive $10M from XTX Markets Founder Alex Gerko to further advance the use of AI for mathematical research&amp;quot;, 24 July 2025. https://www.renaissancephilanthropy.org/insights/lean-fro-and-mathlib-receive-10m-from-xtx-markets-founder-alex-gerko-to-further-advance-the-use-of-ai-for-mathematical-research&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== A version every month ==&lt;br /&gt;
&lt;br /&gt;
Version 4.0.0, of 8 September 2023, was the first stable version of Lean 4. Its announcement planned a new minor version roughly each month, each preceded by a candidate version.&amp;lt;ref name=&amp;quot;firststable&amp;quot;&amp;gt;&amp;quot;The first official release of Lean 4&amp;quot;, Lean community blog, 8 September 2023. https://leanprover-community.github.io/blog/posts/first-lean-release/&amp;lt;/ref&amp;gt; The plan has held. The manual&#039;s notes list every version from 4.1.0 of 26 September 2023 to 4.35.0 of 12 October 2026, with occasional patch versions between them.&amp;lt;ref name=&amp;quot;relnotes&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, &amp;quot;Release Notes&amp;quot;, list of versions (read 14 October 2026). https://lean-lang.org/doc/reference/latest/releases/&amp;lt;/ref&amp;gt; The Lean code in this edition is checked with version 4.34.1, of 24 September 2026.&amp;lt;ref name=&amp;quot;relnotes&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Version 4.22.0, of 14 August 2025, brought two large changes. The old compiler was replaced by a new one. And Lean gained &#039;&#039;&#039;grind&#039;&#039;&#039;, which its notes call an SMT-style tactic, with solvers for particular theories, among them a solver for linear integer arithmetic and one based on Gröbner bases.&amp;lt;ref name=&amp;quot;rn422&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, &amp;quot;Lean 4.22.0 (2025-08-14)&amp;quot;, release notes. https://lean-lang.org/doc/reference/latest/releases/v4.22.0/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The manual describes how &amp;lt;code&amp;gt;grind&amp;lt;/code&amp;gt; works. Several engines share a common store of facts: congruence closure, constraint propagation, E-matching, guided case analysis, and solvers for linear integer arithmetic and commutative rings. Every proof it finds is by contradiction. Like other tactics, it produces ordinary Lean proof terms. For problems that are purely Boolean, the manual points instead to &amp;lt;code&amp;gt;bv_decide&amp;lt;/code&amp;gt;, which calls an external SAT solver and checks the certificate it returns inside Lean.&amp;lt;ref name=&amp;quot;grind&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, chapter 16, &amp;quot;The grind tactic&amp;quot;, for version 4.34.0 of Lean. https://lean-lang.org/doc/reference/4.34.0/The--grind--tactic/&amp;lt;/ref&amp;gt; The following example is the manual&#039;s, given a name so that its axioms can be printed:&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;
theorem no_solution (x y : Int) :&lt;br /&gt;
    27 ≤ 11 * x + 13 * y →&lt;br /&gt;
    11 * x + 13 * y ≤ 45 →&lt;br /&gt;
    -10 ≤ 7 * x - 9 * y →&lt;br /&gt;
    7 * x - 9 * y ≤ 4 →&lt;br /&gt;
    False := by&lt;br /&gt;
  grind&lt;br /&gt;
&lt;br /&gt;
#print axioms no_solution&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean 4.34.1 accepts the proof and prints &amp;lt;code&amp;gt;&#039;no_solution&#039; depends on axioms: [propext, Classical.choice, Quot.sound]&amp;lt;/code&amp;gt;. The search was done by the tactic; the term it produced was checked by Lean&#039;s kernel, and rests on Lean&#039;s three axioms and nothing else. How such procedures fit into Lean is described at [[Lean theorem prover/System/Decision procedures|Decision procedures]] and [[Lean theorem prover/Explainers/Automation and its limits|Automation and its limits]]; the axioms at [[Lean theorem prover/Foundations/The three axioms|The three axioms]].&lt;br /&gt;
&lt;br /&gt;
== Wider use ==&lt;br /&gt;
&lt;br /&gt;
Mathlib kept growing; its history is at [[Lean theorem prover/History/Mathlib and its community|Mathlib and its community]]. The FRO&#039;s timeline dates the start of several large collaborative projects: on the polynomial Freiman–Ruzsa conjecture in November 2023, on Fermat&#039;s Last Theorem in December 2023, and on equational theories in September 2024.&amp;lt;ref name=&amp;quot;froabout&amp;quot; /&amp;gt; They are described at [[Lean theorem prover/Applications/The polynomial Freiman-Ruzsa conjecture|The polynomial Freiman-Ruzsa conjecture]], [[Lean theorem prover/Applications/The Fermat&#039;s Last Theorem project|The Fermat&#039;s Last Theorem project]] and [[Lean theorem prover/Applications/The equational theories project|The equational theories project]].&lt;br /&gt;
&lt;br /&gt;
Lean also became a target for machine learning. In July 2024 Google DeepMind reported AlphaProof, a system that trains itself to prove statements in Lean. With a second system for geometry it solved four of the six problems of the 2024 International Mathematical Olympiad, for 28 points out of 42, the level of a silver medal. The problems were translated into formal language by hand, and some took the systems up to three days.&amp;lt;ref name=&amp;quot;alphaproof&amp;quot;&amp;gt;Google DeepMind, &amp;quot;AI achieves silver-medal standard solving International Mathematical Olympiad problems&amp;quot;, 25 July 2024. https://deepmind.google/discover/blog/ai-solves-imo-problems-at-silver-medal-level/&amp;lt;/ref&amp;gt; Later work of this kind is described at [[Lean theorem prover/Applications/Machine learning and theorem proving|Machine learning and theorem proving]].&lt;br /&gt;
&lt;br /&gt;
In 2025 Lean received two awards. The ACM SIGPLAN Programming Languages Software Award went to Lean, with Gabriel Ebner, Soonho Kong, Leonardo de Moura and Sebastian Ullrich named as contributors. Its citation mentions Mathlib at more than 1.6 million lines, the verification asked for by Peter Scholze, the polynomial Freiman–Ruzsa conjecture, and industrial uses, among them two at Amazon Web Services.&amp;lt;ref name=&amp;quot;sigplan&amp;quot;&amp;gt;ACM SIGPLAN, &amp;quot;Programming Languages Software Award&amp;quot;, recipients, 2025: Lean Theorem Prover. https://www.sigplan.org/Awards/Software/&amp;lt;/ref&amp;gt; The CADE Skolem Award, given for a paper from the Conference on Automated Deduction of ten years earlier that has passed the test of time, went to the 2015 system description of Lean, the paper discussed at [[Lean theorem prover/History/Lean 1 to Lean 3|Lean 1 to Lean 3]].&amp;lt;ref name=&amp;quot;skolemcade&amp;quot;&amp;gt;CADE Inc., &amp;quot;Skolem Award&amp;quot;, with the list of recipients (awards at CADE-30, July 2025). https://cadeinc.org/Skolem-Award&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;skolem&amp;quot;&amp;gt;University of Bonn, Department of Mathematics, &amp;quot;Skolem Award for Floris van Doorn&amp;quot;, 27 May 2025. https://www.mathematics.uni-bonn.de/en/news/skolem-award-for-floris-van-doorn&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Flaws in Lean&#039;s kernel, July 2026 ==&lt;br /&gt;
&lt;br /&gt;
Two versions of July 2026 each fixed a soundness bug in Lean&#039;s kernel. Version 4.32.1, of 22 July, fixed one by which a malicious metaprogram running in the same process as Lean&#039;s kernel could make it accept a proof of &amp;lt;code&amp;gt;False&amp;lt;/code&amp;gt;. Its notes say that this opened no new line of attack, since such a program already has blunter ways to have bad proofs accepted, and that checking possibly dishonest proofs with comparator, described below, was not affected.&amp;lt;ref name=&amp;quot;rn4321&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, version for Lean 4.34.0, &amp;quot;Lean 4.32.1 (2026-07-22)&amp;quot;, release notes. https://lean-lang.org/doc/reference/4.34.0/releases/v4.32.1/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The second bug is the subject of a postmortem. On 25 July 2026 a purported &amp;quot;disproof&amp;quot; of the Collatz conjecture, produced with the help of AI, was published. It was not valid: it exploited a bug in the Lean kernel&#039;s handling of nested inductive types. On 28 July the exploit was reduced to a short proof of &amp;lt;code&amp;gt;False&amp;lt;/code&amp;gt; and reported, and a fix was made within an hour. Leonardo de Moura&#039;s postmortem explains the bug. When an inductive type occurred nested inside another inductive type, parameters of the containing type that none of its constructors mention dropped out of an auxiliary type that Lean&#039;s kernel generates, so an ill-typed argument in that place was never checked. The bug could be reached only by metaprogramming, by sending the definition straight to Lean&#039;s kernel; Lean&#039;s front end would have caught the ill-typed term. The postmortem calls it &amp;quot;an implementation bug, not a hole in Lean&#039;s meta-theory.&amp;quot;&amp;lt;ref name=&amp;quot;postmortem&amp;quot;&amp;gt;Leonardo de Moura, &amp;quot;Postmortem for Kernel Soundness Bug #14576&amp;quot;, 1 August 2026. https://leodemoura.github.io/blog/2026-8-1-postmortem-for-kernel-soundness-bug-14576/&amp;lt;/ref&amp;gt; Version 4.32.2, of 28 July 2026, fixes it. Its notes add that this bug could be exploited even when proofs are checked with comparator, and advise users who must guard against malicious proofs to upgrade nanoda as well.&amp;lt;ref name=&amp;quot;rn4322&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, version for Lean 4.34.0, &amp;quot;Lean 4.32.2 (2026-07-28)&amp;quot;, release notes. https://lean-lang.org/doc/reference/4.34.0/releases/v4.32.2/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The same false proof had also passed a week-old version of nanoda, the main independent checker for Lean, written in Rust. That was a second, unrelated bug in nanoda, fixed a week before the Lean bug was reported. The postmortem draws the practical lesson. Checking with an independent checker still works, since this exploit needed two distinct bugs in two implementations, but users who rely on it need current versions of both. It also rejects the suggestion of restricting metaprogramming. The elaborator is untrusted by design, so soundness cannot depend on it refusing to produce a bad term, and Lean&#039;s kernel has to reject ill-typed definitions by itself. With help from an AI system specialised in security, further mistakes in Lean&#039;s kernel were found and fixed; nanoda caught all of them.&amp;lt;ref name=&amp;quot;postmortem&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The FRO&#039;s roadmap for September 2026 to February 2027 makes independent checking a routine step. It plans commands for Lake, Lean&#039;s build tool, that re-check a development with the Lean kernel, with an alternative checker, or with every checker shipped with Lean, and it plans to include the comparator tool in Lean&#039;s distribution.&amp;lt;ref name=&amp;quot;y41&amp;quot; /&amp;gt; The manual already calls comparator the gold standard against deliberately misleading proofs. It compiles the proposed proof in a sandbox, then replays it outside with Lean&#039;s kernel or an external checker, and confirms that the theorems proved are the ones stated in a trusted file.&amp;lt;ref name=&amp;quot;validating&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, &amp;quot;Validating a Lean Proof&amp;quot;, for version 4.34.0 of Lean. https://lean-lang.org/doc/reference/4.34.0/ValidatingProofs/&amp;lt;/ref&amp;gt; The reasons for this arrangement are set out at [[Lean theorem prover/Explainers/What has to be trusted|What has to be trusted]] and [[Lean theorem prover/System/Proof export and independent checkers|Proof export and independent checkers]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
Provenance: the FRO&#039;s own pages, the Lean reference manual (history, version notes including those of 4.32.1 and 4.32.2, the chapter on &amp;lt;code&amp;gt;grind&amp;lt;/code&amp;gt; and the section on validating proofs), de Moura&#039;s postmortem, the DeepMind announcement, the SIGPLAN and CADE award pages and the Bonn announcement were read on or before 14 October 2026. Dates of projects come from the FRO&#039;s timeline, which is the developers&#039; own account. The postmortem names no version of Lean; the versions and dates of the two fixes come from the version notes. The one quotation is from the postmortem. Events after mid-October 2026 are not covered.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/Applications/Research mathematics|Research mathematics]] · [[Lean theorem prover/Chronology|Chronology]]&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>PMA Publisher</name></author>
	</entry>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/History/The_Liquid_Tensor_Experiment&amp;diff=6805</id>
		<title>Lean theorem prover/History/The Liquid Tensor Experiment</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/History/The_Liquid_Tensor_Experiment&amp;diff=6805"/>
		<updated>2026-10-15T19:35:32Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:The Liquid Tensor Experiment}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
The Liquid Tensor Experiment was the formalisation in Lean of a recent and difficult theorem by Dustin Clausen and Peter Scholze. Scholze posed it as a public challenge in December 2020. The part of the proof he was unsure of was checked by June 2021, and the whole statement was proved on 14 July 2022. The project was led by Johan Commelin. This page states what the challenge was, how the work went, what it found, and what it did and did not show.&lt;br /&gt;
&lt;br /&gt;
== The challenge ==&lt;br /&gt;
&lt;br /&gt;
On 5 December 2020 Kevin Buzzard&#039;s Xena Project blog carried a guest post by Scholze headed &amp;quot;Liquid tensor experiment&amp;quot;. It asked for a formal proof of a theorem of Clausen and Scholze: for real numbers 0 &amp;amp;lt; &#039;&#039;p&#039;&#039;′ &amp;amp;lt; &#039;&#039;p&#039;&#039; ≤ 1, a profinite set &#039;&#039;S&#039;&#039; and a &#039;&#039;p&#039;&#039;-Banach space &#039;&#039;V&#039;&#039;, the Ext groups from the space of &#039;&#039;p&#039;&#039;′-measures on &#039;&#039;S&#039;&#039; to &#039;&#039;V&#039;&#039; vanish in all positive degrees. Scholze described this as a special case of Theorem 9.1 of his lecture notes on analytic geometry, and as the essence of the proof of Theorem 6.5 of the same notes.&amp;lt;ref name=&amp;quot;final&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;challenge&amp;quot;&amp;gt;Peter Scholze, &amp;quot;Liquid tensor experiment&amp;quot;, guest post on the Xena Project blog, 5 December 2020. https://xenaproject.wordpress.com/2020/12/05/liquid-tensor-experiment/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The theorem belongs to &#039;&#039;&#039;condensed mathematics&#039;&#039;&#039;, which Clausen and Scholze had begun to develop about two years before. It proposes condensed sets as a replacement for topological spaces in the foundations of mathematics. Scholze wrote that this claim stands only if the condensed approach also works in real functional analysis, and that this theorem decides whether it does.&amp;lt;ref name=&amp;quot;challenge&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
He gave his reasons for wanting a formal proof. The theorem was of foundational importance, so being &amp;quot;99.9% sure is not enough&amp;quot;. It would be used as a black box, where a mistake could go unnoticed. He had spent much of 2019 on the proof, and did not think anyone else had checked its details. He noted that he had in the past been persuasive with wrong arguments. And success would be a strong signal that computer verification of current research in very abstract mathematics had become possible.&amp;lt;ref name=&amp;quot;challenge&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The first half ==&lt;br /&gt;
&lt;br /&gt;
Six months later Scholze reported on the project in a second guest post. The Lean and mathlib community had discussed the challenge on the Lean Zulip immediately after it was posted. Reid Barton did important early work, and Commelin then took the lead: he worked directly towards the proof and handed self-contained lemmas to others. By 14 January 2021 he had formalised the statement of Theorem 9.4 of the lecture notes, the technical core of the argument, and its proof was completed on 28 May 2021 with the help of many members of the community.&amp;lt;ref name=&amp;quot;halfway&amp;quot;&amp;gt;Peter Scholze, &amp;quot;Half a year of the Liquid Tensor Experiment: Amazing developments&amp;quot;, guest post on the Xena Project blog, 5 June 2021. https://xenaproject.wordpress.com/2021/06/05/half-a-year-of-the-liquid-tensor-experiment-amazing-developments/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Scholze wrote that Theorem 9.4 was the only result he had been worried about, and that with its formal verification he had no remaining doubts about the correctness of the main proof. To him the experiment had succeeded, though the challenge itself was perhaps half done. The remaining half needed condensed abelian groups, Ext groups in abelian categories and the surrounding theory to be formalised.&amp;lt;ref name=&amp;quot;halfway&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The work did not proceed as he had expected. He had imagined that a group would first rewrite the proof as many small lemmas and only then formalise them. Instead the formalisation followed the lecture notes lemma by lemma, typed directly into Lean. The human-readable &amp;quot;blueprint&amp;quot; was written afterwards, from the formal proof, not before it.&amp;lt;ref name=&amp;quot;halfway&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== What the formalisation found ==&lt;br /&gt;
&lt;br /&gt;
Scholze answered the question whether the proof in his notes was correct: yes, up to the usual slight imprecisions.&amp;lt;ref name=&amp;quot;halfway&amp;quot; /&amp;gt; He named them.&lt;br /&gt;
&lt;br /&gt;
* One subtlety concerned quotient norms: the infimum that defines a quotient norm need not be attained. He thought an informal check would probably have missed it. It caused unexpected difficulty but needed only very minor changes to the argument.&lt;br /&gt;
* A hypothesis of Lemma 9.6 and some imprecision around Proposition 8.17 had to be corrected.&lt;br /&gt;
* Commelin found that the Breen–Deligne resolution, a non-explicit object whose existence uses stable homotopy theory, could be replaced for this purpose by an explicit complex with the same key properties. This made the rest of the proof more elementary.&lt;br /&gt;
* The formalisation of convex geometry needed for Gordan&#039;s lemma showed Scholze what makes the proof work: a reduction from a non-convex problem over the reals to a convex problem over the integers.&lt;br /&gt;
* Question 9.9 of the notes, on the growth of certain constants, was answered: explicit recursive definitions were verified, and the constants grow roughly doubly exponentially.&lt;br /&gt;
&lt;br /&gt;
He estimated the ratio of the formal proof&#039;s length to the human proof&#039;s, the de Bruijn factor named after [[Lean theorem prover/History/Automath|Automath]]&#039;s designer, at about 20.&amp;lt;ref name=&amp;quot;halfway&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Completion ==&lt;br /&gt;
&lt;br /&gt;
The Lean community announced that the experiment was completed at 15:46:13 (Eastern time) on Thursday 14 July 2022, a year and a half after the challenge. The project was led by Commelin with continuous mathematical support from Scholze; Adam Topaz contributed much of the homological algebra and condensed mathematics, and sixteen other people are named as contributors. The work was finished at ICERM in Providence, Rhode Island, during the workshop &amp;quot;Lean for the Curious Mathematician 2022&amp;quot;, and relied heavily on mathlib.&amp;lt;ref name=&amp;quot;final&amp;quot;&amp;gt;&amp;quot;Completion of the Liquid Tensor Experiment&amp;quot;, Lean community blog, 15 July 2022. https://leanprover-community.github.io/blog/posts/lte-final/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A formal proof is only as good as its statement. A theorem that Ext groups vanish proves nothing if Ext has been defined wrongly. Topaz described how the team addressed this: a separate collection of examples, written to be readable by mathematicians with little Lean, checks that each definition in the final statement behaves as expected.&amp;lt;ref name=&amp;quot;lteexamples&amp;quot;&amp;gt;Adam Topaz, &amp;quot;Definitions in the liquid tensor experiment&amp;quot;, Lean community blog, 14 October 2022. https://leanprover-community.github.io/blog/posts/lte-examples/&amp;lt;/ref&amp;gt; The general problem is the subject of [[Lean theorem prover/Explainers/Stating the right thing|Stating the right thing]].&lt;br /&gt;
&lt;br /&gt;
== Coverage ==&lt;br /&gt;
&lt;br /&gt;
The first milestone was reported in &#039;&#039;Nature&#039;&#039; on 18 June 2021, in a news article by Davide Castelvecchi.&amp;lt;ref name=&amp;quot;lteupdate&amp;quot;&amp;gt;Johan Commelin, &amp;quot;Liquid Tensor Experiment: an update&amp;quot;, Lean community blog, 31 December 2021. https://leanprover-community.github.io/blog/posts/lte-update/&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;nature&amp;quot;&amp;gt;Davide Castelvecchi, &amp;quot;Mathematicians welcome computer-assisted proof in &#039;grand unification&#039; theory&amp;quot;, &#039;&#039;Nature&#039;&#039; 595, 2021, pp. 18–19 (news, 18 June 2021). doi:10.1038/d41586-021-01627-2&amp;lt;/ref&amp;gt; Its summary says that proof-assistant software had handled an abstract concept at the cutting edge of research.&amp;lt;ref name=&amp;quot;nature&amp;quot; /&amp;gt; &#039;&#039;Quanta Magazine&#039;&#039; followed on 28 July 2021 with an article by Kevin Hartnett. It describes Commelin posting parts of the proof on Zulip for volunteers to formalise, about a dozen mathematicians contributing, and Scholze answering their questions there, and it quotes him as saying that the experiment had drastically changed his impression of what proof assistants can do.&amp;lt;ref name=&amp;quot;quanta&amp;quot;&amp;gt;Kevin Hartnett, &amp;quot;Proof Assistant Makes Jump to Big-League Math&amp;quot;, &#039;&#039;Quanta Magazine&#039;&#039;, 28 July 2021. https://www.quantamagazine.org/lean-computer-program-confirms-peter-scholze-proof-20210728/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== What it showed, and what it did not ==&lt;br /&gt;
&lt;br /&gt;
The experiment showed that a proof at the edge of current research, in abstract mathematics, could be formalised within a reasonable time by following the author&#039;s own notes. Scholze called this a landmark, and wrote that the proof assistant had helped in understanding the proof, because it always stated the current goal clearly.&amp;lt;ref name=&amp;quot;halfway&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
He was also clear about the limits. He could read the Lean definitions and statements without training, but not the proofs. The formal proof gave him reassurance that the route up the mountain could be climbed, he wrote, but no sense of the surrounding terrain.&amp;lt;ref name=&amp;quot;halfway&amp;quot; /&amp;gt; A checked proof establishes that a statement follows from the axioms; it does not by itself explain why. Other large projects that followed are described at [[Lean theorem prover/Applications/Research mathematics|Research mathematics]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
Provenance: Scholze&#039;s two posts and the community blog&#039;s posts on completion and on definitions were read. The &#039;&#039;Nature&#039;&#039; article was read only in its headline, summary and first paragraph, the rest being behind a paywall; the &#039;&#039;Quanta&#039;&#039; article was read in full. The one quotation, &amp;quot;99.9% sure is not enough&amp;quot;, is Scholze&#039;s.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/History/Lean since 2023|Lean since 2023]]&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>PMA Publisher</name></author>
	</entry>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/History/Mathlib_and_its_community&amp;diff=6804</id>
		<title>Lean theorem prover/History/Mathlib and its community</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/History/Mathlib_and_its_community&amp;diff=6804"/>
		<updated>2026-10-15T19:35:31Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Mathlib and its community}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
Mathlib is the main library of formalised mathematics for Lean. It began in 2017 as mathlib, a library for Lean 3, and was carried over to Lean 4 in 2023, where it is written with a capital letter. It is maintained by its users, not by Lean&#039;s developers. This page covers how it started, how changes to it are reviewed, where its community talks, and how large it is, with each figure dated.&lt;br /&gt;
&lt;br /&gt;
== From the core library to mathlib ==&lt;br /&gt;
&lt;br /&gt;
The library&#039;s own account of its origins is the paper &amp;quot;The Lean Mathematical Library&amp;quot;, presented at the Conference on Certified Programs and Proofs (CPP) in New Orleans in January 2020. It was published under the collective name &amp;quot;The mathlib Community&amp;quot;, standing for the 73 contributors listed in its acknowledgements.&amp;lt;ref name=&amp;quot;cpp2020&amp;quot;&amp;gt;The mathlib Community, &amp;quot;The Lean Mathematical Library&amp;quot;, in &#039;&#039;Proceedings of the 9th ACM SIGPLAN International Conference on Certified Programs and Proofs (CPP 2020)&#039;&#039;, ACM, 2020, pp. 367–381. doi:10.1145/3372885.3373824. Preprint: https://arxiv.org/abs/1910.09336&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
According to the paper, in the summer of 2017 much of the core library that came with Lean 3 was moved out of the system&#039;s own code, and this became the base of mathlib. The project was led at first by Mario Carneiro and Johannes Hölzl at Carnegie Mellon University. It drew users through Lean&#039;s documentation, its emphasis on classical mathematics, and its real-time chat. In the two years after the split it grew from 15,000 to 140,000 lines of code, not counting blank lines and comments.&amp;lt;ref name=&amp;quot;cpp2020&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paper names the features that set mathlib apart: dependently typed foundations, a focus on classical mathematics, an extensive hierarchy of structures, automation at both large and small scale, and a distributed organisation. It notes that, unlike most such libraries, many of its contributors have a background in pure mathematics, and that this shaped its contents. It treats the writing of tactics as part of library design, not of system development, a division of labour it credits to Lean 3&#039;s metaprogramming.&amp;lt;ref name=&amp;quot;cpp2020&amp;quot; /&amp;gt; How the hierarchy of structures is organised is described at [[Lean theorem prover/Explainers/A library of mathematics|A library of mathematics]] and [[Lean theorem prover/System/Type classes and instance resolution|Type classes and instance resolution]].&lt;br /&gt;
&lt;br /&gt;
== Review and maintainers ==&lt;br /&gt;
&lt;br /&gt;
Mathlib has no central organisation directing its content; design decisions and directions are discussed in public.&amp;lt;ref name=&amp;quot;cpp2020&amp;quot; /&amp;gt; Changes are proposed openly and reviewed before they are accepted. In 2020 eleven community members had been designated maintainers, responsible for approving changes in their areas, and reviews were welcomed from anyone.&amp;lt;ref name=&amp;quot;cpp2020&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The community&#039;s own description of the maintainers, as read in October 2026, is that they have the power to give final approval to proposed changes and must keep the library&#039;s design cohesive and its implementation of high quality. They usually have research-level knowledge of some field of mathematics or computer science. They join at the invitation of the current maintainers, and serve renewable two-year terms. The page then listed 28 maintainers.&amp;lt;ref name=&amp;quot;maintainers&amp;quot;&amp;gt;Lean community, &amp;quot;Mathlib maintainers&amp;quot; (read 14 October 2026). https://leanprover-community.github.io/teams/maintainers.html&amp;lt;/ref&amp;gt; A separate team of reviewers does much of the daily reviewing and passes changes it judges ready to the maintainers for a final decision. Other teams handle moderation, the code of conduct and the community&#039;s infrastructure.&amp;lt;ref name=&amp;quot;teams&amp;quot;&amp;gt;Lean community, &amp;quot;Community teams&amp;quot; and &amp;quot;Mathlib reviewers&amp;quot; (read 14 October 2026). https://leanprover-community.github.io/teams.html&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The contribution guide asks contributors to consider whether material belongs in the library at all. It suggests asking whether the material is taught or studied in a mathematics department, and whether it lies within the maintainers&#039; mathematical interests, since material outside them may be hard for them to maintain. It states plainly that the library&#039;s remit is not all of mathematics, and that a review need not come from a maintainer.&amp;lt;ref name=&amp;quot;contribute&amp;quot;&amp;gt;Lean community, &amp;quot;Contributing to mathlib&amp;quot; (read 14 October 2026). https://leanprover-community.github.io/contribute/index.html&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The Zulip forum ==&lt;br /&gt;
&lt;br /&gt;
Much of the discussion takes place on the Lean Zulip, a chat forum organised into channels. The 2020 paper describes a channel for new members that welcomes elementary questions, and another for formalising advanced mathematics; it reports that several people cited the forum&#039;s accessibility as their reason for choosing Lean.&amp;lt;ref name=&amp;quot;cpp2020&amp;quot; /&amp;gt; Projects built on the library range from published research to weekend collaborations coordinated there.&amp;lt;ref name=&amp;quot;cpp2020&amp;quot; /&amp;gt; One of them is described at [[Lean theorem prover/History/The Liquid Tensor Experiment|The Liquid Tensor Experiment]].&lt;br /&gt;
&lt;br /&gt;
== From mathlib to Mathlib ==&lt;br /&gt;
&lt;br /&gt;
The move to Lean 4 is described at [[Lean theorem prover/History/Lean 4|Lean 4]]. The Lean 4 library describes itself as &amp;quot;a user maintained library for the Lean theorem prover&amp;quot;, containing programming infrastructure, mathematics, and the tactics that serve both.&amp;lt;ref name=&amp;quot;mathlib4readme&amp;quot;&amp;gt;Mathlib, README of the Lean 4 library. https://github.com/leanprover-community/mathlib4&amp;lt;/ref&amp;gt; The Lean 3 library is now marked as no longer actively maintained.&amp;lt;ref name=&amp;quot;mathlib3readme&amp;quot;&amp;gt;Lean 3 mathlib, README. https://github.com/leanprover-community/mathlib&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Size ==&lt;br /&gt;
&lt;br /&gt;
Dozens of changes are approved every week, so each figure here carries the date of its source.&amp;lt;ref name=&amp;quot;maintainers&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* At the end of Lean 3 mathlib had over one million lines; the Lean reference manual, in the edition for version 4.34.0, says Mathlib has since grown to over 1.5 million.&amp;lt;ref name=&amp;quot;refhist&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, section 1.1 &amp;quot;History&amp;quot;, for version 4.34.0 of Lean. https://lean-lang.org/doc/reference/4.34.0/Introduction/&amp;lt;/ref&amp;gt;&lt;br /&gt;
* In October 2025 Renaissance Philanthropy described the library as nearly two million lines of computer-verified mathematics.&amp;lt;ref name=&amp;quot;rpinterview&amp;quot;&amp;gt;Renaissance Philanthropy, &amp;quot;Kevin Buzzard and Alex Kontorovich on the Future of Formal Mathematics: A Mathlib Initiative Interview&amp;quot;, 3 October 2025. https://www.renaissancephilanthropy.org/insights/kevin-buzzard-and-alex-kontorovich-on-the-future-of-formal-mathematics-a-mathlib-initiative-interview&amp;lt;/ref&amp;gt;&lt;br /&gt;
* As of October 2026 the community&#039;s statistics page counted 137,993 definitions, 290,354 theorems and 772 contributors.&amp;lt;ref name=&amp;quot;stats&amp;quot;&amp;gt;Lean community, &amp;quot;Mathlib statistics&amp;quot; (read 14 October 2026). https://leanprover-community.github.io/mathlib_stats.html&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Review has not kept pace with contributions. In the same 2025 interview, Oliver Nash reported that August 2025 was the library&#039;s busiest month, with over 1,100 contributions reviewed and added, and that about 2,000 more were waiting for review.&amp;lt;ref name=&amp;quot;rpinterview&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The Mathlib Initiative ==&lt;br /&gt;
&lt;br /&gt;
In July 2025 Alex Gerko, founder of XTX Markets, announced a gift of $5 million to Mathlib, alongside $5 million to the Lean Focused Research Organization. With the gift for Mathlib, a new Mathlib Initiative was to be set up within Renaissance Philanthropy.&amp;lt;ref name=&amp;quot;rpgift&amp;quot;&amp;gt;Renaissance Philanthropy, &amp;quot;Lean FRO and Mathlib receive $10M from XTX Markets Founder Alex Gerko to further advance the use of AI for mathematical research&amp;quot;, 24 July 2025. https://www.renaissancephilanthropy.org/insights/lean-fro-and-mathlib-receive-10m-from-xtx-markets-founder-alex-gerko-to-further-advance-the-use-of-ai-for-mathematical-research&amp;lt;/ref&amp;gt; Its stated purpose is to give the library professional support while keeping it open and collaborative. It is led by Johan Commelin, Oliver Nash and Adam Topaz, and a major aim is to increase the capacity for review.&amp;lt;ref name=&amp;quot;rpinterview&amp;quot; /&amp;gt; Several maintainers now describe themselves, on the maintainers&#039; page, as working for it.&amp;lt;ref name=&amp;quot;maintainers&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
Provenance: the 2020 CPP paper, the community&#039;s team, contribution and statistics pages (read on 14 October 2026), the README files, the Lean reference manual and the two Renaissance Philanthropy pages were read. The one quotation is the Lean 4 library&#039;s description of itself. Figures from different sources measure different things (lines, definitions, theorems) and are not comparable with each other.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/History/The Liquid Tensor Experiment|The Liquid Tensor Experiment]]&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>PMA Publisher</name></author>
	</entry>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/History/Lean_4&amp;diff=6803</id>
		<title>Lean theorem prover/History/Lean 4</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/History/Lean_4&amp;diff=6803"/>
		<updated>2026-10-15T19:35:30Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Lean 4}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
Lean 4 is a reimplementation of Lean, written for the most part in Lean itself. Its development began in 2018, it was described at the Conference on Automated Deduction in 2021, and its first stable version, 4.0.0, appeared on 8 September 2023. In the same year the mathematical library was carried over from Lean 3. This page covers the rewrite, the stable versions, and the port.&lt;br /&gt;
&lt;br /&gt;
== Why a rewrite ==&lt;br /&gt;
&lt;br /&gt;
Lean 3 was written in C++. Its developers name two problems with that in the Lean 4 system description. Users could not change many parts of the system without changing the C++ source. And proof automation written as Lean 3 metaprograms was slow compared with the same procedures written in C++ or OCaml, chiefly because Lean 3 interpreted metaprograms in a virtual machine.&amp;lt;ref name=&amp;quot;lean4&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 &#039;&#039;Automated Deduction – CADE 28&#039;&#039;, Lecture Notes in Computer Science 12699, Springer, 2021, pp. 625–635. doi:10.1007/978-3-030-79876-5_37. Author&#039;s copy: https://lean-lang.org/papers/lean4.pdf&amp;lt;/ref&amp;gt; The Lean reference manual adds that a C++ implementation limited Lean&#039;s flexibility and made it harder to develop, because of the range of skills it required.&amp;lt;ref name=&amp;quot;refhist&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, section 1.1 &amp;quot;History&amp;quot;, for version 4.34.0 of Lean. https://lean-lang.org/doc/reference/4.34.0/Introduction/&amp;lt;/ref&amp;gt; The earlier versions are described at [[Lean theorem prover/History/Lean 1 to Lean 3|Lean 1 to Lean 3]].&lt;br /&gt;
&lt;br /&gt;
== The 2021 system description ==&lt;br /&gt;
&lt;br /&gt;
Leonardo de Moura and Sebastian Ullrich described the new system at CADE-28 in 2021. Their abstract calls Lean 4 a reimplementation of the Lean interactive theorem prover in Lean itself, and says that users can modify and extend the parser, the elaborator, the tactics, the decision procedures, the pretty printer and the code generator.&amp;lt;ref name=&amp;quot;lean4&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paper lists what was new. A hygienic macro system, designed for theorem provers, lets users add notation without accidental capture of names. Type class resolution uses a tabled procedure, which addressed performance problems reported by users. The compiler produces C code, so that automation written in Lean can be compiled to native code and loaded as a plugin. Memory is managed by reference counting, which lets a function update data in place when nothing else shares it, a style the authors call &amp;quot;functional but in-place&amp;quot;. An editor server implements the Language Server Protocol. The paper ends by noting that Lean&#039;s trusted kernel is relatively small, and that its interface lets users export their developments to other systems and write their own reference checkers.&amp;lt;ref name=&amp;quot;lean4&amp;quot; /&amp;gt; The paper also states that Lean 4 was made public at the beginning of 2021, with the community already porting mathlib.&amp;lt;ref name=&amp;quot;lean4&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The manual gives the result of the rewrite in one figure: from version 4, about 90 per cent of the code that implements Lean is written in Lean.&amp;lt;ref name=&amp;quot;refhist&amp;quot; /&amp;gt; The interface the system uses for itself is open to users. The function that runs a tactic, for example, is an ordinary Lean definition:&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;
#eval Lean.versionString&lt;br /&gt;
#check @Lean.Elab.Tactic.evalTactic&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With version 4.34.1, the version used for the code in this edition, Lean prints &amp;lt;code&amp;gt;&amp;quot;4.34.1&amp;quot;&amp;lt;/code&amp;gt; and then &amp;lt;code&amp;gt;Lean.Elab.Tactic.evalTactic : Lean.Syntax → Lean.Elab.Tactic.TacticM Unit&amp;lt;/code&amp;gt;: a tactic is run by a function from syntax to an action in the tactic monad. How that machinery works is described at [[Lean theorem prover/System/The tactic framework|The tactic framework]] and [[Lean theorem prover/System/Metaprogramming in Lean|Metaprogramming in Lean]]; the macro system at [[Lean theorem prover/System/Syntax extension and hygienic macros|Syntax extension and hygienic macros]]; the compiler at [[Lean theorem prover/System/The compiler and runtime|The compiler and runtime]].&lt;br /&gt;
&lt;br /&gt;
== The first stable version ==&lt;br /&gt;
&lt;br /&gt;
Until September 2023 most of the Lean 4 ecosystem worked with nightly versions.&amp;lt;ref name=&amp;quot;firststable&amp;quot; /&amp;gt; Version 4.0.0, dated 8 September 2023, was the first stable version.&amp;lt;ref name=&amp;quot;v400&amp;quot;&amp;gt;Lean 4 source code, version tag v4.0.0, published 8 September 2023. https://github.com/leanprover/lean4/releases/tag/v4.0.0&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;refhist&amp;quot; /&amp;gt; The announcement on the Lean community blog set out a schedule: a new minor version roughly each month, preceded by a candidate version early in the month, with breaking changes documented but no promise yet of backward compatibility.&amp;lt;ref name=&amp;quot;firststable&amp;quot;&amp;gt;&amp;quot;The first official release of Lean 4&amp;quot;, Lean community blog, 8 September 2023. https://leanprover-community.github.io/blog/posts/first-lean-release/&amp;lt;/ref&amp;gt; Versions have followed in sequence since; this edition&#039;s examples are checked with version 4.34.1. The manual records that the development of Lean 4 took about as long as all earlier versions together, and that no further rewrite is planned.&amp;lt;ref name=&amp;quot;refhist&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The port of mathlib ==&lt;br /&gt;
&lt;br /&gt;
In December 2021 mathlib, the Lean 3 mathematical library, had more than 700,000 lines. Lean 4 could not run Lean 3 code. The plan, set out on the community blog in December 2021, was a semi-automated port by a tool called Mathport, written mostly by Mario Carneiro and Daniel Selsam.&amp;lt;ref name=&amp;quot;mathportpost&amp;quot;&amp;gt;&amp;quot;Update on mathport (Dec 2021)&amp;quot;, Lean community blog, 22 December 2021. https://leanprover-community.github.io/blog/posts/intro-to-mathport/&amp;lt;/ref&amp;gt; Mathport has two parts. One translates the compiled Lean 3 files into compiled Lean 4 files, so that the whole library could be imported at once; the other makes a best-effort translation of the Lean 3 source text into Lean 4 syntax.&amp;lt;ref name=&amp;quot;mathportpost&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;mathportreadme&amp;quot;&amp;gt;Mathport, README file. https://github.com/leanprover-community/mathport&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The post explains why the port could not be mechanical. Mathlib kept growing while the port went on, so the plan was not to freeze it until late. Files would move to the new library from the bottom of the import hierarchy up, with Mathport re-run on the still-changing Lean 3 sources and lining up definitions already ported. Mathport did not translate the library&#039;s tactics: metaprogramming in Lean 4 differs too much, so they had to be written again by hand.&amp;lt;ref name=&amp;quot;mathportpost&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The manual records that the port was completed in 2023 through a community effort supported by the Lean developers.&amp;lt;ref name=&amp;quot;refhist&amp;quot; /&amp;gt; The community&#039;s page tracking the port records it as declared complete as of 16 July 2023.&amp;lt;ref name=&amp;quot;portstatus&amp;quot;&amp;gt;Lean community, &amp;quot;Mathlib porting status&amp;quot; (read 14 October 2026). https://leanprover-community.github.io/mathlib-port-status/&amp;lt;/ref&amp;gt; The Lean 3 library is now marked as no longer actively maintained.&amp;lt;ref name=&amp;quot;mathlib3readme&amp;quot;&amp;gt;Lean 3 mathlib, README file. https://github.com/leanprover-community/mathlib&amp;lt;/ref&amp;gt; According to the same manual, mathlib had over one million lines at the end of Lean 3 and has since grown to over 1.5 million, and Lean 4 checks the larger library faster than Lean 3 checked the smaller one.&amp;lt;ref name=&amp;quot;refhist&amp;quot; /&amp;gt; The library and the people who maintain it are the subject of [[Lean theorem prover/History/Mathlib and its community|Mathlib and its community]].&lt;br /&gt;
&lt;br /&gt;
In July 2023, two months before the first stable version, de Moura and Ullrich founded the Lean Focused Research Organization, whose staff now work on Lean; its work is followed at [[Lean theorem prover/History/Lean since 2023|Lean since 2023]].&amp;lt;ref name=&amp;quot;refhist&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
Provenance: the 2021 system description, the Lean reference manual&#039;s history section (as of version 4.34.0), the two community blog posts, the community&#039;s porting status page and the Mathport and mathlib README files were read. The quotation &amp;quot;functional but in-place&amp;quot; is the 2021 paper&#039;s name for its technique. The date on which the port was declared complete is the one given on the community&#039;s porting status page.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/History/Mathlib and its community|Mathlib and its community]]&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>PMA Publisher</name></author>
	</entry>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/History/Lean_1_to_Lean_3&amp;diff=6802</id>
		<title>Lean theorem prover/History/Lean 1 to Lean 3</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/History/Lean_1_to_Lean_3&amp;diff=6802"/>
		<updated>2026-10-15T19:35:29Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Lean 1 to Lean 3}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
Lean was started in 2013 by Leonardo de Moura at Microsoft Research. Its first three major versions were written in C++ and developed mainly at Microsoft Research and Carnegie Mellon University. This page covers them: the system described in 2015, the second version&#039;s mode for homotopy type theory and why it did not survive, the third version and its metaprogramming in Lean, and the community&#039;s maintenance of that version after its developers turned to [[Lean theorem prover/History/Lean 4|Lean 4]].&lt;br /&gt;
&lt;br /&gt;
== The start, 2013 ==&lt;br /&gt;
&lt;br /&gt;
The Lean 4 system description dates the project&#039;s start to 2013, as an interactive theorem prover based on the Calculus of Inductive Constructions.&amp;lt;ref name=&amp;quot;lean4&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 &#039;&#039;Automated Deduction – CADE 28&#039;&#039;, Lecture Notes in Computer Science 12699, Springer, 2021, pp. 625–635. doi:10.1007/978-3-030-79876-5_37. Author&#039;s copy: https://lean-lang.org/papers/lean4.pdf&amp;lt;/ref&amp;gt; A 2017 paper by three of its early users adds that de Moura started it, and that it was developed mainly at Microsoft Research and Carnegie Mellon University under the Apache 2.0 licence.&amp;lt;ref name=&amp;quot;hott2017&amp;quot;&amp;gt;Floris van Doorn, Jakob von Raumer and Ulrik Buchholtz, &amp;quot;Homotopy type theory in Lean&amp;quot;, in &#039;&#039;Interactive Theorem Proving (ITP 2017)&#039;&#039;, Lecture Notes in Computer Science 10499, Springer, 2017, pp. 479–495. doi:10.1007/978-3-319-66107-0_30. Preprint: https://arxiv.org/abs/1704.06781&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The Lean reference manual records that Lean 0.1, the first version, appeared officially on 16 June 2014. It states the project&#039;s goal as combining the trust that comes from a small logical core, the Lean kernel, which others can implement independently, with the convenience and automation of tools such as SMT solvers. The first versions were mainly C++ libraries in which client code could construct proofs that could be checked independently; the design then moved towards a conventional interactive prover, first with tactics written in the scripting language Lua and later with a syntax of its own.&amp;lt;ref name=&amp;quot;refhist&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, section 1.1 &amp;quot;History&amp;quot;, for version 4.34.0 of Lean. https://lean-lang.org/doc/reference/4.34.0/Introduction/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The 2015 system description ==&lt;br /&gt;
&lt;br /&gt;
The first published account is &amp;quot;The Lean Theorem Prover (system description)&amp;quot; by de Moura, Soonho Kong, Jeremy Avigad, Floris van Doorn and Jakob von Raumer, presented at the 25th Conference on Automated Deduction (CADE-25) in 2015.&amp;lt;ref name=&amp;quot;lean2015&amp;quot;&amp;gt;Leonardo de Moura, Soonho Kong, Jeremy Avigad, Floris van Doorn and Jakob von Raumer, &amp;quot;The Lean Theorem Prover (system description)&amp;quot;, in &#039;&#039;Automated Deduction – CADE-25&#039;&#039;, Lecture Notes in Computer Science 9195, Springer, 2015, pp. 378–388. doi:10.1007/978-3-319-21401-6_26. Author&#039;s copy: https://lean-lang.org/papers/system.pdf&amp;lt;/ref&amp;gt; It states the aim in one line: to bridge the gap between interactive and automated theorem proving, by placing automated tools inside a framework that supports user interaction and the construction of fully specified axiomatic proofs.&lt;br /&gt;
&lt;br /&gt;
The paper describes Lean&#039;s small trusted kernel, written in two layers of C++: a type checker and the operations on terms in about 6,000 lines, and inductive families in about 700 more. The logic could be configured. With an impredicative sort of propositions, which could also be made proof-irrelevant, it gave a version of the Calculus of Inductive Constructions; without one, a version of Martin-Löf type theory. In both cases the universes were non-cumulative and definitions could be polymorphic in universe levels. Above the Lean kernel sat an elaborator that handled higher-order unification, coercions, overloading and type classes together. Proofs could be written as terms, in a declarative style resembling Mizar and Isabelle/Isar, or with tactics. Editing ran in Emacs with continuous checking, and JavaScript bindings let Lean run in a web browser. At Carnegie Mellon it was being used to formalise category theory, homotopy type theory and abstract algebra, and for a course in the spring of 2015.&amp;lt;ref name=&amp;quot;lean2015&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paper ends with plans: more search and decision procedures, better support for homotopy type theory, and an independent type checker, which it says Lean&#039;s small kernel makes simpler to write.&amp;lt;ref name=&amp;quot;lean2015&amp;quot; /&amp;gt; Independent checkers for Lean now exist; see [[Lean theorem prover/System/Proof export and independent checkers|Proof export and independent checkers]].&lt;br /&gt;
&lt;br /&gt;
== The second version and homotopy type theory ==&lt;br /&gt;
&lt;br /&gt;
The version described in 2015 is the one now called Lean 2; its published source describes itself as a snapshot of Lean 0.2, kept separately because it has special support for homotopy type theory.&amp;lt;ref name=&amp;quot;lean2readme&amp;quot;&amp;gt;Lean 2 source code, README file (&amp;quot;This is a snapshot of the Lean 0.2 theorem prover...&amp;quot;). https://github.com/leanprover/lean2&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean 2&#039;s kernel had two modes. In the standard mode the lowest universe, &amp;lt;code&amp;gt;Prop&amp;lt;/code&amp;gt;, was proof-irrelevant: any two proofs of a proposition were equal by definition. Proof irrelevance is incompatible with homotopy type theory, in which equality corresponds to paths in a space, so a second mode without proof irrelevance was added, and a library for homotopy type theory was written in it.&amp;lt;ref name=&amp;quot;hott2017&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The third version did not keep that mode. Van Doorn, von Raumer and Buchholtz give two design decisions as reasons: Lean 3&#039;s virtual machine erases proofs, and its mechanism for defining functions by pattern matching relies on axiom K. In 2017 the library therefore remained in Lean 2, which was still maintained but no longer developed.&amp;lt;ref name=&amp;quot;hott2017&amp;quot; /&amp;gt; The reason the standard mode is proof-irrelevant is set out at [[Lean theorem prover/Foundations/Proof irrelevance and subsingleton elimination|Proof irrelevance and subsingleton elimination]].&lt;br /&gt;
&lt;br /&gt;
== Lean 3 ==&lt;br /&gt;
&lt;br /&gt;
Version 3.0.0 of Lean is dated 20 January 2017, the date the reference manual also gives.&amp;lt;ref name=&amp;quot;refhist&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;v300&amp;quot;&amp;gt;Lean 3 source code, version tag v3.0.0, published 20 January 2017. https://github.com/leanprover/lean3/releases/tag/v3.0.0&amp;lt;/ref&amp;gt; The 2017 homotopy paper places the third major version in 2016, and records that many of Lean&#039;s components were rewritten for it and that its unification was restricted, because the full higher-order unification of Lean 2 could produce timeouts and error messages unrelated to the user&#039;s mistake.&amp;lt;ref name=&amp;quot;hott2017&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The change that mattered most was metaprogramming in Lean itself. Ebner, Ullrich, Roesch, Avigad and de Moura described it in 2017. Definitions marked &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; may use an interface to Lean&#039;s internal structures and procedures, and may recurse without proof of termination. They are compiled to bytecode and run in a virtual machine. Tactics become ordinary Lean programs in a tactic monad, written in the same files and with the same library as the mathematics. The paper&#039;s examples range from small interactive tactics to a simplifier and a superposition prover.&amp;lt;ref name=&amp;quot;ebner2017&amp;quot;&amp;gt;Gabriel Ebner, Sebastian Ullrich, Jared Roesch, Jeremy Avigad and Leonardo de Moura, &amp;quot;A metaprogramming framework for formal verification&amp;quot;, &#039;&#039;Proceedings of the ACM on Programming Languages&#039;&#039; 1 (ICFP), article 34, 2017. doi:10.1145/3110278. Author&#039;s copy: https://lean-lang.org/papers/tactic.pdf&amp;lt;/ref&amp;gt; The idea is followed backwards at [[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]] and forwards at [[Lean theorem prover/System/Metaprogramming in Lean|Metaprogramming in Lean]].&lt;br /&gt;
&lt;br /&gt;
In 2017, on Lean 3, a community of users started the mathematical library mathlib.&amp;lt;ref name=&amp;quot;lean4&amp;quot; /&amp;gt; Its history is at [[Lean theorem prover/History/Mathlib and its community|Mathlib and its community]].&lt;br /&gt;
&lt;br /&gt;
== The community&#039;s Lean 3 ==&lt;br /&gt;
&lt;br /&gt;
The last official version of Lean 3 was 3.4.2, dated 18 January 2019.&amp;lt;ref name=&amp;quot;lean3community&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;lean3changes&amp;quot;&amp;gt;Lean 3 community edition, change log (&amp;lt;code&amp;gt;doc/changes.md&amp;lt;/code&amp;gt;), entries from v3.2.0 (June 2017) to 3.51.1c (24 May 2023). https://github.com/leanprover-community/lean/blob/master/doc/changes.md&amp;lt;/ref&amp;gt; The developers turned to a reimplementation, and the original Lean 3 source now carries a notice that it is frozen and that Lean 4 is the official line.&amp;lt;ref name=&amp;quot;lean3frozen&amp;quot;&amp;gt;Lean 3 source code, README file, notice that the code is frozen and Lean 4 is the official line. https://github.com/leanprover/lean3&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mathlib&#039;s users still needed Lean 3, and they continued it themselves. Version 3.5.0c of 26 December 2019 is recorded as the first community version, and the community line ran to 3.51.1c of 24 May 2023.&amp;lt;ref name=&amp;quot;lean3changes&amp;quot; /&amp;gt; The community&#039;s edition describes itself as a fork of Lean 3 maintained by the Lean community, and now warns that Lean 3 is no longer actively maintained and that Lean 4 should be used instead.&amp;lt;ref name=&amp;quot;lean3community&amp;quot;&amp;gt;Lean 3 community edition, README file and its earlier version. https://github.com/leanprover-community/lean&amp;lt;/ref&amp;gt; Mathlib&#039;s own move to Lean 4 is told at [[Lean theorem prover/History/Lean 4|Lean 4]].&lt;br /&gt;
&lt;br /&gt;
The Lean 4 system description names the limits that led to the rewrite. Many parts of Lean 3 could not be changed without editing its C++ source, and proof automation written as Lean 3 metaprograms ran slowly, chiefly because of the overhead of interpreting it in the virtual machine.&amp;lt;ref name=&amp;quot;lean4&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
Provenance: the 2015, 2017 and 2021 papers were read, as were the README files and the community change log. The date of version 3.0.0 is the date on its tag; the 2017 homotopy paper&#039;s &amp;quot;2016&amp;quot; is reported as that paper states it. Nothing here is quoted except one line of the Lean 2 README file, in the references.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/History/Lean 4|Lean 4]]&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>PMA Publisher</name></author>
	</entry>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/History/The_Calculus_of_Constructions&amp;diff=6801</id>
		<title>Lean theorem prover/History/The Calculus of Constructions</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/History/The_Calculus_of_Constructions&amp;diff=6801"/>
		<updated>2026-10-15T19:35:28Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:The Calculus of Constructions}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
The Calculus of Constructions is a type theory introduced by Thierry Coquand and Gérard Huet in the mid-1980s. With inductive types added in 1989, it became the Calculus of Inductive Constructions, the logic of the proof assistant Coq, now called the Rocq Prover. Lean&#039;s logic is a member of the same family. This page follows the calculus from Coquand&#039;s thesis to the present and states where Lean departs from its relatives.&lt;br /&gt;
&lt;br /&gt;
== Coquand&#039;s thesis and the first engine ==&lt;br /&gt;
&lt;br /&gt;
Coquand and Huet both worked at INRIA. Coquand&#039;s thesis, which presented what was first called the Theory of Constructions, was defended on 31 January 1985. The Coq reference manual&#039;s history, written by Huet, Coquand and Christine Paulin-Mohring, describes the first software as a prototype type checker for that formalism, developed from late 1983 to early 1985 and mostly Huet&#039;s work. It names Girard&#039;s polymorphic System F and de Bruijn&#039;s Automath as influences; Huet&#039;s earlier summary in the same manual describes the calculus as combining Martin-Löf&#039;s type theory and Girard&#039;s polymorphic calculus in a higher-order extension of the Automath language. The prototype used a single binding operator for both the dependent product and function abstraction, in the manner of Automath, and handled substitution with de Bruijn indices.&amp;lt;ref name=&amp;quot;rocqhist&amp;quot;&amp;gt;The Rocq Prover Reference Manual, &amp;quot;History of Coq&amp;quot;, including &amp;quot;A short history of the early versions&amp;quot; written by Thierry Coquand, Gérard Huet and Christine Paulin-Mohring in September 2015 and Huet&#039;s summary of February 1995. https://rocq-prover.org/doc/master/refman/history.html&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A preliminary version of their paper on the calculus was presented at the International Symposium on Semantics of Data Types at Sophia-Antipolis in June 1984. Coquand and Huet described it at EUROCAL in 1985, and under its present name in an INRIA report of May 1986 and in the journal &#039;&#039;Information and Computation&#039;&#039; in 1988.&amp;lt;ref name=&amp;quot;ch1986&amp;quot;&amp;gt;Thierry Coquand and Gérard Huet, &amp;quot;The calculus of constructions&amp;quot;, INRIA Research Report RR-0530, May 1986. https://inria.hal.science/inria-00076024&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;ch1985&amp;quot;&amp;gt;Thierry Coquand and Gérard Huet, &amp;quot;Constructions: a higher order proof system for mechanizing mathematics&amp;quot;, in &#039;&#039;EUROCAL &#039;85&#039;&#039;, Lecture Notes in Computer Science 203, Springer, 1985, pp. 151–184. doi:10.1007/3-540-15983-5_13&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;ch1988&amp;quot;&amp;gt;Thierry Coquand and Gérard Huet, &amp;quot;The calculus of constructions&amp;quot;, &#039;&#039;Information and Computation&#039;&#039; 76 (2–3), 1988, pp. 95–120. doi:10.1016/0890-5401(88)90005-3&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== What the calculus says ==&lt;br /&gt;
&lt;br /&gt;
In the 1986 report every proof is a lambda-expression whose type is the proposition it proves. Erasing the types leaves a pure lambda-term, the algorithm the proof contains, and computing with it corresponds to cut elimination. The authors call the correspondence between propositions and types, as Martin-Löf had advocated, a powerful paradigm for computer science. They prove that every computation in the calculus terminates, and obtain the consistency of the logic as a corollary. They also say that their terms are inspired by the Automath languages.&amp;lt;ref name=&amp;quot;ch1986&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The calculus is &#039;&#039;&#039;impredicative&#039;&#039;&#039;: a proposition may be formed by quantifying over all propositions, itself included. Christine Paulin-Mohring&#039;s later introduction gives the standard example. The type of the polymorphic identity on propositions, &amp;quot;for every proposition &#039;&#039;X&#039;&#039;, &#039;&#039;X&#039;&#039; implies &#039;&#039;X&#039;&#039;&amp;quot;, is itself a proposition. She adds that impredicativity is powerful but fragile. Only the sort of propositions may have it; making the next universe impredicative as well gives an inconsistent system.&amp;lt;ref name=&amp;quot;pm2015&amp;quot;&amp;gt;Christine Paulin-Mohring, &amp;quot;Introduction to the Calculus of Inductive Constructions&amp;quot;, in B. Woltzenlogel Paleo and D. Delahaye (eds.), &#039;&#039;All about Proofs, Proofs for All&#039;&#039;, Studies in Logic 55, College Publications, 2015. https://inria.hal.science/hal-01094195&amp;lt;/ref&amp;gt; Lean&#039;s &amp;lt;code&amp;gt;Prop&amp;lt;/code&amp;gt; has the same property; see [[Lean theorem prover/Foundations/Universes and Prop|Universes and Prop]].&lt;br /&gt;
&lt;br /&gt;
== Inductive types ==&lt;br /&gt;
&lt;br /&gt;
The pure calculus can encode natural numbers, lists and other data by impredicative definitions, but Paulin-Mohring records two drawbacks: functions over the encoded types compute inefficiently, and some natural properties of them cannot be proved.&amp;lt;ref name=&amp;quot;pm2015&amp;quot; /&amp;gt; Version 4.4 of the software, frozen in March 1988, already offered inductive types encoded in this way.&amp;lt;ref name=&amp;quot;rocqhist&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Coquand and Paulin-Mohring then added inductive definitions as primitives, following the pattern of Martin-Löf&#039;s type theory. Their paper &amp;quot;Inductively defined types&amp;quot; was presented at COLOG-88 and published in 1990; the manual dates the extension to 1989.&amp;lt;ref name=&amp;quot;rocqhist&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;cp1990&amp;quot;&amp;gt;Thierry Coquand and Christine Paulin, &amp;quot;Inductively defined types&amp;quot;, in P. Martin-Löf and G. Mints (eds.), &#039;&#039;COLOG-88&#039;&#039;, Lecture Notes in Computer Science 417, Springer, 1990, pp. 50–66. doi:10.1007/3-540-52335-9_47&amp;lt;/ref&amp;gt; The result is the &#039;&#039;&#039;Calculus of Inductive Constructions&#039;&#039;&#039;. Its rules were set out by Paulin-Mohring in 1993.&amp;lt;ref name=&amp;quot;pm1993&amp;quot;&amp;gt;Christine Paulin-Mohring, &amp;quot;Inductive definitions in the system Coq: rules and properties&amp;quot;, in &#039;&#039;Typed Lambda Calculi and Applications (TLCA &#039;93)&#039;&#039;, Lecture Notes in Computer Science 664, Springer, 1993, pp. 328–345. doi:10.1007/BFb0037116&amp;lt;/ref&amp;gt; In Lean every inductive type comes with a recursor that is its induction principle; see [[Lean theorem prover/Foundations/Inductive types and recursors|Inductive types and recursors]].&lt;br /&gt;
&lt;br /&gt;
== Coq ==&lt;br /&gt;
&lt;br /&gt;
At the end of 1989 the system was renamed Coq, for the Calculus of Inductive Constructions, with version 5.1.&amp;lt;ref name=&amp;quot;rocqhist&amp;quot; /&amp;gt; The name referred to the Calculus of Constructions, to Thierry Coquand, and to the rooster, a French national symbol.&amp;lt;ref name=&amp;quot;rocqabout&amp;quot;&amp;gt;The Rocq Prover, &amp;quot;About&amp;quot; page, sections &amp;quot;An Overview of the Name&#039;s Evolution&amp;quot; and &amp;quot;Awards&amp;quot;. https://rocq-prover.org/about&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The early system already had the division of labour Lean has today. Its theorem prover ran tactics written in CAML &amp;quot;in the LCF fashion&amp;quot;, and users could add their own.&amp;lt;ref name=&amp;quot;rocqhist&amp;quot; /&amp;gt; From version 4.7 in 1988 the proof checker, called the Constructive Engine, was kept apart as the trusted core: a proof term assembled by tactics was checked again in full by the engine, so the tactics did not themselves need to be certified.&amp;lt;ref name=&amp;quot;rocqhist&amp;quot; /&amp;gt; The idea is followed at [[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]].&lt;br /&gt;
&lt;br /&gt;
In 2013 the ACM Software System Award was given to the team that first developed Coq.&amp;lt;ref name=&amp;quot;rocqabout&amp;quot; /&amp;gt; The project later took a new name. Version 9.0 of the Rocq Prover, issued on 12 March 2025, completed the renaming from the Coq Proof Assistant.&amp;lt;ref name=&amp;quot;rocq9&amp;quot;&amp;gt;The Rocq Prover, &amp;quot;Rocq 9.0.0&amp;quot; (announcement of version 9.0.0, 12 March 2025). https://rocq-prover.org/releases/9.0.0&amp;lt;/ref&amp;gt; The new name honours Inria Rocquencourt, where the prover was first developed.&amp;lt;ref name=&amp;quot;rocqabout&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Lean&#039;s place in the family ==&lt;br /&gt;
&lt;br /&gt;
Lean implements a version of the Calculus of Inductive Constructions. Its developers have said so from the start: the 2015 system description presents Lean&#039;s trusted kernel as a version of it when the sort of propositions is impredicative, and the 2017 paper on Lean 3&#039;s metaprogramming cites Coquand and Huet (1988) and Coquand and Paulin (1990) for the logic.&amp;lt;ref name=&amp;quot;lean2015&amp;quot;&amp;gt;Leonardo de Moura, Soonho Kong, Jeremy Avigad, Floris van Doorn and Jakob von Raumer, &amp;quot;The Lean Theorem Prover (system description)&amp;quot;, in &#039;&#039;Automated Deduction – CADE-25&#039;&#039;, Lecture Notes in Computer Science 9195, Springer, 2015, pp. 378–388. doi:10.1007/978-3-319-21401-6_26. Author&#039;s copy: https://lean-lang.org/papers/system.pdf&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;ebner2017&amp;quot;&amp;gt;Gabriel Ebner, Sebastian Ullrich, Jared Roesch, Jeremy Avigad and Leonardo de Moura, &amp;quot;A metaprogramming framework for formal verification&amp;quot;, &#039;&#039;Proceedings of the ACM on Programming Languages&#039;&#039; 1 (ICFP), article 34, 2017. doi:10.1145/3110278. Author&#039;s copy: https://lean-lang.org/papers/tactic.pdf&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is not the same theory as Coq&#039;s. Mario Carneiro&#039;s 2019 account of Lean&#039;s type theory lists the differences as they then stood. Coq&#039;s universes are cumulative, so that a type in one universe also belongs to every larger one, and Lean&#039;s are not. Coq&#039;s core language has primitive constructs for recursion and pattern matching, while Lean&#039;s kernel has only the recursors, and recursive definitions are compiled into them. Lean&#039;s definitions are polymorphic in universe levels. Lean has definitional proof irrelevance, any two proofs of a proposition being equal by definition, where Coq then had it only as an axiom. And Lean has quotient types with a computation rule.&amp;lt;ref name=&amp;quot;carneiro2019&amp;quot;&amp;gt;Mario Carneiro, &#039;&#039;The Type Theory of Lean&#039;&#039;, thesis, April 2019, section 2.8 &amp;quot;Differences from Coq&amp;quot;. https://github.com/digama0/lean-type-theory/releases/download/v1.0/main.pdf&amp;lt;/ref&amp;gt; The 2015 description had already noted that, unlike Coq, Lean keeps fixed-point expressions, match expressions and the termination checker out of the Lean kernel.&amp;lt;ref name=&amp;quot;lean2015&amp;quot; /&amp;gt; These features of Lean are treated at [[Lean theorem prover/Foundations/Proof irrelevance and subsingleton elimination|Proof irrelevance and subsingleton elimination]], [[Lean theorem prover/Foundations/Quotient types|Quotient types]] and [[Lean theorem prover/Foundations/Structural and well-founded recursion|Structural and well-founded recursion]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
Provenance: the Rocq reference manual&#039;s history, the 1986 INRIA report, Paulin-Mohring&#039;s 2015 introduction, Carneiro&#039;s thesis, the two Lean papers and the Rocq project&#039;s pages were read. Coquand&#039;s thesis, the 1985, 1988, 1990 and 1993 papers were not opened; their details come from the publishers&#039; records and the manual. The date of the decision to rename Coq was not verified and is not given.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/History/Lean 1 to Lean 3|Lean 1 to Lean 3]]&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>PMA Publisher</name></author>
	</entry>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/History/Martin-L%C3%B6f_type_theory&amp;diff=6800</id>
		<title>Lean theorem prover/History/Martin-Löf type theory</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/History/Martin-L%C3%B6f_type_theory&amp;diff=6800"/>
		<updated>2026-10-15T19:35:26Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Martin-Löf type theory}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
Per Martin-Löf&#039;s intuitionistic theory of types, begun at Stockholm in 1971, made the identification of propositions with types the foundation of a whole system of mathematics, not an observation about one. Its first version was inconsistent; the versions that followed from 1972 to 1984 are predicative and have stood. This page follows that development and the proof assistants built on it, and says what Lean took from it.&lt;br /&gt;
&lt;br /&gt;
== The first version and Girard&#039;s paradox ==&lt;br /&gt;
&lt;br /&gt;
Martin-Löf&#039;s first theory, an unpublished Stockholm preprint of 1971, contained an axiom that there is a type of all types.&amp;lt;ref name=&amp;quot;pml&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;sep&amp;quot;&amp;gt;Peter Dybjer and Erik Palmgren, &amp;quot;Intuitionistic Type Theory&amp;quot;, &#039;&#039;Stanford Encyclopedia of Philosophy&#039;&#039;, first published 12 February 2016, substantive revision 23 September 2024. https://plato.stanford.edu/entries/type-theory-intuitionistic/&amp;lt;/ref&amp;gt; Jean-Yves Girard showed that this axiom leads to a contradiction. In the paper that replaced it, Martin-Löf describes the first version as based on the &amp;quot;strongly impredicative axiom that there is a type of all types&amp;quot;, records that it had to be abandoned after Girard showed it contradictory, and thanks Girard for showing him the paradox.&amp;lt;ref name=&amp;quot;ml1972&amp;quot;&amp;gt;Per Martin-Löf, &amp;quot;An intuitionistic theory of types&amp;quot;, written 1972 at the University of Stockholm; published in G. Sambin and J. M. Smith (eds.), &#039;&#039;Twenty-Five Years of Constructive Type Theory&#039;&#039;, Oxford University Press, 1998, pp. 127–172. Copy of the 1972 text: https://archive-pml.github.io/martin-lof/pdfs/An-Intuitionistic-Theory-of-Types-1972.pdf&amp;lt;/ref&amp;gt; Girard&#039;s argument encodes the Burali-Forti paradox of the largest ordinal.&amp;lt;ref name=&amp;quot;sep&amp;quot; /&amp;gt; It appeared in his doctoral thesis at the University of Paris VII in 1972, which Martin-Löf cites when he states that a universe containing itself leads to a contradiction.&amp;lt;ref name=&amp;quot;ml1984&amp;quot;&amp;gt;Per Martin-Löf, &#039;&#039;Intuitionistic Type Theory&#039;&#039;, notes by Giovanni Sambin of a series of lectures given in Padua, June 1980, Bibliopolis, Naples, 1984. Re-typeset edition: https://archive-pml.github.io/martin-lof/pdfs/Bibliopolis-Book-retypeset-1984.pdf&amp;lt;/ref&amp;gt; A simplified form of the paradox was published by Antonius Hurkens in 1995.&amp;lt;ref name=&amp;quot;hurkens&amp;quot;&amp;gt;Antonius J. C. Hurkens, &amp;quot;A simplification of Girard&#039;s paradox&amp;quot;, in &#039;&#039;Typed Lambda Calculi and Applications (TLCA &#039;95)&#039;&#039;, Lecture Notes in Computer Science 902, Springer, 1995, pp. 266–278. doi:10.1007/BFb0014058&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The lesson is the reason Lean has a hierarchy of universes instead of a single type of all types. It is told for the general reader at [[Lean theorem prover/Explainers/Why there is no type of all types|Why there is no type of all types]] and formally at [[Lean theorem prover/Foundations/Universes and Prop|Universes and Prop]].&lt;br /&gt;
&lt;br /&gt;
== The predicative versions, 1972 to 1984 ==&lt;br /&gt;
&lt;br /&gt;
The 1972 paper replaced the type of all types by a &#039;&#039;&#039;universe&#039;&#039;&#039; of small types, closed under all the ways of forming types except that it does not contain itself.&amp;lt;ref name=&amp;quot;sep&amp;quot; /&amp;gt; Martin-Löf wrote there that the change was drastic: the theory no longer contained intuitionistic simple type theory, and its proof-theoretic strength should be close to that of predicative analysis.&amp;lt;ref name=&amp;quot;ml1972&amp;quot; /&amp;gt; The paper was not published until 1998.&amp;lt;ref name=&amp;quot;sep&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The next published version was his paper to the Logic Colloquium held at Bristol in July 1973, printed in 1975 as &amp;quot;An intuitionistic theory of types: predicative part&amp;quot;.&amp;lt;ref name=&amp;quot;pml&amp;quot;&amp;gt;&amp;quot;The collected works of Per Martin-Löf&amp;quot;, an online archive of his papers, list of works with dates. https://archive-pml.github.io/&amp;lt;/ref&amp;gt; It extended the single universe to a countable hierarchy of universes and added a uniform identity type, the type of proofs that two objects are equal.&amp;lt;ref name=&amp;quot;sep&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;ml1975&amp;quot;&amp;gt;Per Martin-Löf, &amp;quot;An intuitionistic theory of types: predicative part&amp;quot;, in H. E. Rose and J. C. Shepherdson (eds.), &#039;&#039;Logic Colloquium &#039;73&#039;&#039;, Studies in Logic and the Foundations of Mathematics 80, North-Holland, 1975, pp. 73–118. doi:10.1016/S0049-237X(08)71945-1&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At the International Congress of Logic, Methodology and Philosophy of Science at Hannover in 1979 he presented &amp;quot;Constructive mathematics and computer programming&amp;quot;, published in 1982. It explained that the theory is at once a programming language and a foundation for constructive mathematics. It also introduced the extensional form of the theory, in which two objects proved equal are treated as the same for the purposes of type checking.&amp;lt;ref name=&amp;quot;sep&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;ml1982&amp;quot;&amp;gt;Per Martin-Löf, &amp;quot;Constructive mathematics and computer programming&amp;quot;, in L. J. Cohen, J. Łoś, H. Pfeiffer and K.-P. Podewski (eds.), &#039;&#039;Logic, Methodology and Philosophy of Science VI&#039;&#039;, North-Holland, 1982, pp. 153–175. doi:10.1016/S0049-237X(09)70189-2&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The best-known account is the short book &#039;&#039;Intuitionistic Type Theory&#039;&#039;, Giovanni Sambin&#039;s notes of lectures Martin-Löf gave in Padua in June 1980, published by Bibliopolis in 1984.&amp;lt;ref name=&amp;quot;ml1984&amp;quot; /&amp;gt; In 1986 Martin-Löf reformulated the theory once more, inside a &#039;&#039;&#039;logical framework&#039;&#039;&#039; in which function abstraction and the dependent function type are the only binding operations; the encyclopedia entry calls this now the main version.&amp;lt;ref name=&amp;quot;sep&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Propositions as types as the foundation ==&lt;br /&gt;
&lt;br /&gt;
The Padua lectures distinguish a proposition from a judgement. A proposition is what logical operations combine; a judgement is an act of holding something true, such as &amp;quot;A is a proposition&amp;quot; or &amp;quot;A is true&amp;quot;. A proposition is explained by saying what counts as a proof of it, much as a set is explained by saying how its elements are formed. Martin-Löf concludes that keeping the two notions apart would only duplicate them, and identifies them: a proposition is a set, and a proof is an element of it. He calls this the formulae-as-types, or propositions-as-sets, interpretation on which the theory is based.&amp;lt;ref name=&amp;quot;ml1984&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The correspondence itself was older. Curry had observed it for propositional logic in 1958, and Howard and de Bruijn extended it to predicate logic, which needs types that depend on objects.&amp;lt;ref name=&amp;quot;sep&amp;quot; /&amp;gt; (For de Bruijn&#039;s part, see [[Lean theorem prover/History/Automath|Automath]].) What Martin-Löf added was a theory in which the correspondence is the starting point: the logical connectives and quantifiers are type formers, and a mathematical proof is a program. Lean works the same way; see [[Lean theorem prover/Explainers/Propositions as types|Propositions as types]] and [[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]].&lt;br /&gt;
&lt;br /&gt;
== Descendants ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nuprl.&#039;&#039;&#039; One of the first proof assistants for type theory was Nuprl, built by R. L. Constable and colleagues and described in their book of 1986. It is based on an extensional theory close to Martin-Löf&#039;s of 1982.&amp;lt;ref name=&amp;quot;sep&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;nuprl&amp;quot;&amp;gt;R. L. Constable, S. F. Allen, H. M. Bromley, W. R. Cleaveland, J. F. Cremer, R. W. Harper, D. J. Howe, T. B. Knoblock, N. P. Mendler, P. Panangaden, J. T. Sasaki and S. F. Smith, &#039;&#039;Implementing Mathematics with the Nuprl Proof Development System&#039;&#039;, Prentice-Hall, 1986. ISBN 0-13-451832-2. Catalogue record: https://openlibrary.org/books/OL2715187M&amp;lt;/ref&amp;gt; Gordon counts it among the systems built in the LCF manner, with ML as metalanguage.&amp;lt;ref name=&amp;quot;gordon2000&amp;quot;&amp;gt;Mike Gordon, &amp;quot;From LCF to HOL: a short history&amp;quot;, in G. Plotkin, C. Stirling and M. Tofte (eds.), &#039;&#039;Proof, Language, and Interaction: Essays in Honour of Robin Milner&#039;&#039;, MIT Press, 2000. Author&#039;s copy: https://www.cl.cam.ac.uk/~mjcg/papers/HolHistory.pdf&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALF and Agda.&#039;&#039;&#039; Ulf Norell&#039;s doctoral thesis at Chalmers in 2007 designed and implemented a new Agda, a programming language based on dependent type theory that is also a proof assistant. It cites as earlier systems the ALF proof editor of L. Magnusson and B. Nordström (1994) and the earlier Agda of Catarina Coquand and Thierry Coquand (1999).&amp;lt;ref name=&amp;quot;norell&amp;quot;&amp;gt;Ulf Norell, &#039;&#039;Towards a Practical Programming Language Based on Dependent Type Theory&#039;&#039;, PhD thesis, Chalmers University of Technology and Göteborg University, 2007. https://www.cse.chalmers.se/~ulfn/papers/thesis.pdf&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;agda2009&amp;quot;&amp;gt;Ana Bove, Peter Dybjer and Ulf Norell, &amp;quot;A brief overview of Agda – a functional language with dependent types&amp;quot;, in &#039;&#039;Theorem Proving in Higher Order Logics (TPHOLs 2009)&#039;&#039;, Lecture Notes in Computer Science 5674, Springer, 2009, pp. 73–78. doi:10.1007/978-3-642-03359-9_6&amp;lt;/ref&amp;gt; Agda is based on the logical-framework formulation of Martin-Löf&#039;s predicative theory.&amp;lt;ref name=&amp;quot;sep&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The other branch.&#039;&#039;&#039; Coq and Lean descend instead from the Calculus of Constructions, which is impredicative; that line is followed at [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]]. The encyclopedia entry notes that the Calculus of Inductive Constructions has a predicative part that follows Martin-Löf&#039;s principles.&amp;lt;ref name=&amp;quot;sep&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== What Lean took ==&lt;br /&gt;
&lt;br /&gt;
Lean&#039;s logic combines the two lines. The 2015 description of Lean says that with an impredicative sort of propositions Lean&#039;s trusted kernel gives a version of the Calculus of Inductive Constructions, and without one it gives a version of Martin-Löf type theory; in both cases there is a sequence of type universes, which in Lean are not cumulative.&amp;lt;ref name=&amp;quot;lean2015&amp;quot;&amp;gt;Leonardo de Moura, Soonho Kong, Jeremy Avigad, Floris van Doorn and Jakob von Raumer, &amp;quot;The Lean Theorem Prover (system description)&amp;quot;, in &#039;&#039;Automated Deduction – CADE-25&#039;&#039;, Lecture Notes in Computer Science 9195, Springer, 2015, pp. 378–388. doi:10.1007/978-3-319-21401-6_26. Author&#039;s copy: https://lean-lang.org/papers/system.pdf&amp;lt;/ref&amp;gt; The universes &amp;lt;code&amp;gt;Type 0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Type 1&amp;lt;/code&amp;gt; and so on, each a member of the next and none of itself, follow the pattern Martin-Löf adopted after Girard&#039;s paradox in 1972 and extended in 1973. The impredicative &amp;lt;code&amp;gt;Prop&amp;lt;/code&amp;gt; is the other branch&#039;s contribution.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
Provenance: Martin-Löf&#039;s 1972 paper (its first page) and the 1984 Padua notes were read, as were the encyclopedia entry by Dybjer and Palmgren, Norell&#039;s thesis (introduction and references), Gordon&#039;s history and the 2015 Lean paper. Girard&#039;s 1972 thesis, the 1975 and 1982 papers, Hurkens&#039;s paper, the Nuprl book and the 2009 Agda overview were not opened; their details come from the publishers&#039; records, the encyclopedia entry and Martin-Löf&#039;s own references.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]]&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>PMA Publisher</name></author>
	</entry>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/History/LCF_and_the_tactic_idea&amp;diff=6799</id>
		<title>Lean theorem prover/History/LCF and the tactic idea</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/History/LCF_and_the_tactic_idea&amp;diff=6799"/>
		<updated>2026-10-15T19:35:25Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:LCF and the tactic idea}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
LCF was a proof checker built by Robin Milner, first at Stanford in 1972 and then, in a new design, at Edinburgh. Two ideas from the Edinburgh design run through many proof assistants since: a protected type of theorems, so that only the rules of the logic can produce one, and tactics, programs that reduce a goal to simpler goals. To make tactics programmable, Milner and his colleagues designed a programming language, ML. This page follows those ideas from 1972 to Lean.&lt;br /&gt;
&lt;br /&gt;
== Stanford LCF ==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;LCF&amp;quot; stands for Logic for Computable Functions, Milner&#039;s name for a logic Dana Scott devised in 1969 for reasoning about recursively defined functions; Scott&#039;s manuscript was not published until 1993.&amp;lt;ref name=&amp;quot;gordon2000&amp;quot;&amp;gt;Mike Gordon, &amp;quot;From LCF to HOL: a short history&amp;quot;, in G. Plotkin, C. Stirling and M. Tofte (eds.), &#039;&#039;Proof, Language, and Interaction: Essays in Honour of Robin Milner&#039;&#039;, MIT Press, 2000. Author&#039;s copy: https://www.cl.cam.ac.uk/~mjcg/papers/HolHistory.pdf&amp;lt;/ref&amp;gt; Milner built the first checker for it at Stanford in 1972, with Whitfield Diffie, Richard Weyhrauch and Malcolm Newey. His report of that year describes it as an interactive program for generating formal proofs about computable functions, helped by a subgoaling facility and a simplifier.&amp;lt;ref name=&amp;quot;gordon2000&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;milner1972&amp;quot;&amp;gt;Robin Milner, &#039;&#039;Logic for Computable Functions: Description of a Machine Implementation&#039;&#039;, Stanford Artificial Intelligence Memo AIM-169, Computer Science Report STAN-CS-72-288, Stanford University, May 1972. http://i.stanford.edu/pub/cstr/reports/cs/tr/72/288/CS-TR-72-288.pdf&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A user stated a goal and split it into subgoals with a fixed set of commands, such as induction, until the simplifier could finish each one. Gordon names two limits of the system. The proofs it stored filled the available memory, and its fixed set of proof commands could not easily be extended.&amp;lt;ref name=&amp;quot;gordon2000&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Edinburgh LCF and the type of theorems ==&lt;br /&gt;
&lt;br /&gt;
Around 1973 Milner moved to Edinburgh and began a successor, Edinburgh LCF, first with Lockwood Morris and Malcolm Newey, and from 1975 with Christopher Wadsworth and Mike Gordon.&amp;lt;ref name=&amp;quot;gordon2000&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The answer to the first limit was to keep theorems and discard proofs. To keep that safe, Milner made &#039;&#039;&#039;theorem&#039;&#039;&#039; an abstract data type. Its only given values were instances of the axioms, and its only operations were the rules of inference. A program could hold a value of type theorem only if it had obtained it from axioms by applying rules, so type checking alone guaranteed that every such value was a theorem of the logic.&amp;lt;ref name=&amp;quot;gordon2000&amp;quot; /&amp;gt; The steps of a proof were carried out but not recorded. The guarantee lies in the programming language, not in a stored proof that someone else could check later.&lt;br /&gt;
&lt;br /&gt;
== ML, tactics and tacticals ==&lt;br /&gt;
&lt;br /&gt;
The answer to the second limit was a programming language in which users could write their own proof procedures. Milner, with Morris and Newey, designed &#039;&#039;&#039;ML&#039;&#039;&#039;, the &amp;quot;Meta Language&amp;quot;, strictly typed so that the abstract type of theorems could not be circumvented.&amp;lt;ref name=&amp;quot;gordon2000&amp;quot; /&amp;gt; It was described at the 1978 Symposium on Principles of Programming Languages.&amp;lt;ref name=&amp;quot;popl1978&amp;quot;&amp;gt;M. Gordon, R. Milner, L. Morris, M. Newey and C. Wadsworth, &amp;quot;A metalanguage for interactive proof in LCF&amp;quot;, in &#039;&#039;Proceedings of the 5th ACM SIGACT-SIGPLAN Symposium on Principles of Programming Languages (POPL &#039;78)&#039;&#039;, ACM, 1978, pp. 119–130. doi:10.1145/512760.512773&amp;lt;/ref&amp;gt; Milner&#039;s account of ML&#039;s polymorphic type inference appeared the same year.&amp;lt;ref name=&amp;quot;milner1978&amp;quot;&amp;gt;Robin Milner, &amp;quot;A theory of type polymorphism in programming&amp;quot;, &#039;&#039;Journal of Computer and System Sciences&#039;&#039; 17 (3), 1978, pp. 348–375. doi:10.1016/0022-0000(78)90014-4&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In ML a strategy for reducing a goal to subgoals is a function, which Milner called a &#039;&#039;&#039;tactic&#039;&#039;&#039;. Operations that combine strategies, taking tactics as arguments and returning tactics, are higher-order functions, which he called &#039;&#039;&#039;tacticals&#039;&#039;&#039;. Since a tactic may be applied to a goal it cannot handle, ML was given exceptions, so that a failing tactic could signal failure and another be tried. Gordon records that the needs of theorem proving shaped the first ML in detail.&amp;lt;ref name=&amp;quot;gordon2000&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The work was written up as &#039;&#039;Edinburgh LCF&#039;&#039; by Gordon, Milner and Wadsworth in 1979.&amp;lt;ref name=&amp;quot;lcf1979&amp;quot;&amp;gt;Michael J. Gordon, Robin Milner and Christopher P. Wadsworth, &#039;&#039;Edinburgh LCF: A Mechanised Logic of Computation&#039;&#039;, Lecture Notes in Computer Science 78, Springer, 1979. doi:10.1007/3-540-09724-4&amp;lt;/ref&amp;gt; In 1991 Milner received the ACM Turing Award; the citation names LCF, &amp;quot;probably the first theoretically based yet practical tool for machine-assisted proof construction&amp;quot;, and ML among his achievements.&amp;lt;ref name=&amp;quot;turing1991&amp;quot;&amp;gt;Announcement of the 1991 ACM Turing Award to Robin Milner, with the short citation, forwarded to the TYPES mailing list, 1 November 1991. https://www.engineering.upenn.edu/~sweirich/types/archive/1991/msg00062.html&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Descendants ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Cambridge LCF.&#039;&#039;&#039; In the early 1980s Lawrence Paulson at Cambridge and Gérard Huet in France reworked the system together. Huet improved and extended ML, and his group went on to develop Caml. Paulson&#039;s version, Cambridge LCF, was completed around 1985 and described in his 1987 book &#039;&#039;Logic and Computation&#039;&#039;.&amp;lt;ref name=&amp;quot;gordon2000&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;HOL.&#039;&#039;&#039; Gordon adapted Cambridge LCF to classical higher-order logic for verifying hardware. HOL kept LCF&#039;s syntax, its abstract type of theorems and its tactics, but read types as ordinary sets. A stable version, HOL88, appeared in about 1988. Reimplementations followed: HOL90, in Standard ML, by Konrad Slind, and HOL Light, in Caml Light, by John Harrison and Konrad Slind.&amp;lt;ref name=&amp;quot;gordon2000&amp;quot; /&amp;gt; In 2017 Ebner and colleagues noted that HOL4 and HOL Light still work in the original LCF manner, with the user interacting directly in ML.&amp;lt;ref name=&amp;quot;ebner2017&amp;quot;&amp;gt;Gabriel Ebner, Sebastian Ullrich, Jared Roesch, Jeremy Avigad and Leonardo de Moura, &amp;quot;A metaprogramming framework for formal verification&amp;quot;, &#039;&#039;Proceedings of the ACM on Programming Languages&#039;&#039; 1 (ICFP), article 34, 2017. doi:10.1145/3110278. Author&#039;s copy: https://lean-lang.org/papers/tactic.pdf&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Isabelle.&#039;&#039;&#039; Paulson then built Isabelle, a generic prover in which the rules of many logics are stated declaratively in a common metalogic and combined by higher-order unification.&amp;lt;ref name=&amp;quot;gordon2000&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;paulson1989&amp;quot;&amp;gt;Lawrence C. Paulson, &amp;quot;The foundation of a generic theorem prover&amp;quot;, &#039;&#039;Journal of Automated Reasoning&#039;&#039; 5 (3), 1989, pp. 363–397. doi:10.1007/BF00248324. Preprint: https://arxiv.org/abs/cs/9301105&amp;lt;/ref&amp;gt; Gordon notes that Isabelle keeps Milner&#039;s key idea, the abstract type of theorems, and lifts it to the metalogic.&amp;lt;ref name=&amp;quot;gordon2000&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Type theories.&#039;&#039;&#039; The LCF method, with ML as its metalanguage, was also applied to logics quite unlike Scott&#039;s. Gordon lists Nuprl, a proof system for Martin-Löf type theory, and one for the Calculus of Constructions among the LCF-style systems.&amp;lt;ref name=&amp;quot;gordon2000&amp;quot; /&amp;gt; Those are the subjects of [[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]] and [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]].&lt;br /&gt;
&lt;br /&gt;
== The line to Lean ==&lt;br /&gt;
&lt;br /&gt;
Lean took the tactic idea and changed where the guarantee lies. In Lean, as in Automath, a proof is a term of the type that states the theorem. Tactics are instructions that describe how to construct such a term, and they support writing a proof incrementally, one step at a time.&amp;lt;ref name=&amp;quot;tpil&amp;quot;&amp;gt;Jeremy Avigad, Leonardo de Moura, Soonho Kong and Sebastian Ullrich, &#039;&#039;Theorem Proving in Lean 4&#039;&#039;, chapter &amp;quot;Tactics&amp;quot;. https://lean-lang.org/theorem_proving_in_lean4/tactics.html&amp;lt;/ref&amp;gt; The first description of Lean, in 2015, presents tactics as one way, beside writing terms directly, of constructing proof terms, as in Coq, HOL Light, Isabelle and PVS, and describes Lean&#039;s small trusted kernel and proof terms that can be checked independently.&amp;lt;ref name=&amp;quot;lean2015&amp;quot;&amp;gt;Leonardo de Moura, Soonho Kong, Jeremy Avigad, Floris van Doorn and Jakob von Raumer, &amp;quot;The Lean Theorem Prover (system description)&amp;quot;, in &#039;&#039;Automated Deduction – CADE-25&#039;&#039;, Lecture Notes in Computer Science 9195, Springer, 2015, pp. 378–388. doi:10.1007/978-3-319-21401-6_26. Author&#039;s copy: https://lean-lang.org/papers/system.pdf&amp;lt;/ref&amp;gt; In LCF a faulty tactic is stopped by the type discipline of ML; in Lean whatever term a tactic produces must still pass Lean&#039;s kernel. The two arrangements are compared at [[Lean theorem prover/Explainers/What has to be trusted|What has to be trusted]].&lt;br /&gt;
&lt;br /&gt;
Lean also took the metalanguage idea, but made the metalanguage Lean itself. The 2017 paper on Lean 3&#039;s metaprogramming framework recalls that ML was designed as the metalanguage for LCF, and describes tactics written in Lean, in the same files and with the same library as the mathematics they serve.&amp;lt;ref name=&amp;quot;ebner2017&amp;quot; /&amp;gt; Lean 4 goes further: it is implemented largely in Lean, and users can extend its parser, elaborator and tactics in Lean.&amp;lt;ref name=&amp;quot;lean4&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 &#039;&#039;Automated Deduction – CADE 28&#039;&#039;, Lecture Notes in Computer Science 12699, Springer, 2021, pp. 625–635. doi:10.1007/978-3-030-79876-5_37. Author&#039;s copy: https://lean-lang.org/papers/lean4.pdf&amp;lt;/ref&amp;gt; How tactics work in Lean today is described at [[Lean theorem prover/Explainers/Tactics|Tactics]] and [[Lean theorem prover/System/The tactic framework|The tactic framework]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
Provenance: Gordon&#039;s 2000 history, the Lean papers of 2015, 2017 and 2021 and the tactics chapter of &#039;&#039;Theorem Proving in Lean 4&#039;&#039; were read for this page. Milner&#039;s 1972 report was read in its opening pages only. Milner&#039;s 1978 paper was read in its opening pages, and Paulson&#039;s 1989 paper in its preprint (abstract and history). The 1978 POPL paper and the 1979 book were not opened; their details come from Gordon&#039;s reference list and the publishers&#039; records. The account of Stanford and Edinburgh LCF follows Gordon, a participant from 1975.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/History/Martin-Löf type theory|Martin-Löf type theory]]&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>PMA Publisher</name></author>
	</entry>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/History/Automath&amp;diff=6798</id>
		<title>Lean theorem prover/History/Automath</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/History/Automath&amp;diff=6798"/>
		<updated>2026-10-15T19:35:23Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Automath}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
Automath was the first working system for checking mathematics by computer.&amp;lt;ref name=&amp;quot;gn2022&amp;quot; /&amp;gt; N. G. de Bruijn designed it at Eindhoven in the late 1960s, and his group used it through the 1970s. This page states what the project set out to do, what its languages were, what its largest text showed, and which of its ideas Lean still uses.&lt;br /&gt;
&lt;br /&gt;
== A language for whole books ==&lt;br /&gt;
&lt;br /&gt;
De Bruijn&#039;s own survey of 1980 says the project &amp;quot;was conceived in 1966&amp;quot; and that the first report was written in 1968.&amp;lt;ref name=&amp;quot;survey&amp;quot;&amp;gt;N. G. de Bruijn, &amp;quot;A survey of the project Automath&amp;quot;, in J. P. Seldin and J. R. Hindley (eds.), &#039;&#039;To H. B. Curry: Essays on Combinatory Logic, Lambda Calculus and Formalism&#039;&#039;, Academic Press, 1980, pp. 579–606; reprinted in Nederpelt, Geuvers and de Vrijer (eds.), &#039;&#039;Selected Papers on Automath&#039;&#039; (1994), pp. 141–161. Scan in the Automath Archive: https://automath.win.tue.nl/archive/pdf/aut072.pdf&amp;lt;/ref&amp;gt; His preface to van Benthem Jutting&#039;s book of 1979 gives early 1967 instead, and the Automath Archive at Eindhoven dates the first ideas to around 1967 and the large-scale work to roughly 1970–1975.&amp;lt;ref name=&amp;quot;cwi&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;archive&amp;quot;&amp;gt;The Automath Archive, Eindhoven University of Technology, &amp;quot;About Automath&amp;quot;. https://automath.win.tue.nl/aboutautomath.htm&amp;lt;/ref&amp;gt; An early published account is de Bruijn&#039;s paper to the Symposium on Automatic Demonstration at Versailles in December 1968, printed in 1970, which says that the language was developed in 1967 and 1968.&amp;lt;ref name=&amp;quot;aut1970&amp;quot;&amp;gt;N. G. de Bruijn, &amp;quot;The mathematical language AUTOMATH, its usage, and some of its extensions&amp;quot;, in &#039;&#039;Symposium on Automatic Demonstration&#039;&#039;, Lecture Notes in Mathematics 125, Springer, 1970, pp. 29–61. doi:10.1007/BFb0060623. Scan in the Automath Archive: https://automath.win.tue.nl/archive/pdf/aut002.pdf&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The aim was a way of writing entire mathematical theories so precisely that their correctness could be checked by formal operations on the text, without any appeal to meaning. If the checking is formal, a computer can do it.&amp;lt;ref name=&amp;quot;survey&amp;quot; /&amp;gt; The name means mathematics aided by an automaton.&amp;lt;ref name=&amp;quot;gn2022&amp;quot;&amp;gt;Herman Geuvers and Rob Nederpelt, &amp;quot;Characteristics of de Bruijn&#039;s early proof checker Automath&amp;quot;, &#039;&#039;Fundamenta Informaticae&#039;&#039; 185 (4), 2022, pp. 313–336. doi:10.3233/FI-222112. Preprint: https://arxiv.org/abs/2203.01173&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An Automath text is a &#039;&#039;&#039;book&#039;&#039;&#039;: a sequence of lines, each checked against the lines before it. A line either opens an assumption (a variable of a stated type), makes a definition (a name for an expression of a stated type), or introduces a primitive notion, which is how axioms enter. A theorem is a definition whose type is the proposition and whose body is the proof. Contexts are named by their last variable, so a later line can return to an earlier context without repeating it.&amp;lt;ref name=&amp;quot;gn2022&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Propositions as types ==&lt;br /&gt;
&lt;br /&gt;
Automath treated a proof of a proposition as an object whose type is that proposition. De Bruijn&#039;s survey traces this idea to Curry and Feys (1958) and to Howard (1969), and states that it appeared in his own 1968 work independently of them.&amp;lt;ref name=&amp;quot;survey&amp;quot; /&amp;gt; In the same survey he records the name &#039;&#039;&#039;proof irrelevance&#039;&#039;&#039; for the rule that any two proofs of one proposition are definitionally equal, introduced in a report of 1974.&amp;lt;ref name=&amp;quot;survey&amp;quot; /&amp;gt; Both ideas are part of Lean&#039;s logic: see [[Lean theorem prover/Explainers/Propositions as types|Propositions as types]] and [[Lean theorem prover/Foundations/Proof irrelevance and subsingleton elimination|Proof irrelevance and subsingleton elimination]].&lt;br /&gt;
&lt;br /&gt;
== The languages ==&lt;br /&gt;
&lt;br /&gt;
Automath was a family of languages, not one. The survey presents them in stages. A simple base language, PAL, admits typed variables and definitions; adding lambda abstraction gives &#039;&#039;&#039;AUT-68&#039;&#039;&#039;, long called simply Automath; a slightly stronger variant is &#039;&#039;&#039;AUT-QE&#039;&#039;&#039;. J. Zucker&#039;s &#039;&#039;&#039;AUT-PI&#039;&#039;&#039; extended AUT-68 in another direction and was easier to write. &#039;&#039;&#039;AUT-SL&#039;&#039;&#039; (&amp;quot;single line&amp;quot;) removed the restrictions on abstraction so that a whole book could be written as one expression, mainly to give the theory a clean form.&amp;lt;ref name=&amp;quot;survey&amp;quot; /&amp;gt; AUT-68 and AUT-QE were the languages most used.&amp;lt;ref name=&amp;quot;gn2022&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The survey reports that for these languages checking is decidable: a machine can always settle whether a line is correct. Doing so efficiently was harder, since the naive method of reducing expressions to normal form could repeat a great deal of work. Most of the work on the checking programs was done by I. Zandleven between 1971 and 1976.&amp;lt;ref name=&amp;quot;survey&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Landau&#039;s &#039;&#039;Grundlagen&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
The test of the system was a whole textbook. L. S. van Benthem Jutting translated Edmund Landau&#039;s &#039;&#039;Grundlagen der Analysis&#039;&#039; (1930), which constructs the number systems from the natural numbers up to the complex numbers, line by line into AUT-QE. A five-volume report of the translation appeared in 1976, and his experiences are in his doctoral thesis, written under de Bruijn and W. Peremans and completed at Eindhoven in 1977.&amp;lt;ref name=&amp;quot;survey&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;wiedijk2002&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;mgp&amp;quot;&amp;gt;Mathematics Genealogy Project, entry for Lambert S. van Benthem Jutting: Ph.D., Technische Universiteit Eindhoven, 1977, dissertation &amp;quot;Checking Landau&#039;s &#039;Grundlagen&#039; in the Automath System&amp;quot;, advisors N. G. de Bruijn and W. Peremans. https://www.mathgenealogy.org/id.php?id=63580&amp;lt;/ref&amp;gt; The thesis was published in 1979 as Mathematical Centre Tracts 83.&amp;lt;ref name=&amp;quot;cwi&amp;quot;&amp;gt;L. S. van Benthem Jutting, &#039;&#039;Checking Landau&#039;s &amp;quot;Grundlagen&amp;quot; in the Automath System&#039;&#039;, Mathematical Centre Tracts 83, Mathematisch Centrum, Amsterdam, 1979. ISBN 90-6196-147-5. Record and scan: https://ir.cwi.nl/pub/13104&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
De Bruijn explained the choice of book: Landau&#039;s steps do not grow larger towards the end, and the group wanted to show that Automath could handle mathematics written without it in mind, rather than mathematics rewritten to suit it.&amp;lt;ref name=&amp;quot;survey&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The files outlived the machines. By the early 1990s the original checkers no longer ran, because the language they were written in and the computer they ran on no longer existed, and the copies of the translation had become corrupted. Freek Wiedijk repaired them from the printed 1976 report and wrote a new checker for AUT-68 and AUT-QE. By his count the translation has 10,702 lines and is about 3.9 times the size of the German original, or 3.7 times when both files are compressed; he had earlier named that compressed ratio the &#039;&#039;&#039;de Bruijn factor&#039;&#039;&#039;. He reports that the two checkers of the 1970s took about 35 and 69 minutes over it, and his own 0.6 seconds on a 1 GHz machine.&amp;lt;ref name=&amp;quot;wiedijk2002&amp;quot;&amp;gt;Freek Wiedijk, &amp;quot;A new implementation of Automath&amp;quot;, &#039;&#039;Journal of Automated Reasoning&#039;&#039; 29 (3–4), 2002, pp. 365–387. doi:10.1023/A:1021983302516. Author&#039;s copy: https://www.cs.ru.nl/~freek/aut/aut.pdf&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== What it did not have ==&lt;br /&gt;
&lt;br /&gt;
Automath had no automation. Every proof term was written by hand, and the checker only confirmed it.&amp;lt;ref name=&amp;quot;bw2005&amp;quot;&amp;gt;Henk Barendregt and Freek Wiedijk, &amp;quot;The challenge of computer mathematics&amp;quot;, &#039;&#039;Philosophical Transactions of the Royal Society A&#039;&#039; 363 (1835), 2005, pp. 2351–2375. doi:10.1098/rsta.2005.1650. Author&#039;s copy: https://www.cs.ru.nl/~freek/pubs/rspaper.pdf&amp;lt;/ref&amp;gt; It had no inductive types, so basic types had to be introduced by axioms; and the large texts of the 1970s used classical logic.&amp;lt;ref name=&amp;quot;wiedijk-page&amp;quot;&amp;gt;Freek Wiedijk, &amp;quot;Automath&amp;quot; (notes accompanying the aut checker). https://www.cs.ru.nl/~freek/aut/&amp;lt;/ref&amp;gt; Wiedijk writes that the project was very active in the 1970s and ended when its funding stopped.&amp;lt;ref name=&amp;quot;wiedijk2002&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== What lasted ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;De Bruijn indices.&#039;&#039;&#039; In 1972 de Bruijn proposed writing a bound variable not by a name but by a number counting how many binders lie between the variable and the one that binds it. Renaming bound variables causes considerable trouble in programs that manipulate formulas, and with this notation it never arises. The paper claims that its notation is good for machines and for reasoning about the calculus, but not that it is easy for human readers, and a section of it applies the notation to Automath.&amp;lt;ref name=&amp;quot;nameless&amp;quot;&amp;gt;N. G. de Bruijn, &amp;quot;Lambda calculus notation with nameless dummies, a tool for automatic formula manipulation, with application to the Church-Rosser theorem&amp;quot;, &#039;&#039;Indagationes Mathematicae&#039;&#039; 34 (= &#039;&#039;Proceedings KNAW&#039;&#039; A 75), 1972, pp. 381–392. doi:10.1016/1385-7258(72)90034-0. Reprint from &#039;&#039;Selected Papers on Automath&#039;&#039; in the Eindhoven repository: https://alexandria.tue.nl/repository/freearticles/597619.pdf&amp;lt;/ref&amp;gt; Lean represents a bound variable in exactly this way: in its type of expressions, the constructor for a bound variable carries a de Bruijn index.&amp;lt;ref name=&amp;quot;leanexpr&amp;quot;&amp;gt;Lean 4 source, &amp;lt;code&amp;gt;src/Lean/Expr.lean&amp;lt;/code&amp;gt;, documentation of &amp;lt;code&amp;gt;Expr.bvar&amp;lt;/code&amp;gt;, version 4.34.1. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/Expr.lean&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The de Bruijn criterion.&#039;&#039;&#039; A proof may run to megabytes, yet the program that checks it can be small enough for a person to inspect. Barendregt and Wiedijk call a system that allows its proofs to be checked independently by such a small program one that satisfies the &#039;&#039;&#039;de Bruijn criterion&#039;&#039;&#039;.&amp;lt;ref name=&amp;quot;bw2005&amp;quot; /&amp;gt; The name is later than Automath; the practice it names is Automath&#039;s. Lean&#039;s version of it is described at [[Lean theorem prover/Explainers/The small trusted core|The small trusted core]] and [[Lean theorem prover/System/Proof export and independent checkers|Proof export and independent checkers]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The line to the Calculus of Constructions.&#039;&#039;&#039; Geuvers and Nederpelt state that Automath&#039;s goals and syntactic ideas inspired Thierry Coquand and Gérard Huet to develop the Calculus of Constructions, the ancestor of the logic Lean uses.&amp;lt;ref name=&amp;quot;gn2022&amp;quot; /&amp;gt; That line is followed at [[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]].&lt;br /&gt;
&lt;br /&gt;
The standard collection of the project&#039;s papers, including parts of van Benthem Jutting&#039;s thesis and de Bruijn&#039;s survey, is &#039;&#039;Selected Papers on Automath&#039;&#039; (1994).&amp;lt;ref name=&amp;quot;sp1994&amp;quot;&amp;gt;R. P. Nederpelt, J. H. Geuvers and R. C. de Vrijer (eds.), &#039;&#039;Selected Papers on Automath&#039;&#039;, Studies in Logic and the Foundations of Mathematics 133, North-Holland, Amsterdam, 1994. ISBN 0-444-89822-0. Publisher&#039;s page with contents: https://shop.elsevier.com/books/selected-papers-on-automath/nederpelt/978-0-444-89822-7&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
Provenance: de Bruijn&#039;s 1980 survey, Wiedijk&#039;s 2002 paper, Barendregt and Wiedijk&#039;s 2005 paper and Geuvers and Nederpelt&#039;s 2022 paper were read for this page; the 1970 and 1972 papers were read in their opening pages only, in scans. The published form of van Benthem Jutting&#039;s thesis was read in its title page, contents, de Bruijn&#039;s preface and introduction. The 1994 collection was not opened; its details come from the publisher&#039;s record.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]]&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>PMA Publisher</name></author>
	</entry>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/System/Monads_and_do-notation&amp;diff=6797</id>
		<title>Lean theorem prover/System/Monads and do-notation</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/System/Monads_and_do-notation&amp;diff=6797"/>
		<updated>2026-10-15T19:35:22Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Monads and do-notation}}&lt;br /&gt;
{{Plebeian|Lean theorem prover/Explainers/Programs and proofs in one language}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
&lt;br /&gt;
Lean is a purely functional language: a function&#039;s result depends only on its arguments,&lt;br /&gt;
and evaluating it changes nothing else. Programs still need failure, state, input and output.&lt;br /&gt;
Lean represents these &#039;&#039;&#039;effects&#039;&#039;&#039; as values, using &#039;&#039;&#039;monads&#039;&#039;&#039;, and provides&lt;br /&gt;
&#039;&#039;&#039;do-notation&#039;&#039;&#039; so that programs using them can be written in an imperative style, with&lt;br /&gt;
sequencing, mutable local variables, loops and early return. This page shows the&lt;br /&gt;
&amp;lt;code&amp;gt;Monad&amp;lt;/code&amp;gt; class, the monad &amp;lt;code&amp;gt;IO&amp;lt;/code&amp;gt;, and the features of do-notation, and&lt;br /&gt;
then prints what Lean 4.34.1 turns a &amp;lt;code&amp;gt;do&amp;lt;/code&amp;gt; block into. The result is an ordinary&lt;br /&gt;
term, which is why programs written this way can still be reasoned about.&lt;br /&gt;
&lt;br /&gt;
== The Monad class ==&lt;br /&gt;
&lt;br /&gt;
A monad is a type constructor &amp;lt;code&amp;gt;m&amp;lt;/code&amp;gt;, such as &amp;lt;code&amp;gt;Option&amp;lt;/code&amp;gt; or&lt;br /&gt;
&amp;lt;code&amp;gt;IO&amp;lt;/code&amp;gt;, with two operations. &amp;lt;code&amp;gt;pure&amp;lt;/code&amp;gt; makes a value into a computation that&lt;br /&gt;
has no effect, and &amp;lt;code&amp;gt;bind&amp;lt;/code&amp;gt;, written &amp;lt;code&amp;gt;&amp;gt;&amp;gt;=&amp;lt;/code&amp;gt;, runs one computation and&lt;br /&gt;
passes its result to the next.&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 @pure&lt;br /&gt;
#check @bind&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;@pure : {f : Type u_1 → Type u_2} → [self : Pure f] → {α : Type u_1} → α → f α&lt;br /&gt;
@bind : {m : Type u_1 → Type u_2} → [self : Bind m] → {α β : Type u_1} → m α → (α → m β) → m β&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The class &amp;lt;code&amp;gt;Monad&amp;lt;/code&amp;gt; brings these together, as a&lt;br /&gt;
[[Lean theorem prover/System/Type classes and instance resolution|type class]], with the&lt;br /&gt;
related classes &amp;lt;code&amp;gt;Functor&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Applicative&amp;lt;/code&amp;gt;. The reference manual&lt;br /&gt;
notes that these classes follow the use of functors and monads in programming, which is&lt;br /&gt;
narrower than the general mathematical notion.&amp;lt;ref name=&amp;quot;rm-monads&amp;quot;&amp;gt;&amp;quot;Functors, Monads and do-Notation&amp;quot;, chapter of &#039;&#039;The Lean Language Reference&#039;&#039; (edition covering Lean 4.34.0), introduction and section 18.3 &amp;quot;Syntax&amp;quot;. [https://lean-lang.org/doc/reference/4.34.0/Functors___-Monads-and--do--Notation/ lean-lang.org/doc/reference/4.34.0/Functors___-Monads-and--do--Notation/]; [https://lean-lang.org/doc/reference/4.34.0/Functors___-Monads-and--do--Notation/Syntax/ …/Syntax/]&amp;lt;/ref&amp;gt;&lt;br /&gt;
An instance is not required to obey the monad laws; the separate class&lt;br /&gt;
&amp;lt;code&amp;gt;LawfulMonad&amp;lt;/code&amp;gt; records that it does, and proofs about monadic programs use&lt;br /&gt;
it.&amp;lt;ref name=&amp;quot;rm-monads&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;do&amp;quot;&amp;gt;Sebastian Ullrich and Leonardo de Moura, &amp;quot;‘do’ Unchained: Embracing Local Imperativity in a Purely Functional Language (Functional Pearl)&amp;quot;, &#039;&#039;Proceedings of the ACM on Programming Languages&#039;&#039; 6 (ICFP), article 109, August 2022, 28 pp. doi:[https://doi.org/10.1145/3547640 10.1145/3547640]; author&#039;s copy [https://lean-lang.org/papers/do.pdf lean-lang.org/papers/do.pdf].&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Option&amp;lt;/code&amp;gt; is the simplest useful case. A computation of type &amp;lt;code&amp;gt;Option&lt;br /&gt;
α&amp;lt;/code&amp;gt; either produces a value (&amp;lt;code&amp;gt;some a&amp;lt;/code&amp;gt;) or fails (&amp;lt;code&amp;gt;none&amp;lt;/code&amp;gt;), and&lt;br /&gt;
&amp;lt;code&amp;gt;bind&amp;lt;/code&amp;gt; stops at the first failure.&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 safeDiv (a b : Nat) : Option Nat :=&lt;br /&gt;
  if b == 0 then none else some (a / b)&lt;br /&gt;
&lt;br /&gt;
def compute (a b c : Nat) : Option Nat := do&lt;br /&gt;
  let x ← safeDiv a b&lt;br /&gt;
  let y ← safeDiv x c&lt;br /&gt;
  return x + y&lt;br /&gt;
&lt;br /&gt;
#eval compute 100 5 2&lt;br /&gt;
#eval compute 100 0 2&lt;br /&gt;
&lt;br /&gt;
example (a b c : Nat) :&lt;br /&gt;
    compute a b c =&lt;br /&gt;
      (safeDiv a b &amp;gt;&amp;gt;= fun x =&amp;gt; safeDiv x c &amp;gt;&amp;gt;= fun y =&amp;gt; pure (x + y)) := rfl&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The two evaluations print &amp;lt;code&amp;gt;some 30&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;none&amp;lt;/code&amp;gt;. The&lt;br /&gt;
&amp;lt;code&amp;gt;example&amp;lt;/code&amp;gt; states what the &amp;lt;code&amp;gt;do&amp;lt;/code&amp;gt; block means, and &amp;lt;code&amp;gt;rfl&amp;lt;/code&amp;gt;&lt;br /&gt;
proves it: the block is, by definition, a chain of &amp;lt;code&amp;gt;bind&amp;lt;/code&amp;gt;s. The basic rules are&lt;br /&gt;
few. A block consisting of one expression is that expression. &amp;lt;code&amp;gt;let x ← e&amp;lt;/code&amp;gt;&lt;br /&gt;
followed by the rest becomes &amp;lt;code&amp;gt;e &amp;gt;&amp;gt;= fun x =&amp;gt; …&amp;lt;/code&amp;gt;; an expression whose result is&lt;br /&gt;
not named becomes &amp;lt;code&amp;gt;e &amp;gt;&amp;gt;= fun () =&amp;gt; …&amp;lt;/code&amp;gt;; and &amp;lt;code&amp;gt;let x := e&amp;lt;/code&amp;gt; is an ordinary&lt;br /&gt;
local definition.&amp;lt;ref name=&amp;quot;fpil-do&amp;quot;&amp;gt;David Thrane Christiansen, &#039;&#039;Functional Programming in Lean&#039;&#039;, online book (code tested with Lean 4.33.0), section 4.4 &amp;quot;&amp;lt;code&amp;gt;do&amp;lt;/code&amp;gt;-Notation for Monads&amp;quot;. [https://lean-lang.org/functional_programming_in_lean/Monads/do--Notation-for-Monads/ lean-lang.org/functional_programming_in_lean/Monads/do--Notation-for-Monads/]&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;rm-monads&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;nested action&#039;&#039;&#039; saves naming a result used once: &amp;lt;code&amp;gt;(← e)&amp;lt;/code&amp;gt; inside an&lt;br /&gt;
expression is lifted out and bound just before the statement that contains it, within the&lt;br /&gt;
enclosing &amp;lt;code&amp;gt;do&amp;lt;/code&amp;gt; block.&amp;lt;ref name=&amp;quot;do&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;
def halfPlusOne (a : Nat) : Option Nat := do&lt;br /&gt;
  return (← safeDiv a 2) + 1&lt;br /&gt;
&lt;br /&gt;
#eval halfPlusOne 10&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This prints &amp;lt;code&amp;gt;some 6&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== IO ==&lt;br /&gt;
&lt;br /&gt;
Input and output are effects of the same kind. Lean prints the definition of&lt;br /&gt;
&amp;lt;code&amp;gt;IO&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;
#print IO&lt;br /&gt;
#print EIO&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;@[reducible] def IO : Type → Type :=&lt;br /&gt;
EIO IO.Error&lt;br /&gt;
def EIO : Type → Type → Type :=&lt;br /&gt;
fun ε α =&amp;gt; EST ε IO.RealWorld α&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An &amp;lt;code&amp;gt;IO&amp;lt;/code&amp;gt; action is a computation that may fail with an &amp;lt;code&amp;gt;IO.Error&amp;lt;/code&amp;gt; and&lt;br /&gt;
that takes and returns a token whose type is built from &amp;lt;code&amp;gt;IO.RealWorld&amp;lt;/code&amp;gt; (in 4.34.1,&lt;br /&gt;
&amp;lt;code&amp;gt;Void IO.RealWorld&amp;lt;/code&amp;gt;).&amp;lt;ref name=&amp;quot;fpil-io&amp;quot; /&amp;gt; Christiansen&#039;s&lt;br /&gt;
&#039;&#039;Functional Programming in Lean&#039;&#039; explains the device: an action receives a token&lt;br /&gt;
standing for the world and returns the changed world, and this is safe as long as no token&lt;br /&gt;
is used twice.&amp;lt;ref name=&amp;quot;fpil-io&amp;quot;&amp;gt;David Thrane Christiansen, &#039;&#039;Functional Programming in Lean&#039;&#039;, online book (code tested with Lean 4.33.0), section 4.5 &amp;quot;The IO Monad&amp;quot;. [https://lean-lang.org/functional_programming_in_lean/Monads/The-IO-Monad/ lean-lang.org/functional_programming_in_lean/Monads/The-IO-Monad/]&amp;lt;/ref&amp;gt;&lt;br /&gt;
Seen from inside the logic, an &amp;lt;code&amp;gt;IO&amp;lt;/code&amp;gt; action is a value like any other; seen from&lt;br /&gt;
outside, it is a set of instructions that the run-time system carries out (see&lt;br /&gt;
[[Lean theorem prover/System/The compiler and runtime|the compiler and runtime]]). The&lt;br /&gt;
metaprogramming monads described in&lt;br /&gt;
[[Lean theorem prover/System/Metaprogramming in Lean|metaprogramming in Lean]] are built on&lt;br /&gt;
the same base.&lt;br /&gt;
&lt;br /&gt;
== Mutable variables, loops and early return ==&lt;br /&gt;
&lt;br /&gt;
Haskell&#039;s do-notation provides sequencing and little more. Ullrich and de Moura&#039;s paper&lt;br /&gt;
&amp;quot;‘do’ Unchained&amp;quot; extends it with three features from imperative languages: local mutable&lt;br /&gt;
variables, early return, and &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; loops with &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt;. The paper gives translation rules from each feature back to pure&lt;br /&gt;
code, implements them in Lean 4, and proves in Lean that the rules preserve the meaning of&lt;br /&gt;
the program with respect to a simple semantics.&amp;lt;ref name=&amp;quot;do&amp;quot; /&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 sumUntilZero (xs : List Nat) : Nat := Id.run do&lt;br /&gt;
  let mut total := 0&lt;br /&gt;
  for x in xs do&lt;br /&gt;
    if x == 0 then break&lt;br /&gt;
    total := total + x&lt;br /&gt;
  return total&lt;br /&gt;
&lt;br /&gt;
#eval sumUntilZero [3, 4, 0, 10]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This prints &amp;lt;code&amp;gt;7&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Id&amp;lt;/code&amp;gt; is the monad with no effect, and&lt;br /&gt;
&amp;lt;code&amp;gt;Id.run&amp;lt;/code&amp;gt; extracts the result, so &amp;lt;code&amp;gt;sumUntilZero&amp;lt;/code&amp;gt; is a pure function&lt;br /&gt;
written in imperative style. A mutable variable is local to its &amp;lt;code&amp;gt;do&amp;lt;/code&amp;gt; block and&lt;br /&gt;
cannot be changed from outside it.&amp;lt;ref name=&amp;quot;rm-monads&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Early return leaves the whole block, from inside a loop if need be:&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;
def findBig (xs : List Nat) : Option Nat := Id.run do&lt;br /&gt;
  for x in xs do&lt;br /&gt;
    if x &amp;gt; 10 then return some x&lt;br /&gt;
  return none&lt;br /&gt;
&lt;br /&gt;
#eval findBig [3, 12, 40]&lt;br /&gt;
#eval findBig [1, 2]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The results are &amp;lt;code&amp;gt;some 12&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;none&amp;lt;/code&amp;gt;. The same features work in&lt;br /&gt;
&amp;lt;code&amp;gt;IO&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;
def report (lines : List String) : IO Unit := do&lt;br /&gt;
  let mut count := 0&lt;br /&gt;
  for line in lines do&lt;br /&gt;
    if line.isEmpty then continue&lt;br /&gt;
    count := count + 1&lt;br /&gt;
    IO.println s!&amp;quot;{count}: {line}&amp;quot;&lt;br /&gt;
  IO.println s!&amp;quot;{count} non-empty lines&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#eval report [&amp;quot;alpha&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;beta&amp;quot;]&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;1: alpha&lt;br /&gt;
2: beta&lt;br /&gt;
2 non-empty lines&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== How they are translated ==&lt;br /&gt;
&lt;br /&gt;
In the paper&#039;s rules, each feature becomes a monad transformer wrapped around the block.&lt;br /&gt;
A mutable variable becomes the state of a &amp;lt;code&amp;gt;StateT&amp;lt;/code&amp;gt; layer, initialised with its&lt;br /&gt;
first value; a reassignment sets that state. An early return becomes an exception in an&lt;br /&gt;
&amp;lt;code&amp;gt;ExceptT&amp;lt;/code&amp;gt; layer, caught at the edge of the block. A &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; loop becomes&lt;br /&gt;
a call to a loop function over the collection, with &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt; as two further exceptions, one caught outside the loop and one around&lt;br /&gt;
its body.&amp;lt;ref name=&amp;quot;do&amp;quot; /&amp;gt; The reference manual describes the implementation in the same&lt;br /&gt;
terms: the effects are produced by transforming the whole block &amp;quot;in a manner akin to monad&lt;br /&gt;
transformers&amp;quot;, not by rewriting each statement locally, and a loop requires the collection&#039;s&lt;br /&gt;
type to implement the class &amp;lt;code&amp;gt;ForIn&amp;lt;/code&amp;gt;.&amp;lt;ref name=&amp;quot;rm-monads&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean&#039;s own implementation differs in its details from the paper&#039;s reference&lt;br /&gt;
rules.&amp;lt;ref name=&amp;quot;do&amp;quot; /&amp;gt; Since version 4.32.0, the default is a new elaborator for&lt;br /&gt;
&amp;lt;code&amp;gt;do&amp;lt;/code&amp;gt;; the earlier one is still available with &amp;lt;code&amp;gt;set_option&lt;br /&gt;
backward.do.legacy true&amp;lt;/code&amp;gt;.&amp;lt;ref name=&amp;quot;rn432&amp;quot;&amp;gt;&amp;quot;Lean 4.32.0&amp;quot;, in &amp;quot;Release Notes&amp;quot;, &#039;&#039;The Lean Language Reference&#039;&#039; (edition covering Lean 4.34.0), Highlights and Language sections. [https://lean-lang.org/doc/reference/4.34.0/releases/v4.32.0/ lean-lang.org/doc/reference/4.34.0/releases/v4.32.0/]&amp;lt;/ref&amp;gt;&lt;br /&gt;
What it produces can be printed.&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;
#print sumUntilZero&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;def sumUntilZero : List Nat → Nat :=&lt;br /&gt;
fun xs =&amp;gt;&lt;br /&gt;
  (have total := 0;&lt;br /&gt;
    do&lt;br /&gt;
    let __s ←&lt;br /&gt;
      forIn xs total fun x __s =&amp;gt;&lt;br /&gt;
          have total := __s;&lt;br /&gt;
          if (x == 0) = true then pure (ForInStep.done total)&lt;br /&gt;
          else&lt;br /&gt;
            have total := total + x;&lt;br /&gt;
            pure (ForInStep.yield total)&lt;br /&gt;
    have total : Nat := __s&lt;br /&gt;
    pure total).run&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The loop has become a call to &amp;lt;code&amp;gt;forIn&amp;lt;/code&amp;gt;, the method of &amp;lt;code&amp;gt;ForIn&amp;lt;/code&amp;gt;. The&lt;br /&gt;
mutable variable &amp;lt;code&amp;gt;total&amp;lt;/code&amp;gt; is the loop&#039;s state: each pass of the body receives it&lt;br /&gt;
as &amp;lt;code&amp;gt;__s&amp;lt;/code&amp;gt; and returns the new value. &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; has become&lt;br /&gt;
&amp;lt;code&amp;gt;ForInStep.done&amp;lt;/code&amp;gt;, which tells &amp;lt;code&amp;gt;forIn&amp;lt;/code&amp;gt; to stop, and the normal end of&lt;br /&gt;
the body has become &amp;lt;code&amp;gt;ForInStep.yield&amp;lt;/code&amp;gt;, which tells it to go on. &amp;quot;Mutation&amp;quot; is&lt;br /&gt;
rebinding a name with &amp;lt;code&amp;gt;have&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;
#print findBig&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;def findBig : List Nat → Option Nat :=&lt;br /&gt;
fun xs =&amp;gt;&lt;br /&gt;
  (do&lt;br /&gt;
      let __s ←&lt;br /&gt;
        forIn xs (none, ()) fun x __s =&amp;gt;&lt;br /&gt;
            if x &amp;gt; 10 then pure (ForInStep.done (some (some x), ())) else pure (ForInStep.yield (none, ()))&lt;br /&gt;
      have __r : Option (Option Nat) × Unit := __s&lt;br /&gt;
      match __r.fst with&lt;br /&gt;
        | some r =&amp;gt; pure r&lt;br /&gt;
        | none =&amp;gt; pure none).run&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here the early return travels in the loop&#039;s state. The first component is&lt;br /&gt;
&amp;lt;code&amp;gt;none&amp;lt;/code&amp;gt; while the loop runs normally and &amp;lt;code&amp;gt;some v&amp;lt;/code&amp;gt; once&lt;br /&gt;
&amp;lt;code&amp;gt;return v&amp;lt;/code&amp;gt; has been executed; after the loop, a &amp;lt;code&amp;gt;match&amp;lt;/code&amp;gt; either returns&lt;br /&gt;
that value or continues with the rest of the block. This is the exception path of the&lt;br /&gt;
paper&#039;s rules, encoded directly.&lt;br /&gt;
&lt;br /&gt;
== Why it matters for proofs ==&lt;br /&gt;
&lt;br /&gt;
The output of the translation is an ordinary Lean term built from &amp;lt;code&amp;gt;bind&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;pure&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;forIn&amp;lt;/code&amp;gt; and local definitions. Nothing about it is special to&lt;br /&gt;
the Lean kernel, and a theorem about a &amp;lt;code&amp;gt;do&amp;lt;/code&amp;gt; program is a theorem about that term.&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 sumUntilZero_nil : sumUntilZero [] = 0 := rfl&lt;br /&gt;
&lt;br /&gt;
example : sumUntilZero [1, 2, 3, 0, 5] = 6 := by decide&lt;br /&gt;
&lt;br /&gt;
theorem findBig_nil : findBig [] = none := rfl&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All three are accepted. Ullrich and de Moura prove more general facts in the same way, for&lt;br /&gt;
example that a block with two nested &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; loops and an early return equals a&lt;br /&gt;
search function defined by recursion, for every monad satisfying &amp;lt;code&amp;gt;LawfulMonad&amp;lt;/code&amp;gt;,&lt;br /&gt;
using induction and the simplifier.&amp;lt;ref name=&amp;quot;do&amp;quot; /&amp;gt; Local imperativity is therefore a&lt;br /&gt;
matter of notation. The programs remain pure functions, and the reasoning about them is the&lt;br /&gt;
reasoning used for any other Lean definition.&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/History/Automath|Automath]] begins the history, with the first system&lt;br /&gt;
for checking mathematics by computer. Within this section, the page on&lt;br /&gt;
[[Lean theorem prover/System/Syntax extension and hygienic macros|syntax&lt;br /&gt;
extension and hygienic macros]] shows how notation of this kind is defined.&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>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/System/Proof_export_and_independent_checkers&amp;diff=6796</id>
		<title>Lean theorem prover/System/Proof export and independent checkers</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/System/Proof_export_and_independent_checkers&amp;diff=6796"/>
		<updated>2026-10-15T19:35:20Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Proof export and independent checkers}}&lt;br /&gt;
{{Plebeian|Lean theorem prover/Explainers/Checking a proof again later}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
&lt;br /&gt;
When a Lean source file is elaborated, the Lean kernel checks every definition and theorem&lt;br /&gt;
before it enters Lean&#039;s environment, its table of definitions and theorems. That first check&lt;br /&gt;
happens inside the same program that parsed the file, ran its tactics and executed whatever&lt;br /&gt;
code the file and its imports contain. This page is about checking again: listing the axioms&lt;br /&gt;
a theorem depends on, replaying compiled results through the Lean kernel with&lt;br /&gt;
&amp;lt;code&amp;gt;leanchecker&amp;lt;/code&amp;gt;, exporting proofs to a file, and checking that file with checkers&lt;br /&gt;
written independently of Lean. For each, it says what the check guards against and what it&lt;br /&gt;
does not. The examples were run with Lean 4.34.1.&lt;br /&gt;
&lt;br /&gt;
== What the first check leaves open ==&lt;br /&gt;
&lt;br /&gt;
Lean&#039;s reference manual sets out an escalating series of checks and distinguishes two&lt;br /&gt;
situations. In the &#039;&#039;&#039;honest&#039;&#039;&#039; case the author is trying to produce a valid proof and the&lt;br /&gt;
risks are mistakes and bugs. In the &#039;&#039;&#039;malicious&#039;&#039;&#039; case someone is trying to mislead: by&lt;br /&gt;
exploiting bugs, by code that circumvents the system, or by compromising the machine; the&lt;br /&gt;
manual counts unreviewed proofs generated by AI in this case. It also separates two&lt;br /&gt;
questions: whether a theorem has a valid proof, and what the theorem&#039;s statement&lt;br /&gt;
means.&amp;lt;ref name=&amp;quot;rm-vp&amp;quot;&amp;gt;&amp;quot;Validating a Lean Proof&amp;quot;, a chapter of &#039;&#039;The Lean Language Reference&#039;&#039; (edition covering Lean 4.34.0), with its sections &amp;quot;The Blue Double Check Marks&amp;quot;, &amp;quot;Printing Axioms&amp;quot;, &amp;quot;Re-Checking Proofs with lean4checker&amp;quot;, &amp;quot;Gold Standard: comparator and external checkers&amp;quot;, &amp;quot;Remaining Issues&amp;quot; and &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;
&lt;br /&gt;
The ordinary check, a theorem accepted in the editor or a Lake build of its Lean module&lt;br /&gt;
without errors or warnings, protects against incomplete proofs, an explicit&lt;br /&gt;
&amp;lt;code&amp;gt;sorry&amp;lt;/code&amp;gt; in the theorem itself and honest bugs in tactics and other metaprograms. It assumes that the statement says&lt;br /&gt;
what is intended, that the authors of imported libraries are honest, and that no unsound&lt;br /&gt;
axiom has been declared and used.&amp;lt;ref name=&amp;quot;rm-vp&amp;quot; /&amp;gt; The checks below remove some of these&lt;br /&gt;
assumptions.&lt;br /&gt;
&lt;br /&gt;
== Listing the axioms ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;#print axioms&amp;lt;/code&amp;gt; lists every axiom a theorem depends on, directly or through the&lt;br /&gt;
theorems it uses.&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;
theorem two_add_two : 2 + 2 = 4 := rfl&lt;br /&gt;
&lt;br /&gt;
theorem em_or (p : Prop) : p ∨ ¬p := Classical.em p&lt;br /&gt;
&lt;br /&gt;
theorem unfinished : 2 + 2 = 5 := sorry&lt;br /&gt;
&lt;br /&gt;
#print axioms two_add_two&lt;br /&gt;
#print axioms em_or&lt;br /&gt;
#print axioms unfinished&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean warns &amp;lt;code&amp;gt;declaration uses `sorry`&amp;lt;/code&amp;gt; at the third theorem, and 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;&#039;two_add_two&#039; does not depend on any axioms&lt;br /&gt;
&#039;em_or&#039; depends on axioms: [propext, Classical.choice, Quot.sound]&lt;br /&gt;
&#039;unfinished&#039; depends on axioms: [sorryAx]&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;propext&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Classical.choice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Quot.sound&amp;lt;/code&amp;gt; are Lean&#039;s&lt;br /&gt;
three standard axioms (see [[Lean theorem prover/Foundations/The three axioms|the three&lt;br /&gt;
axioms]]). &amp;lt;code&amp;gt;sorryAx&amp;lt;/code&amp;gt; marks a gap: a &amp;lt;code&amp;gt;sorry&amp;lt;/code&amp;gt; or an incomplete proof&lt;br /&gt;
somewhere in the dependencies, which the editor&#039;s mark next to the theorem does not&lt;br /&gt;
reveal.&amp;lt;ref name=&amp;quot;rm-vp&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The command also exposes proofs that rest on running compiled code. The page on&lt;br /&gt;
[[Lean theorem prover/System/The compiler and runtime|the compiler and runtime]] defines a&lt;br /&gt;
function whose compiled code, supplied through &amp;lt;code&amp;gt;@[implemented_by]&amp;lt;/code&amp;gt;, disagrees&lt;br /&gt;
with its definition. A tactic that trusts compiled code can then prove a falsehood:&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;
theorem ident_five : ident 5 = 5 := rfl&lt;br /&gt;
&lt;br /&gt;
theorem ident_five_zero : ident 5 = 0 := by decide +native&lt;br /&gt;
&lt;br /&gt;
theorem oops : False := by&lt;br /&gt;
  have h1 := ident_five&lt;br /&gt;
  have h2 := ident_five_zero&lt;br /&gt;
  omega&lt;br /&gt;
&lt;br /&gt;
#print axioms oops&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Everything is accepted, and the last line 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;&#039;oops&#039; depends on axioms: [propext, Quot.sound, ident_five_zero._native.decide.ax_1_1]&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;decide +native&amp;lt;/code&amp;gt; evaluated the claim with compiled code and admitted the result&lt;br /&gt;
as a new axiom. Since Lean 4.29.0 each such computation has its own axiom, named after the&lt;br /&gt;
theorem that made it; before that, all of them appeared as one axiom,&lt;br /&gt;
&amp;lt;code&amp;gt;Lean.trustCompiler&amp;lt;/code&amp;gt;.&amp;lt;ref name=&amp;quot;rm-vp&amp;quot; /&amp;gt; Any axiom other than the standard three&lt;br /&gt;
means that the proof depends on something the Lean kernel did not check.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;#print axioms&amp;lt;/code&amp;gt; reads Lean&#039;s environment as it stands. It cannot detect a theorem&lt;br /&gt;
that entered that table without being checked at all.&lt;br /&gt;
&lt;br /&gt;
== Replaying through the Lean kernel: leanchecker ==&lt;br /&gt;
&lt;br /&gt;
Lean&#039;s environment is held in memory while a file is processed and saved, Lean module by&lt;br /&gt;
Lean module, in &amp;lt;code&amp;gt;.olean&amp;lt;/code&amp;gt; files. Code run during elaboration has the access it&lt;br /&gt;
needs to add a constant to that table without passing it to the Lean kernel, and Lean has&lt;br /&gt;
a debugging option, &amp;lt;code&amp;gt;debug.skipKernelTC&amp;lt;/code&amp;gt;, that skips the check.&amp;lt;ref name=&amp;quot;rm-vp&amp;quot; /&amp;gt; The&lt;br /&gt;
following file uses it together with the false tactic from [[Lean theorem prover/System/Metaprogramming in Lean|metaprogramming in&lt;br /&gt;
Lean]], which the Lean kernel would reject.&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 Elab Tactic&lt;br /&gt;
&lt;br /&gt;
elab &amp;quot;cheat&amp;quot; : tactic =&amp;gt; do&lt;br /&gt;
  let goal ← getMainGoal&lt;br /&gt;
  goal.assign (mkConst ``True.intro)&lt;br /&gt;
  replaceMainGoal []&lt;br /&gt;
&lt;br /&gt;
set_option debug.skipKernelTC true in&lt;br /&gt;
theorem bad : False := by cheat&lt;br /&gt;
&lt;br /&gt;
#print axioms bad&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the library &amp;lt;code&amp;gt;Hack&amp;lt;/code&amp;gt; of a small Lake package, it compiles without error, and the&lt;br /&gt;
axiom check reports nothing amiss:&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;ℹ [2/3] Built Hack (868ms)&lt;br /&gt;
info: Hack.lean:12:0: &#039;bad&#039; does not depend on any axioms&lt;br /&gt;
Build completed successfully (3 jobs).&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The reference manual names &amp;lt;code&amp;gt;debug.skipKernelTC&amp;lt;/code&amp;gt; as an example of code whose only&lt;br /&gt;
purpose is to circumvent the system.&amp;lt;ref name=&amp;quot;rm-vp&amp;quot; /&amp;gt; The second check exists for this&lt;br /&gt;
case. &#039;&#039;&#039;&amp;lt;code&amp;gt;leanchecker&amp;lt;/code&amp;gt;&#039;&#039;&#039;, which is part of the Lean 4.34.1 toolchain, reads the&lt;br /&gt;
&amp;lt;code&amp;gt;.olean&amp;lt;/code&amp;gt; files and replays every definition and theorem in them through the Lean&lt;br /&gt;
kernel.&amp;lt;ref name=&amp;quot;rm-bt&amp;quot;&amp;gt;&amp;quot;Build Tools and Distribution&amp;quot;, a chapter of &#039;&#039;The Lean Language Reference&#039;&#039; (edition covering Lean 4.34.0). [https://lean-lang.org/doc/reference/4.34.0/Build-Tools-and-Distribution/ lean-lang.org/doc/reference/4.34.0/Build-Tools-and-Distribution/]&amp;lt;/ref&amp;gt;&lt;br /&gt;
Since Lean 4.28.0 the program is the external checker &amp;lt;code&amp;gt;lean4checker&amp;lt;/code&amp;gt;, shipped with&lt;br /&gt;
every toolchain;&amp;lt;ref name=&amp;quot;rn428&amp;quot;&amp;gt;&amp;quot;Lean 4.28.0&amp;quot;, in &amp;quot;Release Notes&amp;quot;, &#039;&#039;The Lean Language Reference&#039;&#039; (edition covering Lean 4.34.0), section &amp;quot;External Checker&amp;quot;. [https://lean-lang.org/doc/reference/4.34.0/releases/v4.28.0/ lean-lang.org/doc/reference/4.34.0/releases/v4.28.0/]&amp;lt;/ref&amp;gt;&lt;br /&gt;
the reference manual&#039;s chapter on validating proofs still calls it by that&lt;br /&gt;
name.&amp;lt;ref name=&amp;quot;rm-vp&amp;quot; /&amp;gt; Run as &amp;lt;code&amp;gt;lake env leanchecker --fresh&lt;br /&gt;
Hack&amp;lt;/code&amp;gt;, it reports:&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;uncaught exception: while replaying declaration &#039;bad&#039;:&lt;br /&gt;
(kernel) declaration type mismatch, &#039;bad&#039; has type&lt;br /&gt;
  True&lt;br /&gt;
but it is expected to have type&lt;br /&gt;
  False&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and exits with a failure. With &amp;lt;code&amp;gt;--fresh&amp;lt;/code&amp;gt; it replays the named Lean module and&lt;br /&gt;
everything it imports into an empty table; without it, it replays only the Lean module&#039;s own&lt;br /&gt;
constants on top of its imports.&amp;lt;ref name=&amp;quot;rm-vp&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;l4l&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
According to the reference manual, this check protects against bugs in Lean&#039;s handling of&lt;br /&gt;
the Lean kernel&#039;s state, for instance in parallel processing or imports, and against&lt;br /&gt;
metaprograms that deliberately bypass that state. It trusts that the &amp;lt;code&amp;gt;.olean&amp;lt;/code&amp;gt;&lt;br /&gt;
files are well formed, and a crafted file could defeat it. It also runs after the code under&lt;br /&gt;
test has been compiled, and such code, the manual warns, can perform arbitrary actions when&lt;br /&gt;
run; a determined attacker can compromise the machine before any check takes&lt;br /&gt;
place.&amp;lt;ref name=&amp;quot;rm-vp&amp;quot; /&amp;gt; And it uses the same Lean kernel, so it cannot find a bug in the&lt;br /&gt;
Lean kernel itself.&lt;br /&gt;
&lt;br /&gt;
== Exporting proofs ==&lt;br /&gt;
&lt;br /&gt;
The next step separates the proof from the program that produced it. &#039;&#039;&#039;lean4export&#039;&#039;&#039; writes&lt;br /&gt;
the constants of a Lean module and everything it depends on to a file in an NDJSON format,&lt;br /&gt;
one JSON record per line.&amp;lt;ref name=&amp;quot;res-export&amp;quot;&amp;gt;&amp;quot;lean4export&amp;quot;, Reservoir, the index of Lake packages: &amp;quot;A simple declaration exporter for Lean 4 using the Lean 4 NDJSON export format&amp;quot;. [https://reservoir.lean-lang.org/@leanprover/lean4export reservoir.lean-lang.org/@leanprover/lean4export]&amp;lt;/ref&amp;gt;&lt;br /&gt;
The file contains terms of the type theory and nothing else: no tactics, no notation, no&lt;br /&gt;
elaborator. A checker that reads it needs to implement only the type theory: universes,&lt;br /&gt;
dependent function types, inductive types and their recursors, quotients and definitional&lt;br /&gt;
equality. It need not trust what the file says about derived data. A test in the&lt;br /&gt;
Lean Kernel Arena makes the point that a checker &amp;quot;must not blindly trust the recursors it is&lt;br /&gt;
handed&amp;quot;, and should either check them or derive them anew from the inductive type&lt;br /&gt;
itself.&amp;lt;ref name=&amp;quot;arena-tut&amp;quot;&amp;gt;&amp;quot;Tutorial&amp;quot; test suite, Lean Kernel Arena. [https://arena.lean-lang.org/tutorial/ arena.lean-lang.org/tutorial/]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Independent checkers ==&lt;br /&gt;
&lt;br /&gt;
Three programs illustrate the range.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;nanoda&#039;&#039;&#039; is a checker for Lean exports written in Rust, developed independently of&lt;br /&gt;
Lean.&amp;lt;ref name=&amp;quot;rm-vp&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;arena-nanoda&amp;quot;&amp;gt;&amp;quot;nanoda&amp;quot;, checker page, Lean Kernel Arena. [https://arena.lean-lang.org/checker/nanoda/ arena.lean-lang.org/checker/nanoda/]&amp;lt;/ref&amp;gt;&lt;br /&gt;
A bug would have to occur in both nanoda and the Lean kernel, written separately in&lt;br /&gt;
different languages, to let a false theorem through both.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Lean4Lean&#039;&#039;&#039;, by Mario Carneiro, is a type checker for Lean 4 written in Lean. It reads&lt;br /&gt;
compiled &amp;lt;code&amp;gt;.olean&amp;lt;/code&amp;gt; files, offers the same interface as lean4checker, and can check&lt;br /&gt;
the whole of Mathlib, running 20 to 50 per cent slower than the Lean kernel, which is&lt;br /&gt;
written in C++. Because it is written in a language with proofs, parts of it can be, and have&lt;br /&gt;
been, proved correct against a formalisation of Lean&#039;s type theory; that work found a&lt;br /&gt;
soundness bug in the Lean kernel, which has since been fixed.&amp;lt;ref name=&amp;quot;l4l&amp;quot;&amp;gt;Mario Carneiro, &amp;quot;Lean4Lean: Verifying a Typechecker for Lean, in Lean&amp;quot;, in &#039;&#039;31st International Conference on Types for Proofs and Programs (TYPES 2025)&#039;&#039;, Leibniz International Proceedings in Informatics 384, Schloss Dagstuhl, 2026, 2:1–2:23. doi:[https://doi.org/10.4230/LIPIcs.TYPES.2025.2 10.4230/LIPIcs.TYPES.2025.2]; full version [https://arxiv.org/abs/2403.14064 arXiv:2403.14064].&amp;lt;/ref&amp;gt;&lt;br /&gt;
Its description in the Lean Kernel Arena notes the limit of the approach: it follows the C++&lt;br /&gt;
implementation closely, and so &amp;quot;likely shares some implementation bugs with it&amp;quot;.&amp;lt;ref name=&amp;quot;arena-l4l&amp;quot;&amp;gt;&amp;quot;lean4lean&amp;quot;, checker page, Lean Kernel Arena. [https://arena.lean-lang.org/checker/lean4lean arena.lean-lang.org/checker/lean4lean]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;comparator&#039;&#039;&#039; is the reference manual&#039;s &amp;quot;gold standard&amp;quot; for high-risk settings; the manual&lt;br /&gt;
names proof marketplaces, competitions with high rewards, and unaligned AI. The theorem&lt;br /&gt;
statement is written first, in a trusted setting, as a challenge file. comparator compiles&lt;br /&gt;
the proposed proof inside a sandbox, exports it, and, outside the sandbox, validates the export, replays it with the Lean kernel,&lt;br /&gt;
nanoda or both, and checks that the proved statements are exactly those in the challenge&lt;br /&gt;
file.&amp;lt;ref name=&amp;quot;rm-vp&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Lean Kernel Arena&#039;&#039;&#039; tests such checkers side by side. It runs each on the same&lt;br /&gt;
exported tests, some of which a correct checker must accept and some of which it must&lt;br /&gt;
reject, and publishes the results; the Lean kernel of version 4.34.1 is among the checkers&lt;br /&gt;
listed.&amp;lt;ref name=&amp;quot;arena&amp;quot;&amp;gt;Lean Kernel Arena: &amp;quot;presents, tests and benchmarks proof checkers for the Lean Theorem Prover&amp;quot;. [https://arena.lean-lang.org arena.lean-lang.org]&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;arena-tut&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== What each check guards against ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Check !! Reads !! Guards against !! Does not guard against&lt;br /&gt;
|-&lt;br /&gt;
| Editor or Lake build || source files || incomplete proofs, &amp;lt;code&amp;gt;sorry&amp;lt;/code&amp;gt; in the theorem, honest bugs in tactics || gaps in dependencies, extra axioms, bypassed checks&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#print axioms&amp;lt;/code&amp;gt; || Lean&#039;s environment in memory || &amp;lt;code&amp;gt;sorry&amp;lt;/code&amp;gt; anywhere in the dependencies, custom axioms, native computation || constants that were never checked&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;leanchecker&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;.olean&amp;lt;/code&amp;gt; files || constants added without the Lean kernel&#039;s check, bugs in handling the Lean kernel&#039;s state || crafted &amp;lt;code&amp;gt;.olean&amp;lt;/code&amp;gt; files, a compromised machine, bugs in the Lean kernel&lt;br /&gt;
|-&lt;br /&gt;
| comparator with an external checker || an export, outside a sandbox || malicious proofs, a bug present in one checker but not all || a bug shared by every checker, an unsound logic, a wrong statement&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Sources: the reference manual&#039;s chapter on validating proofs,&amp;lt;ref name=&amp;quot;rm-vp&amp;quot; /&amp;gt; and the&lt;br /&gt;
demonstrations above.&lt;br /&gt;
&lt;br /&gt;
== Why check outside the tool that made the proof ==&lt;br /&gt;
&lt;br /&gt;
The Lean kernel is small, but it is a program, and programs have bugs. Lean 4&#039;s kernel was&lt;br /&gt;
extended for performance, with fast arithmetic on natural numbers, nested inductive types and&lt;br /&gt;
primitive projections among other things, and Carneiro reports that some soundness bugs&lt;br /&gt;
entered in the process.&amp;lt;ref name=&amp;quot;l4l&amp;quot; /&amp;gt; A second implementation does not make a bug&lt;br /&gt;
impossible. It makes a bug matter only if every implementation has it.&lt;br /&gt;
&lt;br /&gt;
There is a second reason. Elaboration runs code, much of it written by users, with the full&lt;br /&gt;
rights of a program. A check that runs in the same process, on the same machine, after that&lt;br /&gt;
code, inherits whatever that code did. A check that reads an exported file elsewhere depends&lt;br /&gt;
only on the file and on the checker.&lt;br /&gt;
&lt;br /&gt;
The checks do not answer the other question, whether the statement means what it is taken to&lt;br /&gt;
mean. The reference manual lists among the assumptions that remain even at its gold&lt;br /&gt;
standard: the soundness of Lean&#039;s logic, the correctness of the tools and the sandbox, the&lt;br /&gt;
absence of a bug shared by all checkers, and a statement free of human error, with custom&lt;br /&gt;
notation and type classes named as places to look.&amp;lt;ref name=&amp;quot;rm-vp&amp;quot; /&amp;gt; That question is&lt;br /&gt;
taken up in [[Lean theorem prover/Explainers/Stating the right thing|stating the right thing]].&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/System/Monads and do-notation|Monads and do-notation]] returns to Lean&lt;br /&gt;
as a programming language.&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>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/System/Lake_and_Lean_projects&amp;diff=6795</id>
		<title>Lean theorem prover/System/Lake and Lean projects</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/System/Lake_and_Lean_projects&amp;diff=6795"/>
		<updated>2026-10-15T19:35:19Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Lake and Lean projects}}&lt;br /&gt;
{{Plebeian|Lean theorem prover/Explainers/A library of mathematics}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
&lt;br /&gt;
A single Lean source file can be checked with the command &amp;lt;code&amp;gt;lean&amp;lt;/code&amp;gt;. Anything larger,&lt;br /&gt;
a library of hundreds of files or a program with dependencies, is organised as a &#039;&#039;&#039;Lake&lt;br /&gt;
package&#039;&#039;&#039; and compiled by &#039;&#039;&#039;Lake&#039;&#039;&#039;, Lean&#039;s build tool, which ships with every version of&lt;br /&gt;
Lean. Which version of Lean a project uses is fixed by a one-line file and enforced by&lt;br /&gt;
&#039;&#039;&#039;elan&#039;&#039;&#039;, the toolchain manager. This page shows a minimal project as files, the commands&lt;br /&gt;
that compile and test it, and how dependencies are pinned, all with Lean 4.34.1 and the Lake&lt;br /&gt;
that comes with it.&lt;br /&gt;
&lt;br /&gt;
== The toolchain ==&lt;br /&gt;
&lt;br /&gt;
A Lean &#039;&#039;&#039;toolchain&#039;&#039;&#039; is the set of programs and files for one version of Lean, among them&lt;br /&gt;
&amp;lt;code&amp;gt;lean&amp;lt;/code&amp;gt; itself, &amp;lt;code&amp;gt;lake&amp;lt;/code&amp;gt;, a C compiler (&amp;lt;code&amp;gt;leanc&amp;lt;/code&amp;gt;, a version of Clang), the&lt;br /&gt;
program &amp;lt;code&amp;gt;leanchecker&amp;lt;/code&amp;gt;, and the compiled standard library and runtime. Toolchains&lt;br /&gt;
are installed and selected by elan.&amp;lt;ref name=&amp;quot;rm-bt&amp;quot;&amp;gt;&amp;quot;Build Tools and Distribution&amp;quot;, a chapter of &#039;&#039;The Lean Language Reference&#039;&#039; (edition covering Lean 4.34.0). [https://lean-lang.org/doc/reference/4.34.0/Build-Tools-and-Distribution/ lean-lang.org/doc/reference/4.34.0/Build-Tools-and-Distribution/]&amp;lt;/ref&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;lean&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;lake&amp;lt;/code&amp;gt; commands a user types are small proxies installed&lt;br /&gt;
by elan. Each looks for a file named &amp;lt;code&amp;gt;lean-toolchain&amp;lt;/code&amp;gt; in the current directory and&lt;br /&gt;
its parents, reads the toolchain named there, installs it if it is missing, and runs the&lt;br /&gt;
program from that toolchain. A command can also name a toolchain directly, as in&lt;br /&gt;
&amp;lt;code&amp;gt;lake +leanprover/lean4:v4.34.1 new greeting&amp;lt;/code&amp;gt;.&amp;lt;ref name=&amp;quot;rm-elan&amp;quot;&amp;gt;&amp;quot;Managing Toolchains with Elan&amp;quot;, section 24.2 of &#039;&#039;The Lean Language Reference&#039;&#039; (edition covering Lean 4.34.0). [https://lean-lang.org/doc/reference/4.34.0/Build-Tools-and-Distribution/Managing-Toolchains-with-Elan/ lean-lang.org/doc/reference/4.34.0/Build-Tools-and-Distribution/Managing-Toolchains-with-Elan/]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The file holds one line:&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;leanprover/lean4:v4.34.1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The part before the colon names where toolchains come from, and the part after it the&lt;br /&gt;
version. A project&#039;s file should name an exact version, not a channel such as&lt;br /&gt;
&amp;lt;code&amp;gt;stable&amp;lt;/code&amp;gt;, so that everyone working on it uses the same Lean. Changing the version&lt;br /&gt;
is a one-line edit; the new toolchain is downloaded the next time it is&lt;br /&gt;
needed.&amp;lt;ref name=&amp;quot;rm-elan&amp;quot; /&amp;gt; This matters more for a proof assistant than for most&lt;br /&gt;
languages. The elaborator, the tactics and the library change from one version of Lean to&lt;br /&gt;
the next, and a proof that is accepted under one version may fail under another. The&lt;br /&gt;
toolchain file records under which version a body of proofs was checked.&lt;br /&gt;
&lt;br /&gt;
== A minimal Lake package ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;lake new greeting&amp;lt;/code&amp;gt; creates a directory with a library, an executable and a&lt;br /&gt;
configuration file. With Lean 4.34.1 the configuration it writes, &amp;lt;code&amp;gt;lakefile.toml&amp;lt;/code&amp;gt;,&lt;br /&gt;
is:&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;name = &amp;quot;greeting&amp;quot;&lt;br /&gt;
version = &amp;quot;0.1.0&amp;quot;&lt;br /&gt;
defaultTargets = [&amp;quot;greeting&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
[[lean_lib]]&lt;br /&gt;
name = &amp;quot;Greeting&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[[lean_exe]]&lt;br /&gt;
name = &amp;quot;greeting&amp;quot;&lt;br /&gt;
root = &amp;quot;Main&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first lines describe the Lake package itself. Each &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;[[lean_lib]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; table&lt;br /&gt;
declares a &#039;&#039;&#039;library&#039;&#039;&#039;, a collection of Lean modules under a root name, here&lt;br /&gt;
&amp;lt;code&amp;gt;Greeting&amp;lt;/code&amp;gt;; each &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;[[lean_exe]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; declares an &#039;&#039;&#039;executable&#039;&#039;&#039;, a&lt;br /&gt;
program whose Lean module defines &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;.&amp;lt;ref name=&amp;quot;rm-lake&amp;quot;&amp;gt;&amp;quot;Lake&amp;quot;, section 24.1 of &#039;&#039;The Lean Language Reference&#039;&#039; (edition covering Lean 4.34.0), including 24.1.1 &amp;quot;Concepts and Terminology&amp;quot;, 24.1.1.2 &amp;quot;Builds&amp;quot;, 24.1.1.5 &amp;quot;Test and Lint Drivers&amp;quot; and the TOML configuration reference. [https://lean-lang.org/doc/reference/4.34.0/Build-Tools-and-Distribution/Lake/ lean-lang.org/doc/reference/4.34.0/Build-Tools-and-Distribution/Lake/]&amp;lt;/ref&amp;gt;&lt;br /&gt;
The source files follow the names. &amp;lt;code&amp;gt;Greeting.lean&amp;lt;/code&amp;gt; is the root of the library and&lt;br /&gt;
imports its parts:&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;-- This module serves as the root of the `Greeting` library.&lt;br /&gt;
-- Import modules here that should be built as part of the library.&lt;br /&gt;
import Greeting.Basic&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Greeting/Basic.lean&amp;lt;/code&amp;gt; holds the one definition:&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;def hello := &amp;quot;world&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and &amp;lt;code&amp;gt;Main.lean&amp;lt;/code&amp;gt; is the program:&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;import Greeting&lt;br /&gt;
&lt;br /&gt;
def main : IO Unit :=&lt;br /&gt;
  IO.println s!&amp;quot;Hello, {hello}!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A Lean module&#039;s name is its path: &amp;lt;code&amp;gt;Greeting/Basic.lean&amp;lt;/code&amp;gt; is the Lean module&lt;br /&gt;
&amp;lt;code&amp;gt;Greeting.Basic&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;import Greeting.Basic&amp;lt;/code&amp;gt; refers to it. Lake reads&lt;br /&gt;
the imports to work out the order in which the Lean modules must be compiled.&amp;lt;ref name=&amp;quot;rm-lake&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The configuration can also be written in Lean, as &amp;lt;code&amp;gt;lakefile.lean&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;lake new&lt;br /&gt;
greet2 std.lean&amp;lt;/code&amp;gt; writes:&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;import Lake&lt;br /&gt;
open Lake DSL&lt;br /&gt;
&lt;br /&gt;
package &amp;quot;greet2&amp;quot; where&lt;br /&gt;
  version := v!&amp;quot;0.1.0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
lean_lib «Greet2» where&lt;br /&gt;
  -- add library configuration options here&lt;br /&gt;
&lt;br /&gt;
@[default_target]&lt;br /&gt;
lean_exe &amp;quot;greet2&amp;quot; where&lt;br /&gt;
  root := `Main&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The TOML form is purely declarative. The Lean form is a Lean program and can compute its&lt;br /&gt;
configuration or define new kinds of target.&amp;lt;ref name=&amp;quot;rm-lake&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compiling ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;lake build&amp;lt;/code&amp;gt; compiles the default targets and everything they need. In the new&lt;br /&gt;
directory it reports:&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;info: greeting: no previous manifest, creating one from scratch&lt;br /&gt;
info: toolchain not updated; already up-to-date&lt;br /&gt;
✔ [2/8] Built Greeting.Basic (277ms)&lt;br /&gt;
✔ [3/8] Built Greeting.Basic:c.o (58ms)&lt;br /&gt;
✔ [4/8] Built Greeting (225ms)&lt;br /&gt;
✔ [5/8] Built Greeting:c.o (66ms)&lt;br /&gt;
✔ [6/8] Built Main (244ms)&lt;br /&gt;
✔ [7/8] Built Main:c.o (69ms)&lt;br /&gt;
✔ [8/8] Built greeting:exe (289ms)&lt;br /&gt;
Build completed successfully (8 jobs).&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first two lines appear on the first run only, and the times in brackets vary from run&lt;br /&gt;
to run. Each Lean module is elaborated, which produces an &amp;lt;code&amp;gt;.olean&amp;lt;/code&amp;gt; file holding&lt;br /&gt;
its definitions and theorems in compiled form, and C code, which is compiled to an object file (&amp;lt;code&amp;gt;:c.o&amp;lt;/code&amp;gt;); the&lt;br /&gt;
object files are linked into the executable. &amp;lt;code&amp;gt;lake exe greeting&amp;lt;/code&amp;gt; then prints&lt;br /&gt;
&amp;lt;code&amp;gt;Hello, world!&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Elaboration includes the Lean kernel&#039;s check of every definition and theorem, so a&lt;br /&gt;
Lake build of a Lean module that finishes without errors or warnings gives the same assurance&lt;br /&gt;
as opening it in an editor and seeing it accepted: every theorem in it, and in everything it&lt;br /&gt;
imports, has been checked. The reference manual makes the comparison explicitly.&amp;lt;ref name=&amp;quot;rm-validating&amp;quot;&amp;gt;&amp;quot;Validating a Lean Proof&amp;quot;, a chapter of &#039;&#039;The Lean Language Reference&#039;&#039; (edition covering Lean 4.34.0), section &amp;quot;The Blue Double Check Marks&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;
&lt;br /&gt;
Running &amp;lt;code&amp;gt;lake build&amp;lt;/code&amp;gt; again with nothing changed prints only &amp;lt;code&amp;gt;Build completed&lt;br /&gt;
successfully (8 jobs).&amp;lt;/code&amp;gt; Lake keeps a &#039;&#039;&#039;trace&#039;&#039;&#039; for every output, recording a digest of&lt;br /&gt;
each input from which it was made; when no input has changed, the output is reused and its&lt;br /&gt;
saved messages are replayed instead of being produced again.&amp;lt;ref name=&amp;quot;rm-lake&amp;quot; /&amp;gt; Lake keeps its&lt;br /&gt;
working state under the directory &amp;lt;code&amp;gt;.lake/&amp;lt;/code&amp;gt;: compiled outputs in&lt;br /&gt;
&amp;lt;code&amp;gt;.lake/build/&amp;lt;/code&amp;gt; and the sources of dependencies in&lt;br /&gt;
&amp;lt;code&amp;gt;.lake/packages/&amp;lt;/code&amp;gt;.&amp;lt;ref name=&amp;quot;rm-lake&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Testing ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;lake test&amp;lt;/code&amp;gt; runs the Lake package&#039;s &#039;&#039;&#039;test driver&#039;&#039;&#039;, a target named in the&lt;br /&gt;
configuration. Lake is not a test framework: it finds the driver, compiles it, and, for an&lt;br /&gt;
executable, runs it and treats a non-zero exit code as failure. A library can serve as the&lt;br /&gt;
driver, and then any elaboration error counts as a failure, including a failed&lt;br /&gt;
&amp;lt;code&amp;gt;#guard&amp;lt;/code&amp;gt;.&amp;lt;ref name=&amp;quot;rm-lake&amp;quot; /&amp;gt; Adding &amp;lt;code&amp;gt;testDriver = &amp;quot;GreetingTest&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
and a second library to the configuration,&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;[[lean_lib]]&lt;br /&gt;
name = &amp;quot;GreetingTest&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
with the file &amp;lt;code&amp;gt;GreetingTest.lean&amp;lt;/code&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;import Greeting&lt;br /&gt;
&lt;br /&gt;
#guard hello == &amp;quot;world&amp;quot;&lt;br /&gt;
#guard hello.length == 5&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
makes &amp;lt;code&amp;gt;lake test&amp;lt;/code&amp;gt; succeed. Changing the last line to claim a length of 6 makes it&lt;br /&gt;
fail, with this among its messages:&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;error: GreetingTest.lean:4:0: Expression&lt;br /&gt;
  hello.length == 6&lt;br /&gt;
did not evaluate to `true`&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For a library of proofs the distinction between compiling and testing is thin. A theorem&lt;br /&gt;
that is false, or whose proof is broken, does not compile.&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
A Lake package may require others. In &amp;lt;code&amp;gt;lakefile.toml&amp;lt;/code&amp;gt; each dependency is a&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;[[require]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; table. A dependency can come from Reservoir, an online index of Lake&lt;br /&gt;
packages, from a Git repository at a given revision, or from a local&lt;br /&gt;
path.&amp;lt;ref name=&amp;quot;rm-lake&amp;quot; /&amp;gt; The reference manual&#039;s example of a dependency taken from&lt;br /&gt;
Reservoir is:&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;[[require]]&lt;br /&gt;
name = &amp;quot;example&amp;quot;&lt;br /&gt;
version = &amp;quot;≥2.12.0&amp;quot;&lt;br /&gt;
scope = &amp;quot;exampleDev&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The configuration says which dependencies are wanted. The file&lt;br /&gt;
&amp;lt;code&amp;gt;lake-manifest.json&amp;lt;/code&amp;gt; says exactly which versions are in use: for each dependency&lt;br /&gt;
it records the source and the precise revision. Lake brings each dependency&#039;s local copy into&lt;br /&gt;
line with lake-manifest.json before compiling, and creates the file if it is missing;&lt;br /&gt;
&amp;lt;code&amp;gt;lake update&amp;lt;/code&amp;gt; moves the recorded revisions forward. The file is meant to be kept&lt;br /&gt;
with the source.&amp;lt;ref name=&amp;quot;rm-lake&amp;quot; /&amp;gt; For the minimal project, which has no dependencies,&lt;br /&gt;
Lake wrote:&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;{&amp;quot;version&amp;quot;: &amp;quot;1.2.0&amp;quot;,&lt;br /&gt;
 &amp;quot;packagesDir&amp;quot;: &amp;quot;.lake/packages&amp;quot;,&lt;br /&gt;
 &amp;quot;packages&amp;quot;: [],&lt;br /&gt;
 &amp;quot;name&amp;quot;: &amp;quot;greeting&amp;quot;,&lt;br /&gt;
 &amp;quot;lakeDir&amp;quot;: &amp;quot;.lake&amp;quot;,&lt;br /&gt;
 &amp;quot;fixedToolchain&amp;quot;: false}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Together, &amp;lt;code&amp;gt;lean-toolchain&amp;lt;/code&amp;gt;, the configuration file and lake-manifest.json fix the&lt;br /&gt;
version of Lean and the exact source of every dependency. That is what makes a Lean project&lt;br /&gt;
reproducible: another person, or the same person years later, can obtain the same toolchain&lt;br /&gt;
and the same dependencies and have every proof checked again. The large mathematical&lt;br /&gt;
libraries described in [[Lean theorem prover/Explainers/A library of mathematics|a library&lt;br /&gt;
of mathematics]] are distributed in this form.&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/System/Proof export and independent checkers|Proof export and independent checkers]]&lt;br /&gt;
describes how the results of a Lake build can be checked again outside the program that&lt;br /&gt;
produced 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>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/System/The_compiler_and_runtime&amp;diff=6794</id>
		<title>Lean theorem prover/System/The compiler and runtime</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"/>
		<updated>2026-10-15T19:35:16Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&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;
{{Lean theorem prover map}}&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&#039;s&lt;br /&gt;
intermediate representations to C, the run-time system&#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 &#039;&#039;The Lean Language Reference&#039;&#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 &#039;&#039;Automated Deduction: CADE 28&#039;&#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&#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&#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;, &#039;&#039;The Lean Language Reference&#039;&#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 &#039;&#039;&#039;LCNF&#039;&#039;&#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&#039;s &#039;&#039;&#039;IR&#039;&#039;&#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 &#039;&#039;The Lean Language Reference&#039;&#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 &#039;&#039;&#039;reference counting&#039;&#039;&#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&#039;s answer is that an exact count is also information: it says whether a&lt;br /&gt;
value is &#039;&#039;&#039;shared&#039;&#039;&#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 &#039;&#039;Proceedings of the 31st Symposium on Implementation and Application of Functional Languages (IFL 2019)&#039;&#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&#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;
&#039;&#039;&#039;resurrection hypothesis&#039;&#039;&#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, &#039;&#039;&#039;functional but in place&#039;&#039;&#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. &#039;&#039;&#039;Borrowed&#039;&#039;&#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;
&#039;&#039;&#039;&amp;lt;code&amp;gt;@[extern &amp;quot;sym&amp;quot;]&amp;lt;/code&amp;gt;&#039;&#039;&#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 &#039;&#039;The Lean Language Reference&#039;&#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;
&#039;&#039;&#039;&amp;lt;code&amp;gt;@[implemented_by f]&amp;lt;/code&amp;gt;&#039;&#039;&#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&#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 &#039;&#039;The Lean Language Reference&#039;&#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>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/System/Metaprogramming_in_Lean&amp;diff=6793</id>
		<title>Lean theorem prover/System/Metaprogramming in Lean</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/System/Metaprogramming_in_Lean&amp;diff=6793"/>
		<updated>2026-10-15T19:35:15Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Metaprogramming in Lean}}&lt;br /&gt;
{{Plebeian|Lean theorem prover/Explainers/Tactics}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;metaprogram&#039;&#039;&#039; is a Lean program whose data is Lean itself: syntax, terms, goals,&lt;br /&gt;
Lean&#039;s environment (its table of definitions and theorems). Tactics, elaborators and&lt;br /&gt;
custom commands are metaprograms. Lean 4 is written largely in Lean, and the data&lt;br /&gt;
structures and functions its own elaborator and tactics use are available to any Lean source&lt;br /&gt;
file that imports the library &amp;lt;code&amp;gt;Lean&amp;lt;/code&amp;gt;.&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 &#039;&#039;Automated Deduction: CADE 28&#039;&#039;, Lecture Notes in Computer Science 12699, Springer, 2021, pp. 625–635. doi:[https://doi.org/10.1007/978-3-030-79876-5_37 10.1007/978-3-030-79876-5_37]; author&#039;s copy [https://lean-lang.org/papers/lean4.pdf lean-lang.org/papers/lean4.pdf].&amp;lt;/ref&amp;gt;&lt;br /&gt;
This page shows the representation of terms, the monads metaprograms run in, and three small&lt;br /&gt;
metaprograms compiled by Lean 4.34.1: a term elaborator, a command and a tactic. It ends with&lt;br /&gt;
the point on which the whole arrangement rests. A metaprogram is not trusted. What it&lt;br /&gt;
produces is checked by the Lean kernel, and a wrong result is rejected, unless that check has&lt;br /&gt;
been switched off.&lt;br /&gt;
&lt;br /&gt;
== Terms as data ==&lt;br /&gt;
&lt;br /&gt;
Every term that reaches the Lean kernel is a value of the inductive type&lt;br /&gt;
&amp;lt;code&amp;gt;Lean.Expr&amp;lt;/code&amp;gt;. Lean prints its definition on request.&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 Elab Term Command Tactic&lt;br /&gt;
&lt;br /&gt;
#print Lean.Expr&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;inductive Lean.Expr : Type&lt;br /&gt;
number of parameters: 0&lt;br /&gt;
constructors:&lt;br /&gt;
Lean.Expr.bvar : Nat → Expr&lt;br /&gt;
Lean.Expr.fvar : FVarId → Expr&lt;br /&gt;
Lean.Expr.mvar : MVarId → Expr&lt;br /&gt;
Lean.Expr.sort : Level → Expr&lt;br /&gt;
Lean.Expr.const : Name → List Level → Expr&lt;br /&gt;
Lean.Expr.app : Expr → Expr → Expr&lt;br /&gt;
Lean.Expr.lam : Name → Expr → Expr → BinderInfo → Expr&lt;br /&gt;
Lean.Expr.forallE : Name → Expr → Expr → BinderInfo → Expr&lt;br /&gt;
Lean.Expr.letE : Name → Expr → Expr → Expr → Bool → Expr&lt;br /&gt;
Lean.Expr.lit : Literal → Expr&lt;br /&gt;
Lean.Expr.mdata : MData → Expr → Expr&lt;br /&gt;
Lean.Expr.proj : Name → Nat → Expr → Expr&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The twelve constructors are the type theory&#039;s term formers with some additions for&lt;br /&gt;
practical use. &amp;lt;code&amp;gt;sort&amp;lt;/code&amp;gt; is a universe, &amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; a reference to a named&lt;br /&gt;
definition or theorem at given universe levels, &amp;lt;code&amp;gt;app&amp;lt;/code&amp;gt; an application,&lt;br /&gt;
&amp;lt;code&amp;gt;lam&amp;lt;/code&amp;gt; a function, &amp;lt;code&amp;gt;forallE&amp;lt;/code&amp;gt; a dependent function type and&lt;br /&gt;
&amp;lt;code&amp;gt;letE&amp;lt;/code&amp;gt; a local definition. &amp;lt;code&amp;gt;lit&amp;lt;/code&amp;gt; holds a natural-number or string&lt;br /&gt;
literal, &amp;lt;code&amp;gt;proj&amp;lt;/code&amp;gt; a projection from a structure, and &amp;lt;code&amp;gt;mdata&amp;lt;/code&amp;gt; attaches&lt;br /&gt;
metadata that does not change meaning. Three constructors are variables of different&lt;br /&gt;
kinds. &amp;lt;code&amp;gt;bvar&amp;lt;/code&amp;gt; is a variable bound inside the term, named by a number, the&lt;br /&gt;
&#039;&#039;&#039;de Bruijn index&#039;&#039;&#039;, which counts binders outward; &amp;lt;code&amp;gt;fvar&amp;lt;/code&amp;gt; is a free variable&lt;br /&gt;
of the current local context, such as a hypothesis in a goal; &amp;lt;code&amp;gt;mvar&amp;lt;/code&amp;gt; is a&lt;br /&gt;
&#039;&#039;&#039;metavariable&#039;&#039;&#039;, a hole still to be filled (see&lt;br /&gt;
[[Lean theorem prover/System/Metavariables and unification|metavariables and unification]]).&lt;br /&gt;
&lt;br /&gt;
A small definition shows the encoding.&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;
def k : Nat → Nat → Nat := fun a _b =&amp;gt; a&lt;br /&gt;
&lt;br /&gt;
#eval show MetaM Unit from do&lt;br /&gt;
  let info ← getConstInfo ``k&lt;br /&gt;
  IO.println (repr info.value!)&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;Lean.Expr.lam&lt;br /&gt;
  `a&lt;br /&gt;
  (Lean.Expr.const `Nat [])&lt;br /&gt;
  (Lean.Expr.lam `_b (Lean.Expr.const `Nat []) (Lean.Expr.bvar 1) (Lean.BinderInfo.default))&lt;br /&gt;
  (Lean.BinderInfo.default)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The body of the inner function is &amp;lt;code&amp;gt;bvar 1&amp;lt;/code&amp;gt;: the variable bound one binder further&lt;br /&gt;
out than the nearest, which is &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;. Binder names are kept only for display: two&lt;br /&gt;
terms that differ only in the names of bound variables are treated as the same term.&lt;br /&gt;
&lt;br /&gt;
== The monads ==&lt;br /&gt;
&lt;br /&gt;
A metaprogram runs in a monad that gives it access to the state of Lean (see&lt;br /&gt;
[[Lean theorem prover/System/Monads and do-notation|monads and do-notation]] for monads in&lt;br /&gt;
general). There is a stack of four, each extending the one below it. Lean prints their&lt;br /&gt;
definitions.&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;
#print CoreM&lt;br /&gt;
#print MetaM&lt;br /&gt;
#print TermElabM&lt;br /&gt;
#print TacticM&lt;br /&gt;
#print CommandElabM&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;@[reducible] def Lean.Core.CoreM : Type → Type :=&lt;br /&gt;
ReaderT Core.Context (StateRefT&#039; IO.RealWorld Core.State (EIO Exception))&lt;br /&gt;
@[reducible] def Lean.Meta.MetaM : Type → Type :=&lt;br /&gt;
ReaderT Meta.Context (StateRefT&#039; IO.RealWorld Meta.State CoreM)&lt;br /&gt;
@[reducible] def Lean.Elab.Term.TermElabM : Type → Type :=&lt;br /&gt;
ReaderT Term.Context (StateRefT&#039; IO.RealWorld Term.State MetaM)&lt;br /&gt;
@[reducible] def Lean.Elab.Tactic.TacticM : Type → Type :=&lt;br /&gt;
ReaderT Tactic.Context (StateRefT&#039; IO.RealWorld Tactic.State TermElabM)&lt;br /&gt;
@[reducible] def Lean.Elab.Command.CommandElabM : Type → Type :=&lt;br /&gt;
ReaderT Command.Context (StateRefT&#039; IO.RealWorld Command.State (EIO Exception))&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each layer adds a read-only context (&amp;lt;code&amp;gt;ReaderT&amp;lt;/code&amp;gt;) and a mutable state&lt;br /&gt;
(&amp;lt;code&amp;gt;StateRefT&#039;&amp;lt;/code&amp;gt;) on top of the layer below. At the bottom, &amp;lt;code&amp;gt;EIO&lt;br /&gt;
Exception&amp;lt;/code&amp;gt; is input and output that can fail with an exception, so every metaprogram&lt;br /&gt;
can do input and output.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;CoreM&amp;lt;/code&amp;gt;&#039;&#039;&#039; gives access to Lean&#039;s environment: what has been defined or imported at the current point.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;MetaM&amp;lt;/code&amp;gt;&#039;&#039;&#039; adds the metavariable context, the metavariables in existence and their assignments, and with it the operations of type inference (&amp;lt;code&amp;gt;inferType&amp;lt;/code&amp;gt;), reduction (&amp;lt;code&amp;gt;whnf&amp;lt;/code&amp;gt;) and definitional-equality checking (&amp;lt;code&amp;gt;isDefEq&amp;lt;/code&amp;gt;).&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;TermElabM&amp;lt;/code&amp;gt;&#039;&#039;&#039; adds the information the elaborator uses while turning syntax into terms.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;TacticM&amp;lt;/code&amp;gt;&#039;&#039;&#039; adds the list of current goals.&amp;lt;ref name=&amp;quot;mpb&amp;quot;&amp;gt;Arthur Paulino, Damiano Testa, Edward Ayers, Evgenia Karunus, Henrik Böving, Jannis Limperg, Siddhartha Gadgil and Siddharth Bhat, &#039;&#039;Metaprogramming in Lean 4&#039;&#039;, online book, chapter &amp;quot;MetaM&amp;quot;. [https://leanprover-community.github.io/lean4-metaprogramming-book/main/04_metam.html leanprover-community.github.io/lean4-metaprogramming-book/main/04_metam.html]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CommandElabM&amp;lt;/code&amp;gt;, the monad of commands, stands beside the stack and not on top of&lt;br /&gt;
it; a command that needs to elaborate a term enters &amp;lt;code&amp;gt;TermElabM&amp;lt;/code&amp;gt; with&lt;br /&gt;
&amp;lt;code&amp;gt;liftTermElabM&amp;lt;/code&amp;gt;, as in the second example below.&lt;br /&gt;
&lt;br /&gt;
== Elaborators ==&lt;br /&gt;
&lt;br /&gt;
An &#039;&#039;&#039;elaborator&#039;&#039;&#039; gives meaning to a piece of syntax by running Lean code. A term&lt;br /&gt;
elaborator has type &amp;lt;code&amp;gt;Syntax → Option Expr → TermElabM Expr&amp;lt;/code&amp;gt;: it receives the&lt;br /&gt;
syntax and the expected type if one is known, and must return a &amp;lt;code&amp;gt;Lean.Expr&amp;lt;/code&amp;gt;. A&lt;br /&gt;
command elaborator has type &amp;lt;code&amp;gt;Syntax → CommandElabM Unit&amp;lt;/code&amp;gt; and acts by side&lt;br /&gt;
effects, such as adding constants or reporting messages.&amp;lt;ref name=&amp;quot;rm-elab&amp;quot;&amp;gt;&amp;quot;Elaborators&amp;quot;, section 23.6 of &#039;&#039;The Lean Language Reference&#039;&#039; (edition covering Lean 4.34.0). [https://lean-lang.org/doc/reference/4.34.0/Notations-and-Macros/Elaborators/ lean-lang.org/doc/reference/4.34.0/Notations-and-Macros/Elaborators/]&amp;lt;/ref&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;elab&amp;lt;/code&amp;gt; command declares the syntax and its elaborator together.&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;
elab &amp;quot;double! &amp;quot; t:term : term =&amp;gt; do&lt;br /&gt;
  let stx ← `(2 * $t)&lt;br /&gt;
  elabTerm stx (some (mkConst ``Nat))&lt;br /&gt;
&lt;br /&gt;
#eval double! 21&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This prints &amp;lt;code&amp;gt;42&amp;lt;/code&amp;gt;. The elaborator constructs syntax with a quotation,&lt;br /&gt;
&amp;lt;code&amp;gt;`(2 * $t)&amp;lt;/code&amp;gt;, and hands it to &amp;lt;code&amp;gt;elabTerm&amp;lt;/code&amp;gt; with the expected type&lt;br /&gt;
&amp;lt;code&amp;gt;Nat&amp;lt;/code&amp;gt;. Quotations are available in every one of these monads; a quotation of a&lt;br /&gt;
category other than terms names it, as in &amp;lt;code&amp;gt;`(tactic| intro h)&amp;lt;/code&amp;gt;. Their hygiene is&lt;br /&gt;
the hygiene of [[Lean theorem prover/System/Syntax extension and hygienic macros|macros]].&lt;br /&gt;
Unlike a macro, which can do no more with Lean&#039;s environment than check whether a name exists&lt;br /&gt;
and resolve names, an elaborator can consult types, the local context and the whole of Lean&#039;s&lt;br /&gt;
environment.&amp;lt;ref name=&amp;quot;rm-macros&amp;quot;&amp;gt;&amp;quot;Macros&amp;quot;, section 23.5 of &#039;&#039;The Lean Language Reference&#039;&#039; (edition covering Lean 4.34.0), subsection 23.5.2 &amp;quot;The Macro Monad&amp;quot;. [https://lean-lang.org/doc/reference/4.34.0/Notations-and-Macros/Macros/ lean-lang.org/doc/reference/4.34.0/Notations-and-Macros/Macros/]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A command that elaborates a term, puts it in weak head normal form and reports the result:&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;
elab &amp;quot;#whnf &amp;quot; t:term : command =&amp;gt; do&lt;br /&gt;
  liftTermElabM do&lt;br /&gt;
    let e ← elabTerm t none&lt;br /&gt;
    let r ← whnf e&lt;br /&gt;
    logInfo m!&amp;quot;{e} reduces to {r} : {← inferType e}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#whnf (fun (x : Nat) =&amp;gt; x + 1) 41&lt;br /&gt;
#whnf (fun (x : Nat) =&amp;gt; [x, x]) 7&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;(fun x =&amp;gt; x + 1) 41 reduces to 42 : Nat&lt;br /&gt;
(fun x =&amp;gt; [x, x]) 7 reduces to [7, 7] : List Nat&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== A tactic ==&lt;br /&gt;
&lt;br /&gt;
A tactic is an elaborator in &amp;lt;code&amp;gt;TacticM&amp;lt;/code&amp;gt; (the&lt;br /&gt;
[[Lean theorem prover/System/The tactic framework|tactic framework]] describes how they are&lt;br /&gt;
run). This one closes the main goal with any hypothesis whose type is definitionally equal&lt;br /&gt;
to it, a simple form of Lean&#039;s &amp;lt;code&amp;gt;assumption&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;
elab &amp;quot;my_assumption&amp;quot; : tactic =&amp;gt; do&lt;br /&gt;
  let goal ← getMainGoal&lt;br /&gt;
  let target ← goal.getType&lt;br /&gt;
  for h in ← getLCtx do&lt;br /&gt;
    if !h.isImplementationDetail &amp;amp;amp;&amp;amp;amp; (← isDefEq h.type target) then&lt;br /&gt;
      goal.assign h.toExpr&lt;br /&gt;
      replaceMainGoal []&lt;br /&gt;
      return&lt;br /&gt;
  throwError &amp;quot;my_assumption: no hypothesis has type {target}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
example (p q : Prop) (hp : p) (hq : q) : p ∧ q :=&lt;br /&gt;
  ⟨by my_assumption, by my_assumption⟩&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each goal is a metavariable, and closing it means assigning it a term: here the free&lt;br /&gt;
variable &amp;lt;code&amp;gt;hp&amp;lt;/code&amp;gt; for the first goal and &amp;lt;code&amp;gt;hq&amp;lt;/code&amp;gt; for the second. When no&lt;br /&gt;
hypothesis fits, the tactic fails with its own message:&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 (p q : Prop) (hp : p) : q := by my_assumption&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean reports &amp;lt;code&amp;gt;my_assumption: no hypothesis has type q&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Metaprograms are not trusted ==&lt;br /&gt;
&lt;br /&gt;
Nothing stops a tactic from assigning a goal a term of the wrong type. The assignment&lt;br /&gt;
operation does not check. This tactic claims to prove anything with &amp;lt;code&amp;gt;True.intro&amp;lt;/code&amp;gt;,&lt;br /&gt;
the proof of &amp;lt;code&amp;gt;True&amp;lt;/code&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;
elab &amp;quot;cheat&amp;quot; : tactic =&amp;gt; do&lt;br /&gt;
  let goal ← getMainGoal&lt;br /&gt;
  goal.assign (mkConst ``True.intro)&lt;br /&gt;
  replaceMainGoal []&lt;br /&gt;
&lt;br /&gt;
theorem bad : False := by cheat&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The tactic runs and reports no failure, but the theorem is refused:&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;(kernel) declaration type mismatch, &#039;bad&#039; has type&lt;br /&gt;
  True&lt;br /&gt;
but it is expected to have type&lt;br /&gt;
  False&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The message is the Lean kernel&#039;s. When a definition or theorem is complete, the elaborator&lt;br /&gt;
passes it to the Lean kernel, which checks it against the rules of the type theory before it&lt;br /&gt;
enters Lean&#039;s environment. The reference manual states the purpose plainly: the elaborator&#039;s&lt;br /&gt;
output must be checked by the Lean kernel &amp;quot;to guard against potential bugs in&lt;br /&gt;
elaboration&amp;quot;.&amp;lt;ref name=&amp;quot;rm-ec&amp;quot;&amp;gt;&amp;quot;Elaboration and Compilation&amp;quot;, a chapter of &#039;&#039;The Lean Language Reference&#039;&#039; (edition covering Lean 4.34.0), section &amp;quot;The Kernel&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;
The elaborator, the tactic framework, the simplifier and every user&#039;s tactic are outside the&lt;br /&gt;
trusted part of the system. They may be wrong, and, as long as the Lean kernel&#039;s check is not&lt;br /&gt;
switched off, a wrong result costs a failed check, not a false theorem.&lt;br /&gt;
&lt;br /&gt;
This is why metaprogramming can be open to every user. A proof assistant whose automation&lt;br /&gt;
had to be trusted would have to restrict who may write automation, or audit it. Lean instead&lt;br /&gt;
lets any file define tactics and elaborators with the same access its own have, because the&lt;br /&gt;
check at the end does not depend on how the term was found.&lt;br /&gt;
&lt;br /&gt;
The guarantee has limits, and they are worth stating. The check covers only what reaches&lt;br /&gt;
the Lean kernel. The option &amp;lt;code&amp;gt;debug.skipKernelTC&amp;lt;/code&amp;gt; switches it off, and code run during&lt;br /&gt;
elaboration can add a constant to Lean&#039;s environment without passing it to the Lean kernel;&lt;br /&gt;
the reference manual names both as ways of bypassing the check.&amp;lt;ref name=&amp;quot;rm-validating&amp;quot; /&amp;gt; With&lt;br /&gt;
that option set, the &amp;lt;code&amp;gt;cheat&amp;lt;/code&amp;gt; tactic above yields an accepted theorem&lt;br /&gt;
&amp;lt;code&amp;gt;bad : False&amp;lt;/code&amp;gt;. A metaprogram runs with the full rights of input and output, and the&lt;br /&gt;
reference manual&#039;s guidance on validating a proof warns that tactics and other code run at&lt;br /&gt;
elaboration &amp;quot;can perform arbitrary actions when run&amp;quot;, including, in the hostile case,&lt;br /&gt;
interfering with the system before any check takes place.&amp;lt;ref name=&amp;quot;rm-validating&amp;quot;&amp;gt;&amp;quot;Validating a Lean Proof&amp;quot;, a chapter of &#039;&#039;The Lean Language Reference&#039;&#039; (edition covering Lean 4.34.0). [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;
Honest mistakes are caught by the check above. Deliberate tampering is the subject of&lt;br /&gt;
[[Lean theorem prover/System/Proof export and independent checkers|proof export and independent checkers]].&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/System/The compiler and runtime|The compiler and runtime]] explains how&lt;br /&gt;
metaprograms, like all Lean programs, are compiled and run.&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>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/System/Syntax_extension_and_hygienic_macros&amp;diff=6792</id>
		<title>Lean theorem prover/System/Syntax extension and hygienic macros</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/System/Syntax_extension_and_hygienic_macros&amp;diff=6792"/>
		<updated>2026-10-15T19:35:13Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Syntax extension and hygienic macros}}&lt;br /&gt;
{{Plebeian|Lean theorem prover/Explainers/Programs and proofs in one language}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
&lt;br /&gt;
Lean&#039;s grammar is not fixed. A Lean source file can add operators, notations and whole new&lt;br /&gt;
syntactic forms, and say what each one means by rewriting it into syntax Lean already&lt;br /&gt;
understands. The rewriting is done by &#039;&#039;&#039;macros&#039;&#039;&#039;, and Lean&#039;s macros are &#039;&#039;&#039;hygienic&#039;&#039;&#039;: a&lt;br /&gt;
name that a macro introduces cannot capture a name the user wrote, and a name the user wrote&lt;br /&gt;
cannot capture one the macro relies on. This page shows the commands, from the simplest&lt;br /&gt;
(&amp;lt;code&amp;gt;infixl&amp;lt;/code&amp;gt;) to the most general (&amp;lt;code&amp;gt;macro_rules&amp;lt;/code&amp;gt;), and what hygiene&lt;br /&gt;
prevents, with examples compiled by Lean 4.34.1. The design is set out by Ullrich and de&lt;br /&gt;
Moura.&amp;lt;ref name=&amp;quot;bn&amp;quot;&amp;gt;Sebastian Ullrich and Leonardo de Moura, &amp;quot;Beyond Notations: Hygienic Macro Expansion for Theorem Proving Languages&amp;quot;, &#039;&#039;Logical Methods in Computer Science&#039;&#039; 18(2), 2022, article 1, 21 pp. Extended version of the paper in &#039;&#039;Automated Reasoning: IJCAR 2020&#039;&#039;, Lecture Notes in Computer Science 12167, Springer, 2020, pp. 167–182 (doi:10.1007/978-3-030-51054-1_10). doi:[https://doi.org/10.46298/lmcs-18(2:1)2022 10.46298/lmcs-18(2:1)2022]; preprint [https://arxiv.org/abs/2001.10490 arXiv:2001.10490].&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Where syntax extension sits ==&lt;br /&gt;
&lt;br /&gt;
Lean reads a source file one command at a time. Each command is parsed, then&lt;br /&gt;
[[Lean theorem prover/System/Elaboration|elaborated]] into terms of the type theory, and only&lt;br /&gt;
the elaborated result is passed to the Lean kernel. Macro expansion happens after parsing, as&lt;br /&gt;
part of elaboration: before a piece of syntax is elaborated, any macro at its outermost layer&lt;br /&gt;
is expanded.&amp;lt;ref name=&amp;quot;rm-macros&amp;quot; /&amp;gt; A macro takes a piece of syntax and returns another piece of syntax; the&lt;br /&gt;
reference manual calls the expansion of a notation &amp;quot;a purely syntactic process that occurs&lt;br /&gt;
prior to elaboration or code generation&amp;quot;.&amp;lt;ref name=&amp;quot;rm-notations&amp;quot;&amp;gt;&amp;quot;Notations&amp;quot;, section 23.3 of &#039;&#039;The Lean Language Reference&#039;&#039; (edition covering Lean 4.34.0). [https://lean-lang.org/doc/reference/4.34.0/Notations-and-Macros/Notations/ lean-lang.org/doc/reference/4.34.0/Notations-and-Macros/Notations/]&amp;lt;/ref&amp;gt;&lt;br /&gt;
Whatever a macro produces is then elaborated and checked exactly as if the user had typed&lt;br /&gt;
it. A macro can change what is written; it cannot prove anything that the text it produces&lt;br /&gt;
could not prove if typed by hand.&lt;br /&gt;
&lt;br /&gt;
The commands form a tower. The operator commands are shorthands for &amp;lt;code&amp;gt;notation&amp;lt;/code&amp;gt;.&lt;br /&gt;
In Ullrich and de Moura&#039;s account, &amp;lt;code&amp;gt;notation&amp;lt;/code&amp;gt; is itself a macro that generates a&lt;br /&gt;
&amp;lt;code&amp;gt;macro&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;macro&amp;lt;/code&amp;gt; expands into a grammar rule (&amp;lt;code&amp;gt;syntax&amp;lt;/code&amp;gt;)&lt;br /&gt;
paired with a rewriting rule (&amp;lt;code&amp;gt;macro_rules&amp;lt;/code&amp;gt;).&amp;lt;ref name=&amp;quot;bn&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;rm-ops&amp;quot; /&amp;gt;&lt;br /&gt;
In Lean 4.34.1, &amp;lt;code&amp;gt;notation&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;macro&amp;lt;/code&amp;gt; are each handled by an&lt;br /&gt;
elaborator that produces this pair directly.&amp;lt;ref name=&amp;quot;src-notation&amp;quot;&amp;gt;Lean 4 source code, version 4.34.1 (2026), files &amp;lt;code&amp;gt;src/Lean/Elab/Notation.lean&amp;lt;/code&amp;gt; (the functions &amp;lt;code&amp;gt;elabNotation&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;mkUnexpander&amp;lt;/code&amp;gt;) and &amp;lt;code&amp;gt;src/Lean/Elab/Macro.lean&amp;lt;/code&amp;gt; (the function &amp;lt;code&amp;gt;elabMacro&amp;lt;/code&amp;gt;). Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/Elab/Notation.lean&amp;lt;/ref&amp;gt; The&lt;br /&gt;
&amp;lt;code&amp;gt;syntax&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;macro_rules&amp;lt;/code&amp;gt; commands in turn become ordinary Lean&lt;br /&gt;
definitions that the parser and the macro expander consult.&amp;lt;ref name=&amp;quot;bn&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Operators ==&lt;br /&gt;
&lt;br /&gt;
The smallest extension names a binary operator.&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 avg (a b : Nat) : Nat := (a + b) / 2&lt;br /&gt;
&lt;br /&gt;
infixl:65 &amp;quot; ⊞ &amp;quot; =&amp;gt; avg&lt;br /&gt;
&lt;br /&gt;
#eval 2 ⊞ 4 ⊞ 10&lt;br /&gt;
#check fun (a b : Nat) =&amp;gt; avg a b&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;#eval&amp;lt;/code&amp;gt; prints &amp;lt;code&amp;gt;6&amp;lt;/code&amp;gt;: the operator associates to the left, so the&lt;br /&gt;
expression is &amp;lt;code&amp;gt;avg (avg 2 4) 10&amp;lt;/code&amp;gt;, that is &amp;lt;code&amp;gt;avg 3 10&amp;lt;/code&amp;gt;. The reference&lt;br /&gt;
manual gives the expansion exactly: &amp;lt;code&amp;gt;infixl:prec &amp;quot;op&amp;quot; =&amp;gt; f&amp;lt;/code&amp;gt; stands for&lt;br /&gt;
&amp;lt;code&amp;gt;notation:prec x:prec &amp;quot;op&amp;quot; y:prec1 =&amp;gt; f x y&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;prec1&amp;lt;/code&amp;gt; is one more&lt;br /&gt;
than &amp;lt;code&amp;gt;prec&amp;lt;/code&amp;gt;, so the left operand may itself be a use of the operator and the right&lt;br /&gt;
operand may not. A custom operator must state its precedence; there is no default.&amp;lt;ref name=&amp;quot;rm-ops&amp;quot;&amp;gt;&amp;quot;Custom Operators&amp;quot;, section 23.1 of &#039;&#039;The Lean Language Reference&#039;&#039; (edition covering Lean 4.34.0). [https://lean-lang.org/doc/reference/4.34.0/Notations-and-Macros/Custom-Operators/ lean-lang.org/doc/reference/4.34.0/Notations-and-Macros/Custom-Operators/]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;#check&amp;lt;/code&amp;gt; shows the other direction. Asked to print &amp;lt;code&amp;gt;avg a b&amp;lt;/code&amp;gt;, Lean&lt;br /&gt;
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;fun a b =&amp;gt; a ⊞ b : Nat → Nat → Nat&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The command has also generated an &#039;&#039;&#039;unexpander&#039;&#039;&#039;, a rule used when terms are displayed. A&lt;br /&gt;
notation gets one when its right-hand side applies a named function and each of its term&lt;br /&gt;
positions occurs there exactly once; a notation that expands to an anonymous function gets&lt;br /&gt;
none.&amp;lt;ref name=&amp;quot;rm-notations&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;rm-ops&amp;quot; /&amp;gt;&lt;br /&gt;
The operator therefore appears in goals and error messages, not only in source text.&lt;br /&gt;
&lt;br /&gt;
== Notation, syntax and macro rules ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;notation&amp;lt;/code&amp;gt; accepts any mixture of tokens and term positions, and its right-hand&lt;br /&gt;
side is a template. When a template is not enough, the two halves can be written separately.&lt;br /&gt;
&amp;lt;code&amp;gt;syntax&amp;lt;/code&amp;gt; adds a grammar rule to a &#039;&#039;&#039;syntax category&#039;&#039;&#039; (here &amp;lt;code&amp;gt;term&amp;lt;/code&amp;gt;),&lt;br /&gt;
and &amp;lt;code&amp;gt;macro_rules&amp;lt;/code&amp;gt; says how to rewrite 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;
syntax &amp;quot;∑ &amp;quot; ident &amp;quot; ∈ &amp;quot; term &amp;quot;, &amp;quot; term : term&lt;br /&gt;
&lt;br /&gt;
macro_rules&lt;br /&gt;
  | `(∑ $i ∈ $xs, $body) =&amp;gt; `(List.foldl (fun acc $i =&amp;gt; acc + $body) 0 $xs)&lt;br /&gt;
&lt;br /&gt;
#eval ∑ i ∈ [1, 2, 3, 4], i * i&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The output is &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;, the sum of the squares of 1 to 4. The pattern on the left of&lt;br /&gt;
&amp;lt;code&amp;gt;=&amp;gt;&amp;lt;/code&amp;gt; and the result on the right are &#039;&#039;&#039;syntax quotations&#039;&#039;&#039;, written&lt;br /&gt;
&amp;lt;code&amp;gt;`(...)&amp;lt;/code&amp;gt;. Inside them &amp;lt;code&amp;gt;$i&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$xs&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;$body&amp;lt;/code&amp;gt; are&lt;br /&gt;
&#039;&#039;&#039;antiquotations&#039;&#039;&#039;: holes that match syntax in a pattern and insert it in a result. A&lt;br /&gt;
quotation produces syntax, not a term; it is parsed but not elaborated.&amp;lt;ref name=&amp;quot;rm-macros&amp;quot;&amp;gt;&amp;quot;Macros&amp;quot;, section 23.5 of &#039;&#039;The Lean Language Reference&#039;&#039; (edition covering Lean 4.34.0), including 23.5.1 &amp;quot;Hygiene&amp;quot;, 23.5.3 &amp;quot;Quotation&amp;quot; and 23.5.5 &amp;quot;Defining Macros&amp;quot;. [https://lean-lang.org/doc/reference/4.34.0/Notations-and-Macros/Macros/ lean-lang.org/doc/reference/4.34.0/Notations-and-Macros/Macros/]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;macro_rules&amp;lt;/code&amp;gt; is open. More rules for the same syntax may be added later, in the&lt;br /&gt;
same file or another, and the most recently defined is tried first. A rule that does not&lt;br /&gt;
apply hands the syntax on to the next one, by throwing the exception&lt;br /&gt;
&amp;lt;code&amp;gt;unsupportedSyntax&amp;lt;/code&amp;gt;; any other exception is reported as an error. Only the&lt;br /&gt;
outermost layer of syntax is expanded at a time, and nested macros are expanded when the&lt;br /&gt;
elaborator reaches them.&amp;lt;ref name=&amp;quot;rm-macros&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Syntax categories are not limited to terms. Commands and tactics are categories too, and a&lt;br /&gt;
library may declare its own with &amp;lt;code&amp;gt;declare_syntax_cat&amp;lt;/code&amp;gt;. Ullrich and de Moura give an&lt;br /&gt;
example of why this matters: a big-operator file in Coq&#039;s Mathematical Components library&lt;br /&gt;
repeats twelve notations for index ranges once for each of three operators, because Coq&#039;s&lt;br /&gt;
notation system cannot abstract over the index syntax; with a category for index ranges,&lt;br /&gt;
each range form is interpreted once and every operator reuses it.&amp;lt;ref name=&amp;quot;bn&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== What hygiene prevents ==&lt;br /&gt;
&lt;br /&gt;
A macro is a function on syntax, and syntax contains names. Two kinds of accident follow&lt;br /&gt;
from that.&lt;br /&gt;
&lt;br /&gt;
The first is &#039;&#039;&#039;variable capture&#039;&#039;&#039;: a binder the macro introduces captures a name the user&lt;br /&gt;
supplied. Ullrich and de Moura&#039;s example is a notation for constant&lt;br /&gt;
functions.&amp;lt;ref name=&amp;quot;bn&amp;quot; /&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;
notation &amp;quot;const&amp;quot; e =&amp;gt; fun x =&amp;gt; e&lt;br /&gt;
&lt;br /&gt;
#check fun (x : Nat) =&amp;gt; const x&lt;br /&gt;
#eval (fun (x : Nat) =&amp;gt; const x) 1 2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Read as text substitution, &amp;lt;code&amp;gt;const x&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;fun x =&amp;gt; x&amp;lt;/code&amp;gt;, the&lt;br /&gt;
identity, and the whole expression would return its second argument. Lean 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;fun x x_1 =&amp;gt; x : (x : Nat) → ?m.2 x → Nat&lt;br /&gt;
1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The binder that the notation introduced has been renamed (Lean displays it as&lt;br /&gt;
&amp;lt;code&amp;gt;x_1&amp;lt;/code&amp;gt;), the user&#039;s &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt; still refers to the outer binder, and the&lt;br /&gt;
function returns its first argument. The mechanism is the &#039;&#039;&#039;macro scope&#039;&#039;&#039;. Each expansion of&lt;br /&gt;
a macro tags every identifier it introduces with a fresh scope, and a binder and a use of a&lt;br /&gt;
name match only if their tags agree.&amp;lt;ref name=&amp;quot;rm-macros&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;bn&amp;quot; /&amp;gt; The user&#039;s&lt;br /&gt;
&amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt; carries no tag and the macro&#039;s carries one, so they are different names.&lt;br /&gt;
&lt;br /&gt;
Hygiene can be switched off, and the same notation then captures.&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 hygiene false in&lt;br /&gt;
notation &amp;quot;const&#039;&amp;quot; e =&amp;gt; fun x =&amp;gt; e&lt;br /&gt;
&lt;br /&gt;
#eval (fun (x : Nat) =&amp;gt; const&#039; x) 1 2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This prints &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;, and Lean&#039;s linter warns that the outer &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt; is never&lt;br /&gt;
referenced: the macro&#039;s binder has taken it. The summation notation above is protected in&lt;br /&gt;
the same way. Its accumulator is called &amp;lt;code&amp;gt;acc&amp;lt;/code&amp;gt;, and a user&#039;s variable of that name&lt;br /&gt;
is not affected.&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;
#eval let acc := 100; ∑ i ∈ [1, 2, 3], acc * i&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The result is &amp;lt;code&amp;gt;600&amp;lt;/code&amp;gt;. Rewritten by plain substitution, the body&lt;br /&gt;
&amp;lt;code&amp;gt;acc * i&amp;lt;/code&amp;gt; would refer to the accumulator, which starts at 0, and the result would&lt;br /&gt;
be 0.&lt;br /&gt;
&lt;br /&gt;
The second kind of accident runs the other way: a local name at the use site captures a&lt;br /&gt;
global name the macro relies on.&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 double (n : Nat) : Nat := 2 * n&lt;br /&gt;
&lt;br /&gt;
macro &amp;quot;dbl! &amp;quot; e:term : term =&amp;gt; `(double $e)&lt;br /&gt;
&lt;br /&gt;
#eval let double := fun (n : Nat) =&amp;gt; n; dbl! 5&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The output is &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, and Lean warns that the local variable &amp;lt;code&amp;gt;double&amp;lt;/code&amp;gt; is&lt;br /&gt;
not referenced. The identifier &amp;lt;code&amp;gt;double&amp;lt;/code&amp;gt; in the quotation carries the macro&#039;s scope&lt;br /&gt;
and the local binding at the use site does not, so the two do not match. When the quotation&lt;br /&gt;
&amp;lt;code&amp;gt;`(double $e)&amp;lt;/code&amp;gt; was compiled, the name was also resolved to the global function and&lt;br /&gt;
recorded with it, so a global of the same name introduced later cannot redirect it&lt;br /&gt;
either.&amp;lt;ref name=&amp;quot;rm-macros&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;bn&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hygiene in tactics ==&lt;br /&gt;
&lt;br /&gt;
Tactics form a syntax category, so a tactic can be a macro (the&lt;br /&gt;
[[Lean theorem prover/System/The tactic framework|tactic framework]] treats the result like&lt;br /&gt;
any other tactic). This one introduces a hypothesis and uses 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;
macro &amp;quot;intro_assumption&amp;quot; : tactic =&amp;gt; `(tactic| (intro h; exact h))&lt;br /&gt;
&lt;br /&gt;
example (p : Prop) : p → p := by intro_assumption&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The proof is accepted. The name &amp;lt;code&amp;gt;h&amp;lt;/code&amp;gt;, however, belongs to the macro. A script that&lt;br /&gt;
uses a macro to introduce &amp;lt;code&amp;gt;h&amp;lt;/code&amp;gt; and then refers to &amp;lt;code&amp;gt;h&amp;lt;/code&amp;gt; itself fails.&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;
macro &amp;quot;intro_hyp&amp;quot; : tactic =&amp;gt; `(tactic| intro h)&lt;br /&gt;
&lt;br /&gt;
example (p : Prop) : p → p := by&lt;br /&gt;
  intro_hyp&lt;br /&gt;
  exact h&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean reports &amp;lt;code&amp;gt;Unknown identifier `h`&amp;lt;/code&amp;gt; at the last line. The hypothesis exists,&lt;br /&gt;
but under a name the user cannot type:&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;
macro &amp;quot;intro_hyp&amp;quot; : tactic =&amp;gt; `(tactic| intro h)&lt;br /&gt;
&lt;br /&gt;
example (p : Prop) : p → p := by&lt;br /&gt;
  intro_hyp&lt;br /&gt;
  trace_state&lt;br /&gt;
  assumption&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;p : Prop&lt;br /&gt;
h✝ : p&lt;br /&gt;
⊢ p&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The dagger marks an inaccessible name, and &amp;lt;code&amp;gt;assumption&amp;lt;/code&amp;gt;, which does not need the&lt;br /&gt;
name, closes the goal. Ullrich and de Moura report that Lean 3&#039;s tactic quotations had both&lt;br /&gt;
faults: a short tactic script for injectivity lemmas broke when it was used from a library&lt;br /&gt;
for homotopy type theory that defined its own &amp;lt;code&amp;gt;propext&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;Iff.intro&amp;lt;/code&amp;gt;, and scripts could refer to names a tactic had introduced. They&lt;br /&gt;
describe Lean 4&#039;s tactic language as, to their knowledge, the first in an established theorem&lt;br /&gt;
prover to be hygienic automatically in this sense.&amp;lt;ref name=&amp;quot;bn&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mathematics in its own notation ==&lt;br /&gt;
&lt;br /&gt;
Mathematics is written in notation that varies by field and by author, and much of it binds&lt;br /&gt;
variables: sums, products, integrals, set-builder notation, quantifiers over a finite set. A&lt;br /&gt;
fixed grammar forces a formal text away from that notation. Lean&#039;s macros let a library add&lt;br /&gt;
it, with three properties that matter in practice.&lt;br /&gt;
&lt;br /&gt;
Binding notation is safe to define. A notation that introduces its own bound variables, such&lt;br /&gt;
as the sum above, does not interfere with the names its user chooses, and the user need not&lt;br /&gt;
know which names it uses inside. Without hygiene, every such notation would be a hazard of&lt;br /&gt;
the kind shown in the &amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; example.&lt;br /&gt;
&lt;br /&gt;
Notation is printed back. Because an unexpander is generated where possible, goals and error&lt;br /&gt;
messages show the notation the reader wrote, not the function it stands for.&lt;br /&gt;
&lt;br /&gt;
Notation can be confined. A notation marked &amp;lt;code&amp;gt;scoped&amp;lt;/code&amp;gt; is active only where its&lt;br /&gt;
namespace is open, so a field&#039;s notation need not occupy the grammar of every other field.&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 avg (a b : Nat) : Nat := (a + b) / 2&lt;br /&gt;
&lt;br /&gt;
namespace Averages&lt;br /&gt;
scoped infixl:65 &amp;quot; ⊞ &amp;quot; =&amp;gt; avg&lt;br /&gt;
end Averages&lt;br /&gt;
&lt;br /&gt;
open Averages in&lt;br /&gt;
#eval 2 ⊞ 4 ⊞ 10&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This prints &amp;lt;code&amp;gt;6&amp;lt;/code&amp;gt;. Without the &amp;lt;code&amp;gt;open&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;⊞&amp;lt;/code&amp;gt; is not part of the&lt;br /&gt;
grammar:&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;
def avg (a b : Nat) : Nat := (a + b) / 2&lt;br /&gt;
&lt;br /&gt;
namespace Averages&lt;br /&gt;
scoped infixl:65 &amp;quot; ⊞ &amp;quot; =&amp;gt; avg&lt;br /&gt;
end Averages&lt;br /&gt;
&lt;br /&gt;
#check (2 ⊞ 4 : Nat)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean stops at the operator with the parse error &amp;lt;code&amp;gt;expected token&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
What notation does not do is add meaning. It changes how a statement is written and read,&lt;br /&gt;
and nothing that the Lean kernel checks. That is also its risk. A statement that uses&lt;br /&gt;
unfamiliar notation may not say what it appears to say, and the reference manual&#039;s guidance&lt;br /&gt;
on validating a proof names custom notation among the things to investigate when there is&lt;br /&gt;
doubt that a theorem states what was intended.&amp;lt;ref name=&amp;quot;rm-validating&amp;quot;&amp;gt;&amp;quot;Validating a Lean Proof&amp;quot;, a chapter of &#039;&#039;The Lean Language Reference&#039;&#039; (edition covering Lean 4.34.0), section &amp;quot;Remaining Issues&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;
&lt;br /&gt;
A macro sees only syntax. When a translation depends on types, for example on whether an&lt;br /&gt;
argument is a natural number or a set, a macro cannot decide it, and an &#039;&#039;&#039;elaborator&#039;&#039;&#039; is&lt;br /&gt;
needed: a Lean program that runs inside the elaborator and constructs terms directly.&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/System/Metaprogramming in Lean|Metaprogramming in Lean]] shows how&lt;br /&gt;
elaborators and tactics are written as Lean programs.&lt;br /&gt;
[[Lean theorem prover/System/Monads and do-notation|Monads and do-notation]] describes a&lt;br /&gt;
piece of syntax that Lean translates into ordinary terms: the &amp;lt;code&amp;gt;do&amp;lt;/code&amp;gt; block.&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>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/System/Decision_procedures&amp;diff=6791</id>
		<title>Lean theorem prover/System/Decision procedures</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/System/Decision_procedures&amp;diff=6791"/>
		<updated>2026-10-15T19:35:12Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Decision procedures}}&lt;br /&gt;
{{Plebeian|Lean theorem prover/Explainers/Automation and its limits|Lean theorem prover/Explainers/Computation inside proofs}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;decision procedure&#039;&#039;&#039; is an algorithm that settles every question in a fixed class, answering yes or no. In Lean such an algorithm is useful only when its yes comes with evidence that the Lean kernel accepts. This page treats five tactics that automate whole classes of goals in Lean 4.34.1: &amp;lt;code&amp;gt;decide&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;omega&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;simp&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;grind&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;bv_decide&amp;lt;/code&amp;gt;. For each it says what the tactic covers, what evidence it hands to the Lean kernel, and what a reader must trust beyond the Lean kernel.&lt;br /&gt;
&lt;br /&gt;
== Three kinds of evidence ==&lt;br /&gt;
&lt;br /&gt;
Every tactic ends by assigning a term to the goal&#039;s metavariable, as described on [[Lean theorem prover/System/The tactic framework|the tactic framework]], and the Lean kernel checks that term when the theorem is added. The procedures below differ in the shape of the term.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;An ordinary proof term.&#039;&#039;&#039; The tactic searches, then assembles a proof from library lemmas. &amp;lt;code&amp;gt;omega&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;simp&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;grind&amp;lt;/code&amp;gt; work this way. The search is untrusted; only its output is checked.&lt;br /&gt;
# &#039;&#039;&#039;Proof by reflection.&#039;&#039;&#039; A Boolean function is written in Lean and proved correct once. The tactic reduces the goal to the claim that this function returns &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; on some input, and the Lean kernel confirms the claim by evaluating the function during its definitional equality check. &amp;lt;code&amp;gt;decide&amp;lt;/code&amp;gt; works this way.&lt;br /&gt;
# &#039;&#039;&#039;An asserted evaluation.&#039;&#039;&#039; As in reflection, but the function is run by compiled code and its result is added to Lean&#039;s environment, its table of definitions and theorems, as a new axiom. &amp;lt;code&amp;gt;bv_decide&amp;lt;/code&amp;gt; works this way. The Lean compiler then joins the trusted base.&lt;br /&gt;
&lt;br /&gt;
The command &amp;lt;code&amp;gt;#print axioms&amp;lt;/code&amp;gt; tells the three apart: the first two leave only Lean&#039;s standard axioms (described on [[Lean theorem prover/Foundations/The three axioms|the three axioms]]), the third leaves an extra one.&lt;br /&gt;
&lt;br /&gt;
== decide ==&lt;br /&gt;
&lt;br /&gt;
A proposition &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt; is decidable when there is an instance of the class &amp;lt;code&amp;gt;Decidable p&amp;lt;/code&amp;gt;. The class is an inductive type with two constructors, one carrying a proof of &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt; and one a proof of its negation:&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 Decidable&lt;br /&gt;
#synth Decidable (∀ x : Fin 4, x.val * x.val &amp;amp;lt; 10)&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;&lt;br /&gt;
inductive Decidable : Prop → Type&lt;br /&gt;
number of parameters: 1&lt;br /&gt;
constructors:&lt;br /&gt;
Decidable.isFalse : {p : Prop} → ¬p → Decidable p&lt;br /&gt;
Decidable.isTrue : {p : Prop} → p → Decidable p&lt;br /&gt;
Nat.decidableForallFin fun x =&amp;gt; ↑x * ↑x &amp;amp;lt; 10&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Instances compose: a bounded quantifier over &amp;lt;code&amp;gt;Fin 4&amp;lt;/code&amp;gt; is decidable because each instance of its body is, and instance resolution (see [[Lean theorem prover/System/Type classes and instance resolution|type classes and instance resolution]]) assembles the instance. The tactic &amp;lt;code&amp;gt;decide&amp;lt;/code&amp;gt; synthesises such an instance for the goal and reduces it; if it reaches &amp;lt;code&amp;gt;isTrue h&amp;lt;/code&amp;gt;, then &amp;lt;code&amp;gt;h&amp;lt;/code&amp;gt; proves the goal.&amp;lt;ref name=&amp;quot;src-tactics&amp;quot;&amp;gt;Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Init/Tactics.lean&amp;lt;/code&amp;gt;: the documentation strings of the tactics &amp;lt;code&amp;gt;decide&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;omega&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;bv_decide&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Init/Tactics.lean&amp;lt;/ref&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;
theorem small : 2 ^ 10 = 1024 ∧ 3 &amp;amp;lt; 5 := by decide&lt;br /&gt;
#print small&lt;br /&gt;
#print axioms small&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;
theorem small : 2 ^ 10 = 1024 ∧ 3 &amp;amp;lt; 5 :=&lt;br /&gt;
of_decide_eq_true (id (Eq.refl true))&lt;br /&gt;
&#039;small&#039; does not depend on any axioms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The proof term is short because the work is moved into checking it. For &amp;lt;code&amp;gt;Eq.refl true&amp;lt;/code&amp;gt; to have type &amp;lt;code&amp;gt;decide p = true&amp;lt;/code&amp;gt;, the Lean kernel must reduce &amp;lt;code&amp;gt;decide p&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;, which is the computation itself. This is [[Lean theorem prover/Foundations/Definitional equality|definitional equality]] put to use. On a false proposition the same evaluation yields a refutation, and the tactic reports it:&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;
example : ∀ x : Fin 5, x.val * x.val &amp;amp;lt; 10 := by decide&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;
error: Tactic `decide` proved that the proposition&lt;br /&gt;
  ∀ (x : Fin 5), ↑x * ↑x &amp;amp;lt; 10&lt;br /&gt;
is false&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The limits follow from the method. The goal may contain no local variables or metavariables; on &amp;lt;code&amp;gt;n + 0 = n&amp;lt;/code&amp;gt; for a variable &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;, Lean says &amp;lt;code&amp;gt;Expected type must not contain free variables&amp;lt;/code&amp;gt; and suggests the option &amp;lt;code&amp;gt;+revert&amp;lt;/code&amp;gt;, which first moves such variables into the goal as universally quantified ones. Instances defined by well-founded recursion may not reduce, and reduction can get stuck on instances built with rewriting tactics. The option &amp;lt;code&amp;gt;decide +kernel&amp;lt;/code&amp;gt; hands the reduction to the Lean kernel directly, and &amp;lt;code&amp;gt;decide +native&amp;lt;/code&amp;gt; runs compiled code and admits the result through an axiom. Its documentation says this can be significantly more efficient, but comes &amp;quot;at the cost of increasing the size of the trusted code base&amp;quot;.&amp;lt;ref name=&amp;quot;src-tactics&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== omega ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;omega&amp;lt;/code&amp;gt; proves goals in linear arithmetic over &amp;lt;code&amp;gt;Int&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Nat&amp;lt;/code&amp;gt;. It accepts hypotheses of the forms &amp;lt;code&amp;gt;x = y&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;x &amp;amp;lt; y&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;x ≤ y&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;k ∣ x&amp;lt;/code&amp;gt; for a literal &amp;lt;code&amp;gt;k&amp;lt;/code&amp;gt;, with their negations; it splits both sides into linear combinations of atoms, and for &amp;lt;code&amp;gt;x / k&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;x % k&amp;lt;/code&amp;gt; with a literal &amp;lt;code&amp;gt;k&amp;lt;/code&amp;gt; it introduces a new variable together with the two inequalities that bound it.&amp;lt;ref name=&amp;quot;src-tactics&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;src-omega&amp;quot; /&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;
theorem bound (x y : Nat) (h₁ : x + 2 * y ≤ 10) (h₂ : 3 &amp;amp;lt; x) : y ≤ 3 := by&lt;br /&gt;
  omega&lt;br /&gt;
&lt;br /&gt;
example (a b : Int) (h : 2 * a + 1 = 2 * b) : False := by&lt;br /&gt;
  omega&lt;br /&gt;
&lt;br /&gt;
example (n : Nat) : n / 2 + n % 2 ≤ n := by&lt;br /&gt;
  omega&lt;br /&gt;
&lt;br /&gt;
#print axioms bound&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The last line prints &amp;lt;code&amp;gt;&#039;bound&#039; depends on axioms: [propext, Quot.sound]&amp;lt;/code&amp;gt;: the proof is an ordinary term. The method is William Pugh&#039;s omega test of 1991, an extension of Fourier–Motzkin variable elimination from the reals to the integers.&amp;lt;ref name=&amp;quot;pugh&amp;quot;&amp;gt;William Pugh, &amp;quot;The Omega test: a fast and practical integer programming algorithm for dependence analysis&amp;quot;, &#039;&#039;Proceedings of the 1991 ACM/IEEE Conference on Supercomputing (Supercomputing &#039;91)&#039;&#039;, ACM, 1991, pp. 4–13. doi:10.1145/125826.125848. Read in an expanded version whose first page states that it appeared in &#039;&#039;Communications of the ACM&#039;&#039; in August 1992, there titled &amp;quot;A practical algorithm for exact array dependence analysis&amp;quot;, 35(8), pp. 102–114, doi:10.1145/135226.135233.&amp;lt;/ref&amp;gt; Eliminating a variable from a set of integer inequalities yields Pugh&#039;s &#039;&#039;&#039;real shadow&#039;&#039;&#039;, which may have integer points that lift to no integer solution, and his &#039;&#039;&#039;dark shadow&#039;&#039;&#039;, whose integer points always lift; when the two coincide the elimination is exact.&amp;lt;ref name=&amp;quot;pugh&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean&#039;s implementation states its own limits. Its notes say that it follows Pugh&#039;s paper closely but leaves out the dark and grey shadows, so when the real shadow is satisfiable it fails rather than deciding. It prefers to eliminate a variable for which elimination is exact: all upper bounds, or all lower bounds, with unit coefficient. The notes record that failures from the missing shadows appear to be rare in practice.&amp;lt;ref name=&amp;quot;src-omega&amp;quot;&amp;gt;Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Lean/Elab/Tactic/Omega.lean&amp;lt;/code&amp;gt;: implementation notes of the &amp;lt;code&amp;gt;omega&amp;lt;/code&amp;gt; tactic. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/Elab/Tactic/Omega.lean&amp;lt;/ref&amp;gt; The tactic&#039;s documentation accordingly calls it &amp;quot;not yet a full decision procedure&amp;quot;.&amp;lt;ref name=&amp;quot;src-tactics&amp;quot; /&amp;gt; Each derived constraint carries a record of how it was obtained, and when a contradiction appears that record is turned into the proof term.&amp;lt;ref name=&amp;quot;src-omega&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Products of variables are outside the fragment. &amp;lt;code&amp;gt;omega&amp;lt;/code&amp;gt; treats &amp;lt;code&amp;gt;x * y&amp;lt;/code&amp;gt; as an atom, an unknown like any other,&amp;lt;ref name=&amp;quot;src-omega&amp;quot; /&amp;gt; and, on failure, prints constraints that a counterexample might satisfy:&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;
example (x y : Nat) (h : x * y = 6) : x ≤ 6 := by&lt;br /&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;
error: omega could not prove the goal:&lt;br /&gt;
a possible counterexample may satisfy the constraints&lt;br /&gt;
  a ≥ 7&lt;br /&gt;
where&lt;br /&gt;
 a := ↑x&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== simp ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;simp&amp;lt;/code&amp;gt; is not a decision procedure. It is a rewriting engine: the reference manual describes it as performing inside-out rewriting of terms from a database of simplification rules.&amp;lt;ref name=&amp;quot;manual-simp&amp;quot;&amp;gt;Lean Developers, &#039;&#039;The Lean Language Reference&#039;&#039;, version 4.34.0, chapter &amp;quot;The Simplifier&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/The-Simplifier/&amp;lt;/ref&amp;gt; The database is the &#039;&#039;&#039;simp set&#039;&#039;&#039;: every theorem marked &amp;lt;code&amp;gt;@[simp]&amp;lt;/code&amp;gt;, read as an equation to be used from left to right, together with any lemmas named in the call.&amp;lt;ref name=&amp;quot;lean4-paper&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 &#039;&#039;Automated Deduction – CADE 28&#039;&#039;, Lecture Notes in Computer Science 12699, Springer, 2021, pp. 625–635. doi:10.1007/978-3-030-79876-5_37&amp;lt;/ref&amp;gt; A goal is closed when it rewrites to &amp;lt;code&amp;gt;True&amp;lt;/code&amp;gt;. The option &amp;lt;code&amp;gt;trace.Meta.Tactic.simp.rewrite&amp;lt;/code&amp;gt; shows each step:&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 rev : List α → List α&lt;br /&gt;
  | [] =&amp;gt; []&lt;br /&gt;
  | a :: as =&amp;gt; rev as ++ [a]&lt;br /&gt;
&lt;br /&gt;
@[simp] theorem rev_nil : rev ([] : List α) = [] := rfl&lt;br /&gt;
@[simp] theorem rev_cons (a : α) (as : List α) :&lt;br /&gt;
    rev (a :: as) = rev as ++ [a] := rfl&lt;br /&gt;
&lt;br /&gt;
set_option trace.Meta.Tactic.simp.rewrite true in&lt;br /&gt;
example (a b : Nat) : rev [a, b] = [b, a] := by&lt;br /&gt;
  simp&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;
[Meta.Tactic.simp.rewrite] rev_cons:1000:&lt;br /&gt;
      rev [a, b]&lt;br /&gt;
    ==&amp;gt;&lt;br /&gt;
      rev [b] ++ [a]&lt;br /&gt;
[Meta.Tactic.simp.rewrite] rev_cons:1000:&lt;br /&gt;
      rev [b]&lt;br /&gt;
    ==&amp;gt;&lt;br /&gt;
      rev [] ++ [b]&lt;br /&gt;
[Meta.Tactic.simp.rewrite] rev_nil:1000:&lt;br /&gt;
      rev []&lt;br /&gt;
    ==&amp;gt;&lt;br /&gt;
      []&lt;br /&gt;
[Meta.Tactic.simp.rewrite] List.nil_append:1000:&lt;br /&gt;
      [] ++ [b]&lt;br /&gt;
    ==&amp;gt;&lt;br /&gt;
      [b]&lt;br /&gt;
[Meta.Tactic.simp.rewrite] List.cons_append:1000:&lt;br /&gt;
      [b] ++ [a]&lt;br /&gt;
    ==&amp;gt;&lt;br /&gt;
      b :: ([] ++ [a])&lt;br /&gt;
[Meta.Tactic.simp.rewrite] List.nil_append:1000:&lt;br /&gt;
      [] ++ [a]&lt;br /&gt;
    ==&amp;gt;&lt;br /&gt;
      [a]&lt;br /&gt;
[Meta.Tactic.simp.rewrite] eq_self:1000:&lt;br /&gt;
      [b, a] = [b, a]&lt;br /&gt;
    ==&amp;gt;&lt;br /&gt;
      True&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The number after each lemma name is its priority. Two of the lemmas come from this page, the rest from Lean&#039;s library. The variant &amp;lt;code&amp;gt;simp?&amp;lt;/code&amp;gt; reports a &amp;lt;code&amp;gt;simp only [...]&amp;lt;/code&amp;gt; call naming just the lemmas used; pasted in its place, it makes the proof independent of later changes to the library&#039;s simp set. Whether &amp;lt;code&amp;gt;simp&amp;lt;/code&amp;gt; succeeds depends on the simp set as much as on the goal: it answers no question by itself. Its proof is assembled from the lemmas it used and is checked by the Lean kernel like any other term.&lt;br /&gt;
&lt;br /&gt;
== grind ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;grind&amp;lt;/code&amp;gt; is part of core Lean in version 4.34.1 and needs no import. Its documentation calls it inspired by modern SMT solvers. It keeps one shared collection of facts, groups terms known to be equal by &#039;&#039;&#039;congruence closure&#039;&#039;&#039;, instantiates theorems by &#039;&#039;&#039;E-matching&#039;&#039;&#039; (matching a theorem&#039;s pattern modulo the equalities known so far), splits cases, and passes facts to specialised solvers for linear integer arithmetic, for commutative rings and fields, and for linear arithmetic (its &amp;lt;code&amp;gt;linarith&amp;lt;/code&amp;gt; component).&amp;lt;ref name=&amp;quot;src-grind&amp;quot;&amp;gt;Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Init/Grind/Tactics.lean&amp;lt;/code&amp;gt;: the documentation string of the &amp;lt;code&amp;gt;grind&amp;lt;/code&amp;gt; tactic. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Init/Grind/Tactics.lean&amp;lt;/ref&amp;gt; The reference manual states that it &amp;quot;produces ordinary Lean proof terms for every fact it adds&amp;quot;.&amp;lt;ref name=&amp;quot;manual-grind&amp;quot;&amp;gt;Lean Developers, &#039;&#039;The Lean Language Reference&#039;&#039;, version 4.34.0, chapter &amp;quot;The grind tactic&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/The--grind--tactic/&amp;lt;/ref&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 f (a : Nat) : Nat := a + 1&lt;br /&gt;
def g (a : Nat) : Nat := a - 1&lt;br /&gt;
&lt;br /&gt;
@[grind =] theorem g_f (x : Nat) : g (f x) = x := by&lt;br /&gt;
  simp [f, g]&lt;br /&gt;
&lt;br /&gt;
theorem grind_demo {a b : Nat} (h : f b = a) : g a = b := by&lt;br /&gt;
  grind&lt;br /&gt;
&lt;br /&gt;
example {x y : Int} : 2 * x + 4 * y ≠ 5 := by&lt;br /&gt;
  grind&lt;br /&gt;
&lt;br /&gt;
#print axioms grind_demo&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The attribute &amp;lt;code&amp;gt;@[grind =]&amp;lt;/code&amp;gt; makes the left side &amp;lt;code&amp;gt;g (f x)&amp;lt;/code&amp;gt; a pattern. The goal mentions &amp;lt;code&amp;gt;g a&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;g (f b)&amp;lt;/code&amp;gt;; but &amp;lt;code&amp;gt;h&amp;lt;/code&amp;gt; puts &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f b&amp;lt;/code&amp;gt; in one equality class, so the pattern matches modulo that equality and congruence closure finishes the proof. The second example, taken from the tactic&#039;s documentation, is linear integer arithmetic: &amp;lt;code&amp;gt;2 * x + 4 * y&amp;lt;/code&amp;gt; is even and 5 is not. The last line prints &amp;lt;code&amp;gt;&#039;grind_demo&#039; depends on axioms: [propext, Classical.choice, Quot.sound]&amp;lt;/code&amp;gt;, the standard three and nothing more. Its documentation warns that &amp;lt;code&amp;gt;grind&amp;lt;/code&amp;gt; is not designed for problems whose search space explodes combinatorially, and points to &amp;lt;code&amp;gt;bv_decide&amp;lt;/code&amp;gt; for bit-level and combinatorial problems.&amp;lt;ref name=&amp;quot;src-grind&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== bv_decide ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bv_decide&amp;lt;/code&amp;gt; closes goals about fixed-width bit vectors (&amp;lt;code&amp;gt;BitVec n&amp;lt;/code&amp;gt;) and &amp;lt;code&amp;gt;Bool&amp;lt;/code&amp;gt;: the Lean counterpart of the SMT-LIB logic QF_BV. It needs &amp;lt;code&amp;gt;import Std.Tactic.BVDecide&amp;lt;/code&amp;gt;, and on failure it prints a counterexample.&amp;lt;ref name=&amp;quot;src-tactics&amp;quot; /&amp;gt; Its implementation notes give the steps. It starts a proof by contradiction, normalises the hypotheses with a simp set, and represents the problem as a Lean value of a syntax-tree type. A verified bit-blaster turns that value into an and-inverter graph and then into a formula in conjunctive normal form. The SAT solver CaDiCaL, which is shipped beside the &amp;lt;code&amp;gt;lean&amp;lt;/code&amp;gt; executable, is asked for an LRAT proof that the formula is unsatisfiable. That proof is checked by an LRAT checker with a soundness proof in Lean, and the proofs so far are chained back to the goal.&amp;lt;ref name=&amp;quot;src-bvdecide&amp;quot;&amp;gt;Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Lean/Elab/Tactic/BVDecide.lean&amp;lt;/code&amp;gt;: the overview of &amp;lt;code&amp;gt;bv_decide&amp;lt;/code&amp;gt;, sections &amp;quot;Architecture&amp;quot; and &amp;quot;Axioms&amp;quot;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/Elab/Tactic/BVDecide.lean&amp;lt;/ref&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;
import Std.Tactic.BVDecide&lt;br /&gt;
&lt;br /&gt;
theorem add_as_xor (x y : BitVec 8) :&lt;br /&gt;
    x + y = (x ^^^ y) + ((x &amp;amp;amp;&amp;amp;amp;&amp;amp;amp; y) &amp;amp;lt;&amp;amp;lt;&amp;amp;lt; 1) := by&lt;br /&gt;
  bv_decide&lt;br /&gt;
&lt;br /&gt;
#print axioms add_as_xor&lt;br /&gt;
#print add_as_xor._native.bv_decide.ax_1_5&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;
&#039;add_as_xor&#039; depends on axioms: [propext, Classical.choice, Quot.sound, add_as_xor._native.bv_decide.ax_1_5]&lt;br /&gt;
axiom add_as_xor._native.bv_decide.ax_1_5 : Std.Tactic.BVDecide.Reflect.verifyBVExpr add_as_xor._expr_def_1_1&lt;br /&gt;
    add_as_xor._cert_def_1_1 =&lt;br /&gt;
  true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The output states the trust story exactly. The fourth axiom says that one Boolean function, &amp;lt;code&amp;gt;verifyBVExpr&amp;lt;/code&amp;gt;, returns &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; on the encoded problem and on the certificate string the solver produced. In Lean&#039;s library, &amp;lt;code&amp;gt;verifyBVExpr&amp;lt;/code&amp;gt; bit-blasts the problem and checks the certificate against the resulting formula, and the theorem &amp;lt;code&amp;gt;unsat_of_verifyBVExpr_eq_true&amp;lt;/code&amp;gt; proves that a &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; result means the problem is unsatisfiable.&amp;lt;ref name=&amp;quot;src-reflect&amp;quot;&amp;gt;Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Std/Tactic/BVDecide/Reflect.lean&amp;lt;/code&amp;gt;: the definition &amp;lt;code&amp;gt;verifyBVExpr&amp;lt;/code&amp;gt; and the theorem &amp;lt;code&amp;gt;unsat_of_verifyBVExpr_eq_true&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Std/Tactic/BVDecide/Reflect.lean&amp;lt;/ref&amp;gt; So the result relies on three things: the Lean kernel, which checks the soundness theorems and the chain of reasoning around the axiom; the compiled evaluation of &amp;lt;code&amp;gt;verifyBVExpr&amp;lt;/code&amp;gt;, which is what the axiom asserts; and therefore the Lean compiler that produced that code, together with any definition whose compiled form is replaced by another implementation through &amp;lt;code&amp;gt;@[implemented_by]&amp;lt;/code&amp;gt;, a dependency the documentation of &amp;lt;code&amp;gt;decide +native&amp;lt;/code&amp;gt; spells out for the same mechanism.&amp;lt;ref name=&amp;quot;src-tactics&amp;quot; /&amp;gt; The implementation notes say so: the result of the compiled check is added as an axiom, &amp;quot;thus adding the Lean compiler to the trusted code base&amp;quot;.&amp;lt;ref name=&amp;quot;src-bvdecide&amp;quot; /&amp;gt; The SAT solver is not trusted. A wrong certificate makes the check return &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt; and the tactic fails. The Lean kernel does not repeat the bit-level computation itself.&lt;br /&gt;
&lt;br /&gt;
The reference manual&#039;s page on validating proofs records that up to version 4.28.0 every such use showed up in &amp;lt;code&amp;gt;#print axioms&amp;lt;/code&amp;gt; as one shared axiom, &amp;lt;code&amp;gt;Lean.trustCompiler&amp;lt;/code&amp;gt;, and that since 4.29.0 these tactics instead introduce one dedicated axiom for each computation, as above.&amp;lt;ref name=&amp;quot;manual-validating&amp;quot;&amp;gt;Lean Developers, &#039;&#039;The Lean Language Reference&#039;&#039;, version 4.34.0, &amp;quot;Validating a Lean Proof&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/ValidatingProofs/&amp;lt;/ref&amp;gt; In 4.34.1 the older primitive &amp;lt;code&amp;gt;Lean.ofReduceBool&amp;lt;/code&amp;gt; still exists; &amp;lt;code&amp;gt;#check @Lean.ofReduceBool&amp;lt;/code&amp;gt; answers with the warning that native reduction inside the Lean kernel is deprecated. For the older mechanism the manual states that external checkers cannot check such proofs, having no access to the Lean compiler, and that proofs needing that level of checking must avoid native evaluation.&amp;lt;ref name=&amp;quot;manual-validating&amp;quot; /&amp;gt; Under the newer one a checker sees, in the list of axioms, exactly which computation it is asked to take on trust. [[Lean theorem prover/System/Proof export and independent checkers|Proof export and independent checkers]] takes this up.&lt;br /&gt;
&lt;br /&gt;
A false bit-vector claim is refuted with values:&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;
import Std.Tactic.BVDecide&lt;br /&gt;
&lt;br /&gt;
example (x y : BitVec 4) : x * y = x + y := by&lt;br /&gt;
  bv_decide&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;
error: The prover found a counterexample, consider the following assignment:&lt;br /&gt;
x = 15#4&lt;br /&gt;
y = 15#4&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Indeed 15 × 15 = 225, which is 1 modulo 16, while 15 + 15 = 30, which is 14.&lt;br /&gt;
&lt;br /&gt;
== Side by side ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tactic !! Covers !! Evidence !! Trusted beyond the Lean kernel&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;decide&amp;lt;/code&amp;gt; || propositions with a &amp;lt;code&amp;gt;Decidable&amp;lt;/code&amp;gt; instance that reduces || reflection, evaluated by the Lean kernel || nothing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;omega&amp;lt;/code&amp;gt; || linear arithmetic over &amp;lt;code&amp;gt;Int&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Nat&amp;lt;/code&amp;gt; (incomplete) || ordinary proof term || nothing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;simp&amp;lt;/code&amp;gt; || whatever the simp set rewrites to &amp;lt;code&amp;gt;True&amp;lt;/code&amp;gt; || ordinary proof term || nothing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;grind&amp;lt;/code&amp;gt; || equalities, theorem instances, case splits, arithmetic || ordinary proof term || nothing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;bv_decide&amp;lt;/code&amp;gt; || fixed-width bit vectors and &amp;lt;code&amp;gt;Bool&amp;lt;/code&amp;gt; || asserted evaluation of a verified checker || the Lean compiler and the compiled code&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In every row the search can be wrong without harm: a mistaken search produces a term the Lean kernel rejects, or no term. Only the last row moves part of the checking out of the Lean kernel.&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/System/Syntax extension and hygienic macros|Syntax extension and hygienic macros]] shows how new notation, and new tactics, are added to the language.&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>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/System/The_tactic_framework&amp;diff=6790</id>
		<title>Lean theorem prover/System/The tactic framework</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/System/The_tactic_framework&amp;diff=6790"/>
		<updated>2026-10-15T19:35:10Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:The tactic framework}}&lt;br /&gt;
{{Plebeian|Lean theorem prover/Explainers/Tactics|Lean theorem prover/Explainers/Holes and goals}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;tactic&#039;&#039;&#039; is a program that constructs part of a proof term. The &#039;&#039;&#039;tactic framework&#039;&#039;&#039; is what such programs act on: a list of goals, each one a metavariable, inside a monad that gives access to everything the elaborator can do. This page describes the framework in Lean 4.34.1: how a &amp;lt;code&amp;gt;by&amp;lt;/code&amp;gt; block enters elaboration, what a goal is, the monad &amp;lt;code&amp;gt;TacticM&amp;lt;/code&amp;gt;, the combinators that join tactics, a new tactic defined in three lines, and the library-search tactics &amp;lt;code&amp;gt;exact?&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;apply?&amp;lt;/code&amp;gt;. The idea of a tactic goes back to the LCF system; [[Lean theorem prover/History/LCF and the tactic idea|LCF and the tactic idea]] tells that history.&lt;br /&gt;
&lt;br /&gt;
== A by block is a hole ==&lt;br /&gt;
&lt;br /&gt;
The reference manual states that &amp;lt;code&amp;gt;by tac&amp;lt;/code&amp;gt; constructs a term of the expected type by running the tactics &amp;lt;code&amp;gt;tac&amp;lt;/code&amp;gt;, and that tactics construct proof terms behind the scenes.&amp;lt;ref name=&amp;quot;manual-tactics&amp;quot;&amp;gt;Lean Developers, &#039;&#039;The Lean Language Reference&#039;&#039;, version 4.34.0, chapter &amp;quot;Tactic Proofs&amp;quot;, with its section &amp;quot;Running Tactics&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/Tactic-Proofs/&amp;lt;/ref&amp;gt; When the elaborator meets &amp;lt;code&amp;gt;by&amp;lt;/code&amp;gt;, it does not run the tactics at once. It creates a metavariable of the expected type, of the synthetic opaque kind, and registers the tactic code to be run later.&amp;lt;ref name=&amp;quot;src-termelab&amp;quot;&amp;gt;Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Lean/Elab/Term/TermElabM.lean&amp;lt;/code&amp;gt;: the function &amp;lt;code&amp;gt;mkTacticMVar&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/Elab/Term/TermElabM.lean&amp;lt;/ref&amp;gt; Tactic blocks are run in the last round of pending work, after the rest of the surrounding term has been elaborated as far as it can be, so that the goal&#039;s type is as complete as possible.&amp;lt;ref name=&amp;quot;src-synth&amp;quot;&amp;gt;Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Lean/Elab/SyntheticMVars.lean&amp;lt;/code&amp;gt;: the function &amp;lt;code&amp;gt;synthesizeSyntheticMVars&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/Elab/SyntheticMVars.lean&amp;lt;/ref&amp;gt; The trace option &amp;lt;code&amp;gt;trace.Elab.step&amp;lt;/code&amp;gt; shows both moments. These lines are an excerpt from the trace of &amp;lt;code&amp;gt;example (p : Prop) (hp : p) : p ∧ p := by exact ⟨hp, hp⟩&amp;lt;/code&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;
[Elab.step] ✅️ expected type: p ∧ p, term&lt;br /&gt;
    by exact ⟨hp, hp⟩&lt;br /&gt;
  [Elab.step.result] ?m.1&lt;br /&gt;
[Elab.step] ✅️ exact ⟨hp, hp⟩&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;by&amp;lt;/code&amp;gt; term elaborates to the metavariable &amp;lt;code&amp;gt;?m.1&amp;lt;/code&amp;gt;. Only afterwards does the tactic &amp;lt;code&amp;gt;exact&amp;lt;/code&amp;gt; run, and it is the tactic that assigns &amp;lt;code&amp;gt;?m.1&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Goals are metavariables ==&lt;br /&gt;
&lt;br /&gt;
The state of the tactic framework is a structure with one field, &amp;lt;code&amp;gt;goals : List MVarId&amp;lt;/code&amp;gt;.&amp;lt;ref name=&amp;quot;src-tactic&amp;quot;&amp;gt;Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Lean/Elab/Tactic/Basic.lean&amp;lt;/code&amp;gt;: the definitions &amp;lt;code&amp;gt;TacticM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Tactic&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;getGoals&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;tryCatchRestore&amp;lt;/code&amp;gt;, with the structure &amp;lt;code&amp;gt;Tactic.State&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;src/Lean/Elab/Term/TermElabM.lean&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/Elab/Tactic/Basic.lean&amp;lt;/ref&amp;gt; Each goal is a metavariable, with its own local context of hypotheses and its type, the statement still to be proved; the first is the &#039;&#039;&#039;main goal&#039;&#039;&#039;.&amp;lt;ref name=&amp;quot;manual-tactics&amp;quot; /&amp;gt; A tactic usually acts on the main goal: it assigns that metavariable a term, which may contain new metavariables, and puts the new metavariables in the goal&#039;s place. The goal of a &amp;lt;code&amp;gt;by&amp;lt;/code&amp;gt; block, and the goals made by tactics such as &amp;lt;code&amp;gt;intro&amp;lt;/code&amp;gt;, are synthetic opaque, the kind that unification never assigns, because a goal counts as solved exactly when its metavariable is assigned.&amp;lt;ref name=&amp;quot;src-mctx&amp;quot;&amp;gt;Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Lean/MetavarContext.lean&amp;lt;/code&amp;gt;: the design notes at the head of the file. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/MetavarContext.lean&amp;lt;/ref&amp;gt; [[Lean theorem prover/System/Metavariables and unification|Metavariables and unification]] treats these kinds.&lt;br /&gt;
&lt;br /&gt;
A short tactic that reads the list makes the point concrete:&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 Elab Tactic in&lt;br /&gt;
elab &amp;quot;show_goals&amp;quot; : tactic =&amp;gt; do&lt;br /&gt;
  let gs ← getGoals&lt;br /&gt;
  logInfo m!&amp;quot;goals: {gs.map Expr.mvar}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
example (p q : Prop) (hp : p) (hq : q) : p ∧ q := by&lt;br /&gt;
  constructor&lt;br /&gt;
  show_goals&lt;br /&gt;
  all_goals assumption&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It prints &amp;lt;code&amp;gt;goals: [?left, ?right]&amp;lt;/code&amp;gt;. The tactic &amp;lt;code&amp;gt;constructor&amp;lt;/code&amp;gt; assigned the original goal the term &amp;lt;code&amp;gt;And.intro ?left ?right&amp;lt;/code&amp;gt; and left the two new metavariables as goals, named after the arguments of &amp;lt;code&amp;gt;And.intro&amp;lt;/code&amp;gt;. The built-in &amp;lt;code&amp;gt;trace_state&amp;lt;/code&amp;gt; prints the same goals in the familiar form:&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;
theorem and_swap (p q : Prop) (h : p ∧ q) : q ∧ p := by&lt;br /&gt;
  constructor&lt;br /&gt;
  trace_state&lt;br /&gt;
  · exact h.2&lt;br /&gt;
  · exact h.1&lt;br /&gt;
&lt;br /&gt;
#print and_swap&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;
case left&lt;br /&gt;
p q : Prop&lt;br /&gt;
h : p ∧ q&lt;br /&gt;
⊢ q&lt;br /&gt;
&lt;br /&gt;
case right&lt;br /&gt;
p q : Prop&lt;br /&gt;
h : p ∧ q&lt;br /&gt;
⊢ p&lt;br /&gt;
theorem and_swap : ∀ (p q : Prop), p ∧ q → q ∧ p :=&lt;br /&gt;
fun p q h =&amp;gt; ⟨h.right, h.left⟩&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The last lines are the point of the whole framework. Once every goal is assigned, the &amp;lt;code&amp;gt;by&amp;lt;/code&amp;gt; block&#039;s metavariable stands for an ordinary term, and that term, not the script, is what the Lean kernel checks and what Lean&#039;s environment, its table of definitions and theorems, records. If a goal is left open, the block fails:&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;
example (p q : Prop) (hp : p) : p ∧ q := by&lt;br /&gt;
  constructor&lt;br /&gt;
  exact hp&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;
error: unsolved goals&lt;br /&gt;
case right&lt;br /&gt;
p q : Prop&lt;br /&gt;
hp : p&lt;br /&gt;
⊢ q&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The monad TacticM ==&lt;br /&gt;
&lt;br /&gt;
In Lean 4.34.1 the tactic monad is defined as&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;
abbrev TacticM := ReaderT Context $ StateRefT State TermElabM&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Its documentation describes it as the term elaboration monad &amp;lt;code&amp;gt;TermElabM&amp;lt;/code&amp;gt; extended with the current goals and some local information, and defines a tactic as a function from syntax to an action in &amp;lt;code&amp;gt;TacticM&amp;lt;/code&amp;gt;. Several tactics may be attached to one kind of syntax; they are attempted until one succeeds.&amp;lt;ref name=&amp;quot;src-tactic&amp;quot; /&amp;gt; Because &amp;lt;code&amp;gt;TacticM&amp;lt;/code&amp;gt; sits on top of the elaborator, a tactic can do anything the elaborator does: elaborate a term against a goal, call the unifier, search for instances, inspect and extend Lean&#039;s environment. [[Lean theorem prover/System/Monads and do-notation|Monads and do-notation]] explains the monad stack, and [[Lean theorem prover/System/Metaprogramming in Lean|metaprogramming in Lean]] shows how to write tactics against it. The paper that introduced Lean 4 stresses that tactics are implemented in Lean itself and can be added by users.&amp;lt;ref name=&amp;quot;lean4-paper&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 &#039;&#039;Automated Deduction – CADE 28&#039;&#039;, Lecture Notes in Computer Science 12699, Springer, 2021, pp. 625–635. doi:10.1007/978-3-030-79876-5_37&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
None of this is trusted. A tactic may be wrong in any way: it may assign a goal an ill-typed term, or a term of the wrong type. The error surfaces when the term is checked, at the latest by the Lean kernel ([[Lean theorem prover/System/The Lean kernel|the Lean kernel]]).&lt;br /&gt;
&lt;br /&gt;
== Combinators ==&lt;br /&gt;
&lt;br /&gt;
Tactics are joined by combinators, themselves tactics. Their documentation strings in Lean&#039;s source give their meaning:&amp;lt;ref name=&amp;quot;src-tactics&amp;quot;&amp;gt;Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Init/Tactics.lean&amp;lt;/code&amp;gt;: the documentation strings and definitions of &amp;lt;code&amp;gt;all_goals&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;focus&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;first&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;try&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;lt;;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;repeat&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;exact?&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;apply?&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Init/Tactics.lean&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;t₁ &amp;amp;lt;;&amp;amp;gt; t₂&amp;lt;/code&amp;gt; runs &amp;lt;code&amp;gt;t₁&amp;lt;/code&amp;gt; on the main goal and &amp;lt;code&amp;gt;t₂&amp;lt;/code&amp;gt; on each goal it produces, collecting all the goals that result.&lt;br /&gt;
* &amp;lt;code&amp;gt;all_goals t&amp;lt;/code&amp;gt; runs &amp;lt;code&amp;gt;t&amp;lt;/code&amp;gt; on every goal and fails if it fails on any. &amp;lt;code&amp;gt;focus t&amp;lt;/code&amp;gt; runs &amp;lt;code&amp;gt;t&amp;lt;/code&amp;gt; on the main goal with the other goals hidden; the bullet &amp;lt;code&amp;gt;· t&amp;lt;/code&amp;gt;, used in &amp;lt;code&amp;gt;and_swap&amp;lt;/code&amp;gt; above and preferred by the documentation, also requires that &amp;lt;code&amp;gt;t&amp;lt;/code&amp;gt; close the goal. In 4.34.1 &amp;lt;code&amp;gt;t₁ &amp;amp;lt;;&amp;amp;gt; t₂&amp;lt;/code&amp;gt; is itself a macro built from &amp;lt;code&amp;gt;focus&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;all_goals&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;first | t₁ | t₂ | …&amp;lt;/code&amp;gt; runs each alternative until one succeeds, and fails if none does.&lt;br /&gt;
* &amp;lt;code&amp;gt;try t&amp;lt;/code&amp;gt; runs &amp;lt;code&amp;gt;t&amp;lt;/code&amp;gt; and succeeds even if &amp;lt;code&amp;gt;t&amp;lt;/code&amp;gt; fails. In 4.34.1 it is not a primitive but a macro: &amp;lt;code&amp;gt;first | t | skip&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;repeat t&amp;lt;/code&amp;gt; applies &amp;lt;code&amp;gt;t&amp;lt;/code&amp;gt; for as long as it succeeds, undoing any partial changes of the attempt that fails. If &amp;lt;code&amp;gt;t&amp;lt;/code&amp;gt; never fails, &amp;lt;code&amp;gt;repeat t&amp;lt;/code&amp;gt; does not stop. &amp;lt;code&amp;gt;repeat&#039; t&amp;lt;/code&amp;gt; applies &amp;lt;code&amp;gt;t&amp;lt;/code&amp;gt; recursively to every goal produced.&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;
example (p q r : Prop) (hp : p) (hq : q) (hr : r) : p ∧ q ∧ r := by&lt;br /&gt;
  constructor &amp;amp;lt;;&amp;amp;gt; (try constructor) &amp;amp;lt;;&amp;amp;gt; assumption&lt;br /&gt;
&lt;br /&gt;
example (n : Nat) : n = n ∨ n = 0 := by&lt;br /&gt;
  first&lt;br /&gt;
  | exact Or.inr rfl&lt;br /&gt;
  | exact Or.inl rfl&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the second example the first alternative fails, since &amp;lt;code&amp;gt;n = 0&amp;lt;/code&amp;gt; does not hold for every &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;first&amp;lt;/code&amp;gt; backtracks to the second. Before the second alternative runs, the state saved before the first is restored, metavariable assignments included: in &amp;lt;code&amp;gt;TacticM&amp;lt;/code&amp;gt; the standard way of catching a failure rolls the state back.&amp;lt;ref name=&amp;quot;src-tactic&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== A new tactic in three lines ==&lt;br /&gt;
&lt;br /&gt;
Since &amp;lt;code&amp;gt;try&amp;lt;/code&amp;gt; is a macro, so can a user&#039;s tactic be. A &#039;&#039;&#039;macro&#039;&#039;&#039; tactic rewrites its own syntax into existing tactics, and needs no access to &amp;lt;code&amp;gt;TacticM&amp;lt;/code&amp;gt; at all:&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;
macro &amp;quot;conj_close&amp;quot; : tactic =&amp;gt;&lt;br /&gt;
  `(tactic| (repeat&#039; constructor) &amp;amp;lt;;&amp;amp;gt; assumption)&lt;br /&gt;
&lt;br /&gt;
theorem three (p q r : Prop) (hp : p) (hq : q) (hr : r) : (p ∧ q) ∧ r := by&lt;br /&gt;
  conj_close&lt;br /&gt;
&lt;br /&gt;
#print three&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;
theorem three : ∀ (p q r : Prop), p → q → r → (p ∧ q) ∧ r :=&lt;br /&gt;
fun p q r hp hq hr =&amp;gt; ⟨⟨hp, hq⟩, hr⟩&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The new tactic &amp;lt;code&amp;gt;conj_close&amp;lt;/code&amp;gt; splits nested conjunctions as far as they go and closes every resulting goal with a hypothesis. The proof term shows nothing of it. [[Lean theorem prover/System/Syntax extension and hygienic macros|Syntax extension and hygienic macros]] covers the macro system, and [[Lean theorem prover/System/Metaprogramming in Lean|metaprogramming in Lean]] the tactics that need &amp;lt;code&amp;gt;elab&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;TacticM&amp;lt;/code&amp;gt;, as &amp;lt;code&amp;gt;show_goals&amp;lt;/code&amp;gt; above did.&lt;br /&gt;
&lt;br /&gt;
== Library search ==&lt;br /&gt;
&lt;br /&gt;
Lean 4.34.1 includes two search tactics in its core. &amp;lt;code&amp;gt;exact?&amp;lt;/code&amp;gt; searches Lean&#039;s environment for a definition or theorem that closes the goal with &amp;lt;code&amp;gt;exact&amp;lt;/code&amp;gt;, discharging side conditions with &amp;lt;code&amp;gt;solve_by_elim&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;apply?&amp;lt;/code&amp;gt; searches for one that refines the goal with &amp;lt;code&amp;gt;apply&amp;lt;/code&amp;gt;.&amp;lt;ref name=&amp;quot;src-tactics&amp;quot; /&amp;gt; Both report what they found as a suggestion to paste in place of the search:&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;
example (a b : Nat) : a + b = b + a := by&lt;br /&gt;
  exact?&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;
Try this:&lt;br /&gt;
  [apply] exact Nat.add_comm a b&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The suggestion is meant to replace the call. A proof that keeps &amp;lt;code&amp;gt;exact?&amp;lt;/code&amp;gt; repeats the search every time the file is checked, and may find a different lemma once the library changes.&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/System/Decision procedures|Decision procedures]] describes the tactics that settle whole classes of goals: &amp;lt;code&amp;gt;decide&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;omega&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;simp&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;grind&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;bv_decide&amp;lt;/code&amp;gt;.&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>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/System/Type_classes_and_instance_resolution&amp;diff=6789</id>
		<title>Lean theorem prover/System/Type classes and instance resolution</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/System/Type_classes_and_instance_resolution&amp;diff=6789"/>
		<updated>2026-10-15T19:35:09Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Type classes and instance resolution}}&lt;br /&gt;
{{Plebeian|Lean theorem prover/Explainers/A library of mathematics}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;type class&#039;&#039;&#039; in Lean is a structure whose values Lean finds by itself. Writing &amp;lt;code&amp;gt;a + b&amp;lt;/code&amp;gt;, comparing two values, printing one, or treating a natural number as an integer all depend on such values, called &#039;&#039;&#039;instances&#039;&#039;&#039;, which the elaborator supplies by a search called &#039;&#039;&#039;instance resolution&#039;&#039;&#039; or instance synthesis. This page shows what a class is, how the search runs in Lean 4.34.1, why it is tabled, how its inputs and outputs are controlled, and how a large mathematical library is organised around it.&lt;br /&gt;
&lt;br /&gt;
== Classes are structures ==&lt;br /&gt;
&lt;br /&gt;
The command &amp;lt;code&amp;gt;class&amp;lt;/code&amp;gt; declares a structure and marks it for instance resolution:&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;
class Shape (α : Type) where&lt;br /&gt;
  area : α → Nat&lt;br /&gt;
&lt;br /&gt;
#check @Shape.area&lt;br /&gt;
#print Shape&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;
@Shape.area : {α : Type} → [self : Shape α] → α → Nat&lt;br /&gt;
class Shape (α : Type) : Type&lt;br /&gt;
number of parameters: 1&lt;br /&gt;
fields:&lt;br /&gt;
  Shape.area : α → Nat&lt;br /&gt;
constructor:&lt;br /&gt;
  Shape.mk {α : Type} (area : α → Nat) : Shape α&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The class has one field and one constructor, like any structure. The difference is in the type of the field&#039;s accessor. Its argument &amp;lt;code&amp;gt;[self : Shape α]&amp;lt;/code&amp;gt; is &#039;&#039;&#039;instance-implicit&#039;&#039;&#039;: the user does not write it, and the elaborator does not find it by unification, as it would an ordinary implicit argument, but by searching the declared instances.&amp;lt;ref name=&amp;quot;manual-tc&amp;quot;&amp;gt;Lean Developers, &#039;&#039;The Lean Language Reference&#039;&#039;, version 4.34.0, chapter &amp;quot;Type Classes&amp;quot;, and its section &amp;quot;Instance Synthesis&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/Type-Classes/&amp;lt;/ref&amp;gt; In the logic, nothing is new: an instance is an ordinary constant, and the term the search returns is an ordinary term that the Lean kernel checks like any other.&lt;br /&gt;
&lt;br /&gt;
== Instances and the search ==&lt;br /&gt;
&lt;br /&gt;
An instance supplies a value of the class, possibly depending on other instances:&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;
structure Square where&lt;br /&gt;
  side : Nat&lt;br /&gt;
&lt;br /&gt;
instance : Shape Square where&lt;br /&gt;
  area s := s.side * s.side&lt;br /&gt;
&lt;br /&gt;
instance [Shape α] [Shape β] : Shape (α × β) where&lt;br /&gt;
  area p := Shape.area p.1 + Shape.area p.2&lt;br /&gt;
&lt;br /&gt;
set_option pp.explicit true in&lt;br /&gt;
#synth Shape (Square × (Square × Square))&lt;br /&gt;
#eval Shape.area ((⟨3⟩, ⟨4⟩) : Square × Square)&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;
@instShapeProd Square (Prod Square Square) instShapeSquare&lt;br /&gt;
  (@instShapeProd Square Square instShapeSquare instShapeSquare)&lt;br /&gt;
25&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The command &amp;lt;code&amp;gt;#synth&amp;lt;/code&amp;gt; runs the search and prints its result: a term assembled from the two instances, nested to the shape of the type. An instance with instance arguments behaves like a rule of a logic program: to obtain &amp;lt;code&amp;gt;Shape (α × β)&amp;lt;/code&amp;gt;, obtain &amp;lt;code&amp;gt;Shape α&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Shape β&amp;lt;/code&amp;gt;. The paper that introduced Lean 4 describes resolution as a simple λ-Prolog interpreter whose Horn clauses are the declared instances, and states that Lean 4 indexes instances with discrimination trees.&amp;lt;ref name=&amp;quot;lean4-paper&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 &#039;&#039;Automated Deduction – CADE 28&#039;&#039;, Lecture Notes in Computer Science 12699, Springer, 2021, pp. 625–635. doi:10.1007/978-3-030-79876-5_37&amp;lt;/ref&amp;gt; The reference manual calls synthesis a recursive search procedure that either finds an instance or fails, and says that candidates are tried in order of priority, the more recent instance first among those of equal priority.&amp;lt;ref name=&amp;quot;manual-tc&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tabling ==&lt;br /&gt;
&lt;br /&gt;
Search of this kind has two known failures. In a hierarchy of mathematical structures there are often several paths from one class to another; such &#039;&#039;&#039;diamonds&#039;&#039;&#039;, stacked in towers, make naive depth-first search take time exponential in the height of the tower when a subquery fails. And useful instances can form &#039;&#039;&#039;cycles&#039;&#039;&#039;, such as coercions in both directions between two types, on which naive search may loop. Daniel Selsam, Sebastian Ullrich and Leonardo de Moura named these the diamond problem and the cycle problem, reported that increasingly sophisticated uses of type classes in Lean&#039;s mathematical library had turned them into practical obstacles, and proposed &#039;&#039;&#039;tabled typeclass resolution&#039;&#039;&#039; to solve both.&amp;lt;ref name=&amp;quot;selsam&amp;quot;&amp;gt;Daniel Selsam, Sebastian Ullrich and Leonardo de Moura, &amp;quot;Tabled Typeclass Resolution&amp;quot;, arXiv:2001.04301 [cs.PL], 2020. https://arxiv.org/abs/2001.04301&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Tabling, a technique taken from logic programming, keeps a table from each subgoal met so far to the solutions already found for it, and reuses those solutions instead of searching again. The procedure keeps one search tree per distinct subgoal. &#039;&#039;&#039;Generator nodes&#039;&#039;&#039;, the roots of the trees, try the instances for their subgoal one after another. &#039;&#039;&#039;Consumer nodes&#039;&#039;&#039; wait on a subgoal and are resumed whenever a new solution for it appears. The authors state that this removes the exponential blow-up from diamonds and guarantees termination under a bounded term-size assumption.&amp;lt;ref name=&amp;quot;selsam&amp;quot; /&amp;gt; In Lean 4.34.1 the table&#039;s keys are subgoals in which each assignable metavariable has been replaced by a normalised name, so that &amp;lt;code&amp;gt;f ?m ?m ?n&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;f _tc.0 _tc.0 _tc.1&amp;lt;/code&amp;gt;; the source notes that the lookup is structural, so a goal may be visited twice if two occurrences are equal only up to unfolding.&amp;lt;ref name=&amp;quot;src-synth&amp;quot;&amp;gt;Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Lean/Meta/SynthInstance.lean&amp;lt;/code&amp;gt;: the notes on tabled resolution and table keys, the function &amp;lt;code&amp;gt;generate&amp;lt;/code&amp;gt;, and the notes on &amp;lt;code&amp;gt;outParam&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/Meta/SynthInstance.lean&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A cycle shows the difference. Each of these instances needs the other:&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;
class R (α : Type) where&lt;br /&gt;
&lt;br /&gt;
instance [R Nat] : R Int := ⟨⟩&lt;br /&gt;
instance [R Int] : R Nat := ⟨⟩&lt;br /&gt;
&lt;br /&gt;
set_option trace.Meta.synthInstance true in&lt;br /&gt;
#synth R Nat&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;
error: failed to synthesize&lt;br /&gt;
  R Nat&lt;br /&gt;
[Meta.synthInstance] ❌️ R Nat&lt;br /&gt;
  [Meta.synthInstance] ✅️ new goal R Nat&lt;br /&gt;
    [Meta.synthInstance.instances] #[@instRNatOfInt]&lt;br /&gt;
  [Meta.synthInstance.apply] ✅️ apply @instRNatOfInt to R Nat&lt;br /&gt;
    [Meta.synthInstance.tryResolve] ✅️ R Nat ≟ R Nat&lt;br /&gt;
    [Meta.synthInstance] ✅️ new goal R Int&lt;br /&gt;
      [Meta.synthInstance.instances] #[@instRIntOfNat]&lt;br /&gt;
  [Meta.synthInstance.apply] ✅️ apply @instRIntOfNat to R Int&lt;br /&gt;
    [Meta.synthInstance.tryResolve] ✅️ R Int ≟ R Int&lt;br /&gt;
  [Meta.synthInstance] result &amp;amp;lt;not-available&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The error message is shortened here by one line of hint. When the search for &amp;lt;code&amp;gt;R Int&amp;lt;/code&amp;gt; asks again for &amp;lt;code&amp;gt;R Nat&amp;lt;/code&amp;gt;, that goal is already in the table, so no new goal is opened; the request waits for an answer, none ever arrives, and the search ends with a failure. A naive depth-first search would loop forever.&lt;br /&gt;
&lt;br /&gt;
== Inputs and outputs ==&lt;br /&gt;
&lt;br /&gt;
The reference manual states that a search is attempted only when all the input parameters of the class are known. A problem with unknown inputs is &#039;&#039;&#039;stuck&#039;&#039;&#039;; it may be retried when elaboration learns more, and otherwise it fails.&amp;lt;ref name=&amp;quot;manual-tc&amp;quot; /&amp;gt; A parameter marked &amp;lt;code&amp;gt;outParam&amp;lt;/code&amp;gt; is not an input. It is ignored when instances are matched, and the instance found determines it.&amp;lt;ref name=&amp;quot;manual-tc&amp;quot; /&amp;gt; In 4.34.1 the search replaces each output argument by a fresh metavariable before it starts and unifies the original afterwards.&amp;lt;ref name=&amp;quot;src-synth&amp;quot; /&amp;gt; The arithmetic classes use this: &amp;lt;code&amp;gt;#check @HAdd&amp;lt;/code&amp;gt; prints &amp;lt;code&amp;gt;HAdd : Type u_1 → Type u_2 → outParam (Type u_3) → Type (max (max u_1 u_2) u_3)&amp;lt;/code&amp;gt;, so the types of the two summands select the instance and the instance fixes the type of the sum.&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;
class Container (c : Type) (elem : outParam Type) where&lt;br /&gt;
  first? : c → Option elem&lt;br /&gt;
&lt;br /&gt;
instance : Container (List α) α := ⟨List.head?⟩&lt;br /&gt;
&lt;br /&gt;
#check fun (xs : List Nat) =&amp;gt; Container.first? xs&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This prints &amp;lt;code&amp;gt;fun xs =&amp;gt; Container.first? xs : List Nat → Option Nat&amp;lt;/code&amp;gt;: the element type was an output, read off the instance. Remove &amp;lt;code&amp;gt;outParam&amp;lt;/code&amp;gt; and the same use is stuck, because the second argument is now an input and nothing determines it:&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;
class Container&#039; (c : Type) (elem : Type) where&lt;br /&gt;
  first? : c → Option elem&lt;br /&gt;
&lt;br /&gt;
instance : Container&#039; (List α) α := ⟨List.head?⟩&lt;br /&gt;
&lt;br /&gt;
def firstOf (xs : List Nat) := Container&#039;.first? xs&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;
error: typeclass instance problem is stuck&lt;br /&gt;
  Container&#039; (List Nat) (?m.7 xs)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean&#039;s message continues with a note that the second argument contains metavariables and must be fully determined before resolution is tried. The manual also describes &amp;lt;code&amp;gt;semiOutParam&amp;lt;/code&amp;gt;, a parameter that is taken into account when instances are selected but that instances must fill in.&amp;lt;ref name=&amp;quot;manual-tc&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Default instances ==&lt;br /&gt;
&lt;br /&gt;
When a search would otherwise fail without having selected an instance, the &#039;&#039;&#039;default instances&#039;&#039;&#039; of the class are tried, by priority, the more recent first among equals.&amp;lt;ref name=&amp;quot;manual-tc&amp;quot; /&amp;gt; This is why &amp;lt;code&amp;gt;fun x =&amp;gt; x + 1&amp;lt;/code&amp;gt; elaborates to a function on &amp;lt;code&amp;gt;Nat&amp;lt;/code&amp;gt;, as [[Lean theorem prover/System/Elaboration|elaboration]] traces in detail: the prelude makes &amp;lt;code&amp;gt;instHAdd&amp;lt;/code&amp;gt; a default instance of &amp;lt;code&amp;gt;HAdd&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;instOfNatNat&amp;lt;/code&amp;gt; a default instance of &amp;lt;code&amp;gt;OfNat&amp;lt;/code&amp;gt; with low priority.&lt;br /&gt;
&lt;br /&gt;
== Coercions through classes ==&lt;br /&gt;
&lt;br /&gt;
Coercions are instances too. When a term of one type is used where another is expected, the elaborator searches for an instance of the coercion classes, of which &amp;lt;code&amp;gt;Coe&amp;lt;/code&amp;gt; is the main one, and inserts the function it finds.&amp;lt;ref name=&amp;quot;manual-coe&amp;quot;&amp;gt;Lean Developers, &#039;&#039;The Lean Language Reference&#039;&#039;, version 4.34.0, chapter &amp;quot;Coercions&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/Coercions/&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;
@[coe] def Square.toNat (s : Square) : Nat := s.side&lt;br /&gt;
instance : Coe Square Nat := ⟨Square.toNat⟩&lt;br /&gt;
&lt;br /&gt;
def twice (n : Nat) : Nat := 2 * n&lt;br /&gt;
&lt;br /&gt;
#check twice (⟨5⟩ : Square)&lt;br /&gt;
set_option pp.coercions false in&lt;br /&gt;
#check twice (⟨5⟩ : Square)&lt;br /&gt;
#eval twice (⟨5⟩ : Square)&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;
twice ↑{ side := 5 } : Nat&lt;br /&gt;
twice { side := OfNat.ofNat 5 }.toNat : Nat&lt;br /&gt;
10&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The attribute &amp;lt;code&amp;gt;@[coe]&amp;lt;/code&amp;gt; tells the printer to show the function as an arrow. With &amp;lt;code&amp;gt;pp.coercions&amp;lt;/code&amp;gt; off, the elaborated term shows what was really inserted: a call of &amp;lt;code&amp;gt;Square.toNat&amp;lt;/code&amp;gt;. The instance itself has been unfolded away, and the Lean kernel sees only the function application.&lt;br /&gt;
&lt;br /&gt;
== The mathematical library&#039;s hierarchy ==&lt;br /&gt;
&lt;br /&gt;
Lean&#039;s mathematical library, Mathlib, is organised around classes. A 2020 account of it, written for the Lean 3 version of the library, names, among the uses of type classes in Lean&#039;s core library: notation, such as the class behind &amp;lt;code&amp;gt;+&amp;lt;/code&amp;gt;; mathematical structures, such as a ring structure on a type; coercions; and decidability of propositions. It explains that the library&#039;s classes are mostly &#039;&#039;&#039;semi-bundled&#039;&#039;&#039;: the carrier type is a parameter of the class and the operations and axioms are fields. A type class problem should have essentially at most one solution and only parameters guide the search, so exposing the carrier lets the library register the canonical structure on a type. The same account calls the result a structure hierarchy rather than an algebraic one, because it extends far beyond groups and rings, and it records that diamonds are common in it.&amp;lt;ref name=&amp;quot;mathlib-paper&amp;quot;&amp;gt;The mathlib Community, &amp;quot;The Lean Mathematical Library&amp;quot;, in &#039;&#039;Proceedings of the 9th ACM SIGPLAN International Conference on Certified Programs and Proofs (CPP 2020)&#039;&#039;, ACM, 2020, pp. 367–381. doi:10.1145/3372885.3373824&amp;lt;/ref&amp;gt; A 2022 study of the same library counted over 600 classes and over 8,000 instances as of February 2022, and analysed the design patterns, and the problems, that instance parameters bring at that scale.&amp;lt;ref name=&amp;quot;baanen&amp;quot;&amp;gt;Anne Baanen, &amp;quot;Use and Abuse of Instance Parameters in the Lean Mathematical Library&amp;quot;, in &#039;&#039;13th International Conference on Interactive Theorem Proving (ITP 2022)&#039;&#039;, Leibniz International Proceedings in Informatics 237, Schloss Dagstuhl, 2022, pp. 4:1–4:20. doi:10.4230/LIPIcs.ITP.2022.4&amp;lt;/ref&amp;gt; Those are the conditions under which the diamond and cycle problems became urgent and tabled resolution was introduced.&amp;lt;ref name=&amp;quot;selsam&amp;quot; /&amp;gt; In Lean 4 the mechanism is the one shown on this page. &#039;&#039;Mathematics in Lean&#039;&#039; devotes a chapter to building such hierarchies from classes that extend one another, starting from the observation that a commutative ring is in particular an additive group.&amp;lt;ref name=&amp;quot;mil&amp;quot;&amp;gt;Jeremy Avigad and Patrick Massot, &#039;&#039;Mathematics in Lean&#039;&#039;, online book, chapter 8, &amp;quot;Hierarchies&amp;quot;. https://leanprover-community.github.io/mathematics_in_lean/C08_Hierarchies.html&amp;lt;/ref&amp;gt; This edition&#039;s code uses core Lean only, so the figures above are quoted from the cited papers, not measured here.&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/System/The tactic framework|The tactic framework]] turns from the search for instances to the search for proofs.&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>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/System/Metavariables_and_unification&amp;diff=6788</id>
		<title>Lean theorem prover/System/Metavariables and unification</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/System/Metavariables_and_unification&amp;diff=6788"/>
		<updated>2026-10-15T19:35:07Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Metavariables and unification}}&lt;br /&gt;
{{Plebeian|Lean theorem prover/Explainers/Holes and goals|Lean theorem prover/Explainers/When Lean says no}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;metavariable&#039;&#039;&#039; is a named hole in a term: a placeholder for a subterm not yet known. &#039;&#039;&#039;Unification&#039;&#039;&#039; is the search for values of metavariables that make two terms definitionally equal. Lean&#039;s elaborator, its tactic framework, its instance resolution and its simplifier all rest on these two things. This page describes them as Lean 4.34.1 implements them, explains why unification in Lean&#039;s type theory cannot be solved in general, and says what Lean does instead and what its failures mean.&lt;br /&gt;
&lt;br /&gt;
== Holes with contexts ==&lt;br /&gt;
&lt;br /&gt;
When the elaborator meets &amp;lt;code&amp;gt;id 5&amp;lt;/code&amp;gt;, it does not yet know the implicit type argument of &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt;. It creates a metavariable, written &amp;lt;code&amp;gt;?α&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;?m.7&amp;lt;/code&amp;gt; in Lean&#039;s output, applies &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt; to it, and continues; the numeral &amp;lt;code&amp;gt;5&amp;lt;/code&amp;gt; must have type &amp;lt;code&amp;gt;?α&amp;lt;/code&amp;gt;, and the instance problem it brings, &amp;lt;code&amp;gt;OfNat ?α 5&amp;lt;/code&amp;gt;, later fixes &amp;lt;code&amp;gt;?α := Nat&amp;lt;/code&amp;gt; through a default instance ([[Lean theorem prover/System/Elaboration|elaboration]]). A goal in a tactic proof is the same thing: an unassigned metavariable whose type is the proposition to prove.&amp;lt;ref name=&amp;quot;mpbook&amp;quot;&amp;gt;Arthur Paulino, Damiano Testa, Edward Ayers, Evgenia Karunus, Henrik Böving, Jannis Limperg, Siddhartha Gadgil and Siddharth Bhat, &#039;&#039;Metaprogramming in Lean 4&#039;&#039;, online book, chapter &amp;quot;MetaM&amp;quot;. https://leanprover-community.github.io/lean4-metaprogramming-book/main/04_metam.html&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each metavariable is declared in a &#039;&#039;&#039;local context&#039;&#039;&#039;, the list of variables and hypotheses in scope where the hole was made, and it may be assigned only a term whose free variables come from that context. Lean&#039;s source writes this &amp;lt;code&amp;gt;C |- ?m : t&amp;lt;/code&amp;gt;.&amp;lt;ref name=&amp;quot;src-defeq&amp;quot;&amp;gt;Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Lean/Meta/ExprDefEq.lean&amp;lt;/code&amp;gt;: the notes on pattern unification and its approximations A1 to A7. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/Meta/ExprDefEq.lean&amp;lt;/ref&amp;gt; The restriction is what keeps a solution from capturing a variable that did not exist where the hole was made.&lt;br /&gt;
&lt;br /&gt;
The assignments live in a &#039;&#039;&#039;metavariable context&#039;&#039;&#039;, separate from the terms. Assigning &amp;lt;code&amp;gt;?m&amp;lt;/code&amp;gt; does not rewrite the terms that mention it; a later call to &amp;lt;code&amp;gt;instantiateMVars&amp;lt;/code&amp;gt; substitutes the current assignments.&amp;lt;ref name=&amp;quot;mpbook&amp;quot; /&amp;gt; A term handed to the Lean kernel must contain no metavariables at all ([[Lean theorem prover/System/The Lean kernel|the Lean kernel]]).&lt;br /&gt;
&lt;br /&gt;
== Three kinds ==&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;
#print Lean.MetavarKind&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;
inductive Lean.MetavarKind : Type&lt;br /&gt;
number of parameters: 0&lt;br /&gt;
constructors:&lt;br /&gt;
Lean.MetavarKind.natural : Lean.MetavarKind&lt;br /&gt;
Lean.MetavarKind.synthetic : Lean.MetavarKind&lt;br /&gt;
Lean.MetavarKind.syntheticOpaque : Lean.MetavarKind&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The design notes in Lean&#039;s source give the rules. A &#039;&#039;&#039;natural&#039;&#039;&#039; metavariable may be assigned freely by unification; implicit arguments are of this kind. A &#039;&#039;&#039;synthetic&#039;&#039;&#039; one may be assigned by unification, but unification avoids doing so when it has a choice, because another procedure, usually instance resolution, is responsible for it and must check any value unification chose. A &#039;&#039;&#039;synthetic opaque&#039;&#039;&#039; one is never assigned by unification. Tactics such as &amp;lt;code&amp;gt;intro&amp;lt;/code&amp;gt; make their new goals of this kind: a goal counts as solved when its metavariable is assigned, so unification must not close it behind the user&#039;s back.&amp;lt;ref name=&amp;quot;src-mctx&amp;quot;&amp;gt;Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Lean/MetavarContext.lean&amp;lt;/code&amp;gt;: the design notes at the head of the file. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/MetavarContext.lean&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Metavariables also carry a &#039;&#039;&#039;depth&#039;&#039;&#039;. A nested procedure, such as instance resolution called from inside unification, raises the depth of the metavariable context, and while it runs, unification does not assign metavariables of lower depth. This lets a subsidiary search create and solve its own holes without committing its caller to anything.&amp;lt;ref name=&amp;quot;src-mctx&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Delayed assignment ==&lt;br /&gt;
&lt;br /&gt;
A difficulty arises when a term containing a hole is put under a binder. Suppose &amp;lt;code&amp;gt;?m&amp;lt;/code&amp;gt; may mention &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt;, and the elaborator forms &amp;lt;code&amp;gt;fun x =&amp;gt; t[?m]&amp;lt;/code&amp;gt;. If &amp;lt;code&amp;gt;?m&amp;lt;/code&amp;gt; is later assigned a term containing &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt;, that occurrence must refer to the new bound variable. Lean handles this by creating a fresh metavariable &amp;lt;code&amp;gt;?n&amp;lt;/code&amp;gt; of function type, with &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt; removed from its context, and producing &amp;lt;code&amp;gt;fun x =&amp;gt; t[?n x]&amp;lt;/code&amp;gt;. For a natural or synthetic &amp;lt;code&amp;gt;?m&amp;lt;/code&amp;gt; it simply assigns &amp;lt;code&amp;gt;?m := ?n x&amp;lt;/code&amp;gt;. For a synthetic opaque &amp;lt;code&amp;gt;?m&amp;lt;/code&amp;gt;, which may not be assigned that way, it records a &#039;&#039;&#039;delayed assignment&#039;&#039;&#039; &amp;lt;code&amp;gt;?n #[x] := ?m&amp;lt;/code&amp;gt;: once &amp;lt;code&amp;gt;?m&amp;lt;/code&amp;gt; receives a value with no metavariables left in it, each &amp;lt;code&amp;gt;?n r&amp;lt;/code&amp;gt; is replaced by that value with &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt; for &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt;.&amp;lt;ref name=&amp;quot;src-mctx&amp;quot; /&amp;gt; This is how a tactic block inside a &amp;lt;code&amp;gt;fun&amp;lt;/code&amp;gt; can be run after the surrounding term has been closed over its variables.&lt;br /&gt;
&lt;br /&gt;
== Unification ==&lt;br /&gt;
&lt;br /&gt;
The unifier is Lean&#039;s definitional equality test with metavariables allowed. In the traces below it is written &amp;lt;code&amp;gt;s =?= t&amp;lt;/code&amp;gt;, and it runs in the monad &amp;lt;code&amp;gt;MetaM&amp;lt;/code&amp;gt; under a &#039;&#039;&#039;transparency&#039;&#039;&#039; setting that limits which definitions it may unfold, from &amp;lt;code&amp;gt;reducible&amp;lt;/code&amp;gt; through &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;all&amp;lt;/code&amp;gt;.&amp;lt;ref name=&amp;quot;mpbook&amp;quot; /&amp;gt; First-order cases are easy. To make &amp;lt;code&amp;gt;?n + 2&amp;lt;/code&amp;gt; equal to &amp;lt;code&amp;gt;5&amp;lt;/code&amp;gt;, Lean solves &amp;lt;code&amp;gt;?n := 3&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;
theorem w : ∃ n : Nat, n + 2 = 5 := ⟨_, rfl⟩&lt;br /&gt;
#print w&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This prints &amp;lt;code&amp;gt;Exists.intro 3 rfl&amp;lt;/code&amp;gt; as the proof. The hard cases have a metavariable applied to arguments, &amp;lt;code&amp;gt;?f a =?= t&amp;lt;/code&amp;gt;: then &amp;lt;code&amp;gt;?f&amp;lt;/code&amp;gt; stands for a function, and the problem is &#039;&#039;&#039;higher-order unification&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Why it cannot be solved in general ==&lt;br /&gt;
&lt;br /&gt;
Higher-order unification is undecidable. Gérard Huet&#039;s 1975 procedure for the typed λ-calculus is a semi-decision algorithm: it finds a unifier when one exists, but on problems with no unifier it may never stop, and Huet cites the undecidability of the problem as the reason.&amp;lt;ref name=&amp;quot;huet&amp;quot;&amp;gt;Gérard P. Huet, &amp;quot;A unification algorithm for typed λ-calculus&amp;quot;, &#039;&#039;Theoretical Computer Science&#039;&#039; 1(1), 1975, pp. 27–57. doi:10.1016/0304-3975(75)90011-0&amp;lt;/ref&amp;gt; For simply typed λ-terms it is undecidable already from order 2 upwards, a result due to Warren Goldfarb in 1981.&amp;lt;ref name=&amp;quot;goldfarb&amp;quot;&amp;gt;Warren D. Goldfarb, &amp;quot;The undecidability of the second-order unification problem&amp;quot;, &#039;&#039;Theoretical Computer Science&#039;&#039; 13(2), 1981, pp. 225–230. doi:10.1016/0304-3975(81)90040-2. Not consulted directly; the result is stated, with this citation, in the introduction of Miller 1991.&amp;lt;/ref&amp;gt; Unifiers are also not unique: &amp;lt;code&amp;gt;?f 3 =?= 3 + 3&amp;lt;/code&amp;gt; is solved by &amp;lt;code&amp;gt;fun x =&amp;gt; x + x&amp;lt;/code&amp;gt;, by &amp;lt;code&amp;gt;fun x =&amp;gt; 3 + x&amp;lt;/code&amp;gt;, by &amp;lt;code&amp;gt;fun x =&amp;gt; x + 3&amp;lt;/code&amp;gt; and by the constant function returning &amp;lt;code&amp;gt;3 + 3&amp;lt;/code&amp;gt;, and none is more general than the others.&lt;br /&gt;
&lt;br /&gt;
Dale Miller isolated a fragment that behaves well. In a &#039;&#039;&#039;pattern&#039;&#039;&#039;, a metavariable is applied only to distinct bound variables. Unification restricted to patterns is decidable and has most general unifiers whenever it has unifiers at all.&amp;lt;ref name=&amp;quot;miller&amp;quot;&amp;gt;Dale Miller, &amp;quot;A logic programming language with lambda-abstraction, function variables, and simple unification&amp;quot;, &#039;&#039;Journal of Logic and Computation&#039;&#039; 1(4), 1991, pp. 497–536. doi:10.1093/logcom/1.4.497&amp;lt;/ref&amp;gt; The solution is read off directly:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;?m\ a_1 \ldots a_n =^{?} t \quad\Longrightarrow\quad ?m := \lambda a_1 \ldots a_n.\ t&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== What Lean does ==&lt;br /&gt;
&lt;br /&gt;
Lean&#039;s unifier, in &amp;lt;code&amp;gt;ExprDefEq.lean&amp;lt;/code&amp;gt;, states its own version of Miller&#039;s condition. The constraint &amp;lt;code&amp;gt;?m@C a₁ … aₙ =?= t&amp;lt;/code&amp;gt; is a pattern when the &amp;lt;code&amp;gt;aᵢ&amp;lt;/code&amp;gt; are pairwise distinct free variables that are not local definitions and are not in &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt;, when &amp;lt;code&amp;gt;t&amp;lt;/code&amp;gt; uses only variables from &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt; and the &amp;lt;code&amp;gt;aᵢ&amp;lt;/code&amp;gt;, when every metavariable in &amp;lt;code&amp;gt;t&amp;lt;/code&amp;gt; has a context that is a prefix of &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt;, and when &amp;lt;code&amp;gt;?m&amp;lt;/code&amp;gt; does not occur in &amp;lt;code&amp;gt;t&amp;lt;/code&amp;gt;. Then &amp;lt;code&amp;gt;?m := fun a₁ … aₙ =&amp;gt; t&amp;lt;/code&amp;gt;.&amp;lt;ref name=&amp;quot;src-defeq&amp;quot; /&amp;gt; The following problem is a pattern, because &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt; is bound after the hole for &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; was made:&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;
theorem dbl : ∃ f : Nat → Nat, ∀ x, f x = x * 2 := ⟨_, fun _ =&amp;gt; rfl⟩&lt;br /&gt;
#print dbl&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The proof printed is &amp;lt;code&amp;gt;Exists.intro (fun x =&amp;gt; x * 2) fun x =&amp;gt; rfl&amp;lt;/code&amp;gt;. With &amp;lt;code&amp;gt;set_option trace.Meta.isDefEq.assign true&amp;lt;/code&amp;gt; the unifier reports the step, among 67 lines of trace:&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;
[Meta.isDefEq.assign] ✅️ ?m.12 x✝ := x✝ * 2&lt;br /&gt;
  [Meta.isDefEq.assign.beforeMkLambda] ?m.12 [x✝] := x✝ * 2&lt;br /&gt;
  [Meta.isDefEq.assign.checkTypes] ✅️ (?m.12 : Nat → Nat) := (fun x =&amp;gt; x * 2 : Nat → Nat)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Outside the pattern fragment Lean does not search, as Huet&#039;s procedure would. It applies workarounds and approximations, listed in the source as A1 to A7. Among them: &#039;&#039;&#039;first-order approximation&#039;&#039;&#039;, which solves &amp;lt;code&amp;gt;?m a₁ … aₙ =?= f b₁ … bₖ&amp;lt;/code&amp;gt; by matching the last arguments pairwise and unifying &amp;lt;code&amp;gt;?m&amp;lt;/code&amp;gt; applied to the rest with &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; applied to the rest; and &#039;&#039;&#039;constant approximation&#039;&#039;&#039;, which assigns &amp;lt;code&amp;gt;?m&amp;lt;/code&amp;gt; a function ignoring its arguments. The notes say plainly that constant approximation may produce bad solutions, and give an example on which another of the approximations fails.&amp;lt;ref name=&amp;quot;src-defeq&amp;quot; /&amp;gt; Each picks one unifier and commits to 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;
theorem d (h : (3 : Nat) = 3) : 3 + 3 = 3 + 3 := congrArg _ h&lt;br /&gt;
#print d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The conclusion of &amp;lt;code&amp;gt;congrArg&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;?f ?x = ?f ?y&amp;lt;/code&amp;gt;, and the elaborator unifies it with the expected type before it looks at &amp;lt;code&amp;gt;h&amp;lt;/code&amp;gt;. So the first constraint is &amp;lt;code&amp;gt;?f ?x =?= 3 + 3&amp;lt;/code&amp;gt;, whose argument is itself unknown: not a pattern. The trace shows first-order approximation at work. It reads &amp;lt;code&amp;gt;3 + 3&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;HAdd.hAdd 3 3&amp;lt;/code&amp;gt;, matches the last argument, &amp;lt;code&amp;gt;?x := 3&amp;lt;/code&amp;gt;, and the rest, &amp;lt;code&amp;gt;?f := HAdd.hAdd 3&amp;lt;/code&amp;gt;. The proof printed is &amp;lt;code&amp;gt;fun h =&amp;gt; congrArg (HAdd.hAdd 3) h&amp;lt;/code&amp;gt;: of the four solutions above, the one that reads &amp;lt;code&amp;gt;3 + x&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== When it fails ==&lt;br /&gt;
&lt;br /&gt;
The same approximation can choose wrongly. Here &amp;lt;code&amp;gt;?f a =?= a * 2&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;?f b =?= b * 2&amp;lt;/code&amp;gt; must both hold, and &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt; belongs to the context in which &amp;lt;code&amp;gt;?f&amp;lt;/code&amp;gt; was made, so the first constraint is not a pattern:&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;
example (a b : Nat) (h : a = b) : a * 2 = b * 2 := congrArg _ h&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;
error: Type mismatch&lt;br /&gt;
  congrArg ?m.19 h&lt;br /&gt;
has type&lt;br /&gt;
  ?m.19 a = ?m.19 b&lt;br /&gt;
but is expected to have type&lt;br /&gt;
  a * 2 = b * 2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The trace option &amp;lt;code&amp;gt;trace.Meta.isDefEq&amp;lt;/code&amp;gt; shows why. In this excerpt, lines marked … are omitted:&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;
[Meta.isDefEq] ❌️ a * 2 = b * 2 =?= ?m.19 a = ?m.19 b&lt;br /&gt;
  …&lt;br /&gt;
  [Meta.isDefEq] ✅️ a * 2 =?= ?m.19 a&lt;br /&gt;
    [Meta.isDefEq] a * 2 [nonassignable] =?= ?m.19 a [assignable]&lt;br /&gt;
    [Meta.isDefEq.foApprox] ?m.19 [a] := a * 2&lt;br /&gt;
    [Meta.isDefEq] ❌️ a =?= 2&lt;br /&gt;
    …&lt;br /&gt;
    [Meta.isDefEq.foApprox] ?m.19 [a] := (a.mul 1).add a&lt;br /&gt;
    [Meta.isDefEq] ✅️ a =?= a&lt;br /&gt;
    [Meta.isDefEq] ✅️ ?m.19 =?= (a.mul 1).add&lt;br /&gt;
  …&lt;br /&gt;
  [Meta.isDefEq] ❌️ b * 2 =?= (a.mul 1).add b&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
First-order approximation first tries to match &amp;lt;code&amp;gt;a * 2&amp;lt;/code&amp;gt; against &amp;lt;code&amp;gt;?m.19 a&amp;lt;/code&amp;gt; and fails on &amp;lt;code&amp;gt;a =?= 2&amp;lt;/code&amp;gt;. After unfolding multiplication it succeeds, with &amp;lt;code&amp;gt;?m.19 := (a.mul 1).add&amp;lt;/code&amp;gt;, a function that satisfies the first constraint and not the second. Writing the function explicitly, &amp;lt;code&amp;gt;congrArg (· * 2) h&amp;lt;/code&amp;gt;, removes the higher-order problem and the proof is accepted.&lt;br /&gt;
&lt;br /&gt;
A message such as &amp;lt;code&amp;gt;Type mismatch&amp;lt;/code&amp;gt;, or from a tactic &amp;lt;code&amp;gt;could not unify&amp;lt;/code&amp;gt;, therefore reports that the unifier returned false. That has three possible causes. The terms may differ under every assignment. The unifier may have committed to a wrong approximation, as above, or met a problem outside what it attempts. Or the transparency setting may have forbidden an unfolding that would have shown the terms equal. Only the first is a fact about the mathematics. The cure for the other two is to supply the missing information: an explicit argument, a type ascription, or a lemma that rewrites one side into the shape of the other.&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/System/Type classes and instance resolution|Type classes and instance resolution]] describes the search that fills synthetic metavariables, and [[Lean theorem prover/System/The tactic framework|the tactic framework]] the one that fills goals.&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>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/System/The_Lean_kernel&amp;diff=6787</id>
		<title>Lean theorem prover/System/The Lean kernel</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/System/The_Lean_kernel&amp;diff=6787"/>
		<updated>2026-10-15T19:35:06Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:The Lean kernel}}&lt;br /&gt;
{{Plebeian|Lean theorem prover/Explainers/The small trusted core|Lean theorem prover/Explainers/What a proof assistant does}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Lean kernel&#039;&#039;&#039; is the type checker that decides whether a definition, theorem, axiom or inductive type may enter Lean&#039;s environment, its table of definitions and theorems. Everything else in Lean, from the parser to the most elaborate tactic, produces candidates; the Lean kernel accepts or refuses them. This page describes what it checks, what it never sees, how it is written, and where its trust ends, for Lean 4.34.1.&lt;br /&gt;
&lt;br /&gt;
== What reaches it ==&lt;br /&gt;
&lt;br /&gt;
The Lean kernel receives fully explicit terms of one data type, &amp;lt;code&amp;gt;Expr&amp;lt;/code&amp;gt;. With &amp;lt;code&amp;gt;import Lean&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;#print Lean.Expr&amp;lt;/code&amp;gt; lists its twelve constructors:&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;
#print Lean.Expr&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;
inductive Lean.Expr : Type&lt;br /&gt;
number of parameters: 0&lt;br /&gt;
constructors:&lt;br /&gt;
Lean.Expr.bvar : Nat → Lean.Expr&lt;br /&gt;
Lean.Expr.fvar : Lean.FVarId → Lean.Expr&lt;br /&gt;
Lean.Expr.mvar : Lean.MVarId → Lean.Expr&lt;br /&gt;
Lean.Expr.sort : Lean.Level → Lean.Expr&lt;br /&gt;
Lean.Expr.const : Lean.Name → List Lean.Level → Lean.Expr&lt;br /&gt;
Lean.Expr.app : Lean.Expr → Lean.Expr → Lean.Expr&lt;br /&gt;
Lean.Expr.lam : Lean.Name → Lean.Expr → Lean.Expr → Lean.BinderInfo → Lean.Expr&lt;br /&gt;
Lean.Expr.forallE : Lean.Name → Lean.Expr → Lean.Expr → Lean.BinderInfo → Lean.Expr&lt;br /&gt;
Lean.Expr.letE : Lean.Name → Lean.Expr → Lean.Expr → Lean.Expr → Bool → Lean.Expr&lt;br /&gt;
Lean.Expr.lit : Lean.Literal → Lean.Expr&lt;br /&gt;
Lean.Expr.mdata : Lean.MData → Lean.Expr → Lean.Expr&lt;br /&gt;
Lean.Expr.proj : Lean.Name → Nat → Lean.Expr → Lean.Expr&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These are bound variables, free variables, metavariables, sorts, constants with universe levels, applications, functions, dependent function types, local definitions, numeric and string literals, annotations, and structure projections. The type theory they encode is described in [[Lean theorem prover/Foundations/Terms, types and judgments|terms, types and judgments]]. A term handed to the Lean kernel for addition may contain neither metavariables nor free variables: the elaborator must have solved every hole and closed every term.&amp;lt;ref name=&amp;quot;src-env-cpp&amp;quot;&amp;gt;Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/kernel/environment.cpp&amp;lt;/code&amp;gt;: the functions &amp;lt;code&amp;gt;add_axiom&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;add_definition&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;add_theorem&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;add_opaque&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;add_mutual&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;check_constant_val&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/kernel/environment.cpp&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The requests themselves form a second data type, &amp;lt;code&amp;gt;Lean.Declaration&amp;lt;/code&amp;gt;, with seven constructors: an axiom, a definition, a theorem, an opaque constant, a block of mutually recursive definitions, the quotient primitives, and a block of inductive types. What the table stores, &amp;lt;code&amp;gt;Lean.ConstantInfo&amp;lt;/code&amp;gt;, has eight: the same kinds, minus the mutual block, plus the constructors and recursors that the Lean kernel itself generates for each inductive type. Both are printed by &amp;lt;code&amp;gt;#print&amp;lt;/code&amp;gt; in the same way as &amp;lt;code&amp;gt;Expr&amp;lt;/code&amp;gt; above.&lt;br /&gt;
&lt;br /&gt;
== What it checks ==&lt;br /&gt;
&lt;br /&gt;
For every constant, whatever its kind, the Lean kernel checks that the name is not already taken, that no universe parameter is listed twice, that the stated type contains no metavariables or free variables, and that the type is itself well typed with a sort as its type.&amp;lt;ref name=&amp;quot;src-env-cpp&amp;quot; /&amp;gt; Then it checks by kind.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;An axiom&#039;&#039;&#039; is accepted once its type passes. Nothing else is checked, which is why axioms are listed by &amp;lt;code&amp;gt;#print axioms&amp;lt;/code&amp;gt; and why the edition treats them on their own page, [[Lean theorem prover/Foundations/The three axioms|the three axioms]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A definition, a theorem or an opaque constant&#039;&#039;&#039; has a value. The Lean kernel infers the value&#039;s type and asks whether it is definitionally equal to the stated type. For a theorem it also checks that the stated type is a proposition.&amp;lt;ref name=&amp;quot;src-env-cpp&amp;quot; /&amp;gt; In the notation of the foundations pages, a definition &amp;lt;math&amp;gt;c : T := v&amp;lt;/math&amp;gt; is accepted when&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\vdash T : \mathrm{Sort}\ u \qquad \vdash v : T&#039; \qquad T&#039; \equiv T}{c : T := v\ \ \mathrm{accepted}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where &amp;lt;math&amp;gt;\equiv&amp;lt;/math&amp;gt; is definitional equality, the subject of [[Lean theorem prover/Foundations/Definitional equality|definitional equality]]. Much of the Lean kernel&#039;s work is in that last premise. Its implementation in 4.34.1 tries, in order: quick structural checks; full evaluation when the second term is the Boolean &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; and the first has no free variables, a path its source comment ties to the &amp;lt;code&amp;gt;decide&amp;lt;/code&amp;gt; tactic; reduction to weak head normal form; proof irrelevance; lazy unfolding of definitions, the side with the greater definitional height first; then comparison of arguments, eta for functions, eta for structures, string literals and unit-like types.&amp;lt;ref name=&amp;quot;src-tc&amp;quot;&amp;gt;Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/kernel/type_checker.cpp&amp;lt;/code&amp;gt;: the functions &amp;lt;code&amp;gt;is_def_eq_core&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;lazy_delta_reduction_step&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;reduce_nat&amp;lt;/code&amp;gt;; with the function &amp;lt;code&amp;gt;compare&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;src/kernel/declaration.cpp&amp;lt;/code&amp;gt;, which orders unfolding by definitional height. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/kernel/type_checker.cpp&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A block of mutually recursive definitions is accepted only when it is marked &amp;lt;code&amp;gt;partial&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;unsafe&amp;lt;/code&amp;gt;.&amp;lt;ref name=&amp;quot;src-env-cpp&amp;quot; /&amp;gt; Ordinary recursive functions reach the Lean kernel already compiled into recursors, as [[Lean theorem prover/Foundations/Structural and well-founded recursion|structural and well-founded recursion]] explains, so the Lean kernel has no termination checker to trust.&amp;lt;ref name=&amp;quot;manual-elab&amp;quot;&amp;gt;Lean Developers, &#039;&#039;The Lean Language Reference&#039;&#039;, version 4.34.0, chapter &amp;quot;Elaboration and Compilation&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/Elaboration-and-Compilation/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;An inductive type&#039;&#039;&#039; is checked hardest, because its constructors and its recursor become axiom-like rules. For each constructor the Lean kernel checks that its type is well typed, that its parameters match the type&#039;s parameters, that each field lives in a universe no larger than the type&#039;s own (unless the type is a proposition), that the type being defined occurs only strictly positively, and that the constructor returns the type being defined. It then generates the recursor and its computation rules.&amp;lt;ref name=&amp;quot;src-ind&amp;quot;&amp;gt;Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/kernel/inductive.cpp&amp;lt;/code&amp;gt;: the functions &amp;lt;code&amp;gt;check_constructors&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;check_positivity&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/kernel/inductive.cpp&amp;lt;/ref&amp;gt; [[Lean theorem prover/Foundations/Inductive types and recursors|Inductive types and recursors]] gives the rules; here is the positivity check refusing a type that would make the logic inconsistent:&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;
inductive Bad where&lt;br /&gt;
  | mk : (Bad → Nat) → Bad&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;
error: (kernel) arg #1 of &#039;Bad.mk&#039; has a non positive occurrence of the datatypes being declared&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The prefix &amp;lt;code&amp;gt;(kernel)&amp;lt;/code&amp;gt; marks a message that comes from the Lean kernel and not from the elaborator.&amp;lt;ref name=&amp;quot;src-message&amp;quot;&amp;gt;Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Lean/Message.lean&amp;lt;/code&amp;gt;: the messages for &amp;lt;code&amp;gt;Kernel.Exception&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/Message.lean&amp;lt;/ref&amp;gt; Some checks are made twice. A constructor field in too large a universe, such as &amp;lt;code&amp;gt;mk : Type → Big&amp;lt;/code&amp;gt; for &amp;lt;code&amp;gt;Big : Type&amp;lt;/code&amp;gt;, is caught first by the elaborator, which gives a fuller message; the Lean kernel would refuse it too.&amp;lt;ref name=&amp;quot;src-ind&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== What it does not see ==&lt;br /&gt;
&lt;br /&gt;
The Lean kernel sees no syntax, no notation, no macro, no tactic, no instance search and no coercion. It performs no unification and no termination checking.&amp;lt;ref name=&amp;quot;manual-elab&amp;quot; /&amp;gt; A proof written with fifty tactic steps and the same proof written as a term reach it as the same kind of object, an &amp;lt;code&amp;gt;Expr&amp;lt;/code&amp;gt;, and it cannot tell how either was found. This is the point of the design: the elaborator ([[Lean theorem prover/System/Elaboration|elaboration]]) and the tactic framework may be as clever, as large and as buggy as they like, because what they produce is checked again.&lt;br /&gt;
&lt;br /&gt;
The arrangement can be tested by going around the elaborator. The following metaprogram hands the Lean kernel a theorem whose stated type is &amp;lt;code&amp;gt;False&amp;lt;/code&amp;gt; and whose proof is &amp;lt;code&amp;gt;True.intro&amp;lt;/code&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;
import Lean&lt;br /&gt;
open Lean Elab Command&lt;br /&gt;
&lt;br /&gt;
#eval show CommandElabM Unit from do&lt;br /&gt;
  let decl := Declaration.thmDecl {&lt;br /&gt;
    name := `bogus, levelParams := [], type := mkConst ``False,&lt;br /&gt;
    value := mkConst ``True.intro }&lt;br /&gt;
  liftCoreM (addDecl decl)&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;
error: (kernel) declaration type mismatch, &#039;bogus&#039; has type&lt;br /&gt;
  True&lt;br /&gt;
but it is expected to have type&lt;br /&gt;
  False&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Computation inside the check ==&lt;br /&gt;
&lt;br /&gt;
Deciding definitional equality means running programs, so the Lean kernel contains an evaluator. Pure unfolding would make arithmetic on numerals hopeless, since &amp;lt;code&amp;gt;Nat&amp;lt;/code&amp;gt; is unary in its definition. The Lean kernel therefore computes &amp;lt;code&amp;gt;Nat.add&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Nat.sub&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Nat.mul&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Nat.div&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Nat.mod&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Nat.gcd&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Nat.pow&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Nat.beq&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Nat.ble&amp;lt;/code&amp;gt;, the bitwise operations and the shifts directly on literals, with the arbitrary-precision numbers of Lean&#039;s runtime.&amp;lt;ref name=&amp;quot;src-tc&amp;quot; /&amp;gt; Their size is capped all the same: the Lean kernel refuses a natural-number literal, whether written in the source or produced by this arithmetic, that takes more than 128 MB, a default that the operating-system variable &amp;lt;code&amp;gt;LEAN_NAT_MAX_SIZE&amp;lt;/code&amp;gt; can change.&amp;lt;ref name=&amp;quot;src-natmax&amp;quot;&amp;gt;Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/kernel/type_checker.cpp&amp;lt;/code&amp;gt;: the constant &amp;lt;code&amp;gt;LEAN_NAT_MAX_SIZE_DEFAULT&amp;lt;/code&amp;gt; (128 × 1024 × 1024 bytes), the functions &amp;lt;code&amp;gt;check_nat_size&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;infer_lit&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;reduce_nat&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;initialize_type_checker&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/kernel/type_checker.cpp&amp;lt;/ref&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;
theorem big : 2 ^ 64 * 2 ^ 64 = 2 ^ 128 := rfl&lt;br /&gt;
#print axioms big&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This prints &amp;lt;code&amp;gt;&#039;big&#039; does not depend on any axioms&amp;lt;/code&amp;gt;. The cost is that this arithmetic, and the runtime code behind it, is part of what must be trusted.&lt;br /&gt;
&lt;br /&gt;
== Its implementation ==&lt;br /&gt;
&lt;br /&gt;
The reference manual states that the Lean kernel is written in C++, and that independent reimplementations exist in Rust and in Lean, the aim being to have as many implementations as possible so that they can be cross-checked against each other.&amp;lt;ref name=&amp;quot;manual-elab&amp;quot; /&amp;gt; In version 4.34.1 the directory &amp;lt;code&amp;gt;src/kernel&amp;lt;/code&amp;gt; of the Lean source holds 36 C++ source and header files totalling 8,071 lines, blank lines and comments included; this count was made for this page by running &amp;lt;code&amp;gt;wc -l&amp;lt;/code&amp;gt; over those files as they stand at that version.&amp;lt;ref name=&amp;quot;src-kernel-dir&amp;quot;&amp;gt;Lean 4 source code, version 4.34.1 (2026), directory &amp;lt;code&amp;gt;src/kernel&amp;lt;/code&amp;gt; (36 files &amp;lt;code&amp;gt;*.cpp&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;*.h&amp;lt;/code&amp;gt;, plus &amp;lt;code&amp;gt;CMakeLists.txt&amp;lt;/code&amp;gt;). Apache License 2.0. https://github.com/leanprover/lean4/tree/v4.34.1/src/kernel&amp;lt;/ref&amp;gt; The count is a lower bound on what is trusted, not a measure of it: those files include headers from Lean&#039;s runtime and utility libraries, for numbers, names and memory management, which the count leaves out. The largest files are the type checker (1,373 lines) and the checker for inductive types (1,417 lines). The paper that introduced Lean 4 describes the Lean kernel as relatively small.&amp;lt;ref name=&amp;quot;lean4-paper&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 &#039;&#039;Automated Deduction – CADE 28&#039;&#039;, Lecture Notes in Computer Science 12699, Springer, 2021, pp. 625–635. doi:10.1007/978-3-030-79876-5_37&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Lean&#039;s environment ==&lt;br /&gt;
&lt;br /&gt;
Lean&#039;s environment, its table of definitions and theorems, is the Lean kernel&#039;s state. In 4.34.1 the Lean structure &amp;lt;code&amp;gt;Lean.Kernel.Environment&amp;lt;/code&amp;gt; maps each constant&#039;s name to its &amp;lt;code&amp;gt;ConstantInfo&amp;lt;/code&amp;gt;, and its documentation says that this table contains every constant that has already been type checked by the Lean kernel, that it is never destructively updated, and that its constructor is private to protect against changes that bypass the Lean kernel.&amp;lt;ref name=&amp;quot;src-env-lean&amp;quot;&amp;gt;Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Lean/Environment.lean&amp;lt;/code&amp;gt;: the structure &amp;lt;code&amp;gt;Lean.Kernel.Environment&amp;lt;/code&amp;gt;, the option &amp;lt;code&amp;gt;debug.skipKernelTC&amp;lt;/code&amp;gt; and the function &amp;lt;code&amp;gt;addDeclWithoutChecking&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/Environment.lean&amp;lt;/ref&amp;gt; The same structure carries &#039;&#039;&#039;extensions&#039;&#039;&#039;, further tables for data the Lean kernel ignores, such as simp lemmas, custom pretty printers and the compiler&#039;s intermediate code.&amp;lt;ref name=&amp;quot;src-env-lean&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;manual-elab&amp;quot; /&amp;gt; Adding a constant returns a new table; nothing already accepted is changed.&lt;br /&gt;
&lt;br /&gt;
== Where the trust ends ==&lt;br /&gt;
&lt;br /&gt;
The checked table is only as good as the path into it. Lean 4.34.1 has an option, &amp;lt;code&amp;gt;debug.skipKernelTC&amp;lt;/code&amp;gt;, whose own description warns that setting it &amp;quot;may compromise soundness&amp;quot; because proofs are then not checked by the Lean kernel, and a matching function, &amp;lt;code&amp;gt;addDeclWithoutChecking&amp;lt;/code&amp;gt;.&amp;lt;ref name=&amp;quot;src-env-lean&amp;quot; /&amp;gt; A Lean source file can also run arbitrary code while it is processed. The reference manual&#039;s guidance on validating proofs therefore recommends replaying the compiled files through the Lean kernel with a separate checker, and, for adversarial settings, building the proofs in a sandbox, exporting them and replaying them with the Lean kernel or an independent checker.&amp;lt;ref name=&amp;quot;manual-validating&amp;quot;&amp;gt;Lean Developers, &#039;&#039;The Lean Language Reference&#039;&#039;, version 4.34.0, &amp;quot;Validating a Lean Proof&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/ValidatingProofs/&amp;lt;/ref&amp;gt; [[Lean theorem prover/System/Proof export and independent checkers|Proof export and independent checkers]] takes this up. The soundness of the type theory itself, which no checker can establish from inside, is the subject of [[Lean theorem prover/Foundations/Consistency and the metatheory|consistency and the metatheory]].&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/System/Metavariables and unification|Metavariables and unification]] describes the holes the elaborator must fill before a term may reach the Lean kernel.&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>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/System/Elaboration&amp;diff=6786</id>
		<title>Lean theorem prover/System/Elaboration</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/System/Elaboration&amp;diff=6786"/>
		<updated>2026-10-15T19:35:04Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Elaboration}}&lt;br /&gt;
{{Plebeian|Lean theorem prover/Explainers/What a proof assistant does|Lean theorem prover/Explainers/When Lean says no}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Elaboration&#039;&#039;&#039; is the step that turns what a person types into a term of Lean&#039;s core type theory. The typed text leaves out a great deal: the types of arguments, the instances behind notation such as &amp;lt;code&amp;gt;+&amp;lt;/code&amp;gt;, conversions between number types, universe levels. The &#039;&#039;&#039;elaborator&#039;&#039;&#039; supplies all of it and produces a fully explicit term. That term then goes to the Lean kernel, which checks it. The elaborator&#039;s own reasoning is not trusted. This page follows a term from text to the Lean kernel and shows, with Lean 4.34.1&#039;s own output, what the elaborator adds.&lt;br /&gt;
&lt;br /&gt;
== From text to the Lean kernel ==&lt;br /&gt;
&lt;br /&gt;
Lean processes a source file one command at a time. Each command is parsed, then elaborated, and a new definition or theorem is checked by the Lean kernel and recorded in Lean&#039;s environment, its table of definitions and theorems. Each command can change how later commands are read, since a command may add new syntax.&amp;lt;ref name=&amp;quot;manual-elab&amp;quot;&amp;gt;Lean Developers, &#039;&#039;The Lean Language Reference&#039;&#039;, version 4.34.0, chapter &amp;quot;Elaboration and Compilation&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/Elaboration-and-Compilation/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;parser&#039;&#039;&#039; turns characters into a syntax tree of type &amp;lt;code&amp;gt;Syntax&amp;lt;/code&amp;gt;. The reference manual describes it as a recursive-descent parser that uses dynamic tables based on Pratt parsing, and its tables can be extended by any command.&amp;lt;ref name=&amp;quot;manual-elab&amp;quot; /&amp;gt; A syntax tree records what was written, not what it means: &amp;lt;code&amp;gt;x + 1&amp;lt;/code&amp;gt; parses the same whether &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt; is a natural number, an integer or a matrix.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;elaborator&#039;&#039;&#039; gives the tree its meaning. Term elaborators, in the manual&#039;s words, map syntax and an optional expected type to a core language expression, and they work in a setting that provides unification, type class instance synthesis and type checking.&amp;lt;ref name=&amp;quot;manual-elab&amp;quot; /&amp;gt; The result is an &amp;lt;code&amp;gt;Expr&amp;lt;/code&amp;gt;, the same data type the Lean kernel checks.&lt;br /&gt;
&lt;br /&gt;
== Macro expansion ==&lt;br /&gt;
&lt;br /&gt;
Much of Lean&#039;s notation is defined by &#039;&#039;&#039;macros&#039;&#039;&#039;: rules that rewrite one piece of syntax into another before it is given meaning. Macro expansion is not a separate pass. It is interleaved with elaboration.&amp;lt;ref name=&amp;quot;manual-elab&amp;quot; /&amp;gt; In Lean 4.34.1 the main elaboration loop first asks whether a macro applies to the syntax at hand; if one does, it elaborates the expansion instead, and only otherwise does it call an elaboration function registered for that kind of syntax.&amp;lt;ref name=&amp;quot;src-termelab&amp;quot;&amp;gt;Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Lean/Elab/Term/TermElabM.lean&amp;lt;/code&amp;gt;: the function &amp;lt;code&amp;gt;elabTermAux&amp;lt;/code&amp;gt; and the type &amp;lt;code&amp;gt;SyntheticMVarKind&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/Elab/Term/TermElabM.lean&amp;lt;/ref&amp;gt; The trace option &amp;lt;code&amp;gt;trace.Elab.step&amp;lt;/code&amp;gt; prints each step together with the expected type at that point:&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.Elab.step true in&lt;br /&gt;
#check (3 : Nat) ≠ 4&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;
3 ≠ 4 : Prop&lt;br /&gt;
[Elab.step] ✅️ expected type: &amp;amp;lt;not-available&amp;amp;gt;, term&lt;br /&gt;
    (3 : Nat) ≠ 4&lt;br /&gt;
  [Elab.step] ✅️ expected type: &amp;amp;lt;not-available&amp;amp;gt;, term&lt;br /&gt;
      binrel% Ne✝ (3 : Nat) 4&lt;br /&gt;
    [Elab.step] ✅️ expected type: &amp;amp;lt;not-available&amp;amp;gt;, term&lt;br /&gt;
        (3 : Nat)&lt;br /&gt;
      [Elab.step] ✅️ expected type: Type, term&lt;br /&gt;
          Nat&lt;br /&gt;
        [Elab.step.result] Nat&lt;br /&gt;
      [Elab.step] ✅️ expected type: Nat, term&lt;br /&gt;
          3&lt;br /&gt;
        [Elab.step.result] 3&lt;br /&gt;
      [Elab.step.result] 3&lt;br /&gt;
    [Elab.step] ✅️ expected type: &amp;amp;lt;not-available&amp;amp;gt;, term&lt;br /&gt;
        4&lt;br /&gt;
      [Elab.step.result] 4&lt;br /&gt;
    [Elab.step.result] 3 ≠ 4&lt;br /&gt;
  [Elab.step.result] 3 ≠ 4&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The symbol &amp;lt;code&amp;gt;≠&amp;lt;/code&amp;gt; is a macro. Its expansion, &amp;lt;code&amp;gt;binrel% Ne✝ (3 : Nat) 4&amp;lt;/code&amp;gt;, hands the two sides to &amp;lt;code&amp;gt;binrel%&amp;lt;/code&amp;gt;, an elaborator for binary relations. The dagger after &amp;lt;code&amp;gt;Ne&amp;lt;/code&amp;gt; marks a name introduced by the macro, which text written by the user cannot capture; [[Lean theorem prover/System/Syntax extension and hygienic macros|syntax extension and hygienic macros]] explains this hygiene, which the paper introducing Lean 4 describes as capture-avoiding.&amp;lt;ref name=&amp;quot;lean4-paper&amp;quot; /&amp;gt; The ascription &amp;lt;code&amp;gt;(3 : Nat)&amp;lt;/code&amp;gt; passes the expected type &amp;lt;code&amp;gt;Nat&amp;lt;/code&amp;gt; down to the numeral &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Expected types ==&lt;br /&gt;
&lt;br /&gt;
The expected type is the elaborator&#039;s main source of information. Some notation cannot be read at all without it. The anonymous constructor &amp;lt;code&amp;gt;⟨1, 2⟩&amp;lt;/code&amp;gt; names no type, so on its own it fails:&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;
#check ⟨1, 2⟩&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean answers &amp;lt;code&amp;gt;Invalid `⟨...⟩` notation: The expected type of this term could not be determined&amp;lt;/code&amp;gt;. With an ascription, &amp;lt;code&amp;gt;#check (⟨1, 2⟩ : Nat × Nat)&amp;lt;/code&amp;gt; prints &amp;lt;code&amp;gt;(1, 2) : Nat × Nat&amp;lt;/code&amp;gt;: knowing the type, the elaborator finds the structure&#039;s one constructor and applies it.&lt;br /&gt;
&lt;br /&gt;
== What the elaborator fills in ==&lt;br /&gt;
&lt;br /&gt;
The option &amp;lt;code&amp;gt;pp.all&amp;lt;/code&amp;gt; prints a term with nothing hidden: every implicit argument, every instance, every universe level. It is the way to see what the elaborator actually produced.&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 @id&lt;br /&gt;
set_option pp.all true in&lt;br /&gt;
#check id 5&lt;br /&gt;
set_option pp.all true in&lt;br /&gt;
#check (2 : Int) + (3 : Nat)&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;
@id : {α : Sort u_1} → α → α&lt;br /&gt;
@id.{1} Nat (@OfNat.ofNat.{0} Nat (nat_lit 5) (instOfNatNat (nat_lit 5))) : Nat&lt;br /&gt;
@HAdd.hAdd.{0, 0, 0} Int Int Int (@instHAdd.{0} Int Int.instAdd)&lt;br /&gt;
  (@OfNat.ofNat.{0} Int (nat_lit 2) (@instOfNat (nat_lit 2)))&lt;br /&gt;
  (@Nat.cast.{0} Int instNatCastInt (@OfNat.ofNat.{0} Nat (nat_lit 3) (instOfNatNat (nat_lit 3)))) : Int&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Four kinds of filling are visible.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Implicit arguments.&#039;&#039;&#039; The braces in &amp;lt;code&amp;gt;{α : Sort u_1}&amp;lt;/code&amp;gt; mark an argument the user does not write. For &amp;lt;code&amp;gt;id 5&amp;lt;/code&amp;gt; the elaborator creates a placeholder for &amp;lt;code&amp;gt;α&amp;lt;/code&amp;gt;, a &#039;&#039;metavariable&#039;&#039;, and unifies it with the type of the argument &amp;lt;code&amp;gt;5&amp;lt;/code&amp;gt;, which is itself still open; it becomes &amp;lt;code&amp;gt;Nat&amp;lt;/code&amp;gt; when the default instance for numerals is applied, as described under postponement below. [[Lean theorem prover/System/Metavariables and unification|Metavariables and unification]] treats this machinery.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Universe levels.&#039;&#039;&#039; The universe parameter &amp;lt;code&amp;gt;u_1&amp;lt;/code&amp;gt; of &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt; is instantiated to &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;, since &amp;lt;code&amp;gt;Nat : Type&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Type&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;Sort 1&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Instances.&#039;&#039;&#039; A numeral is not a primitive: &amp;lt;code&amp;gt;5&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;OfNat.ofNat Nat 5 (instOfNatNat 5)&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;+&amp;lt;/code&amp;gt; becomes the method &amp;lt;code&amp;gt;HAdd.hAdd&amp;lt;/code&amp;gt; of a type class with the instance &amp;lt;code&amp;gt;instHAdd&amp;lt;/code&amp;gt; built on &amp;lt;code&amp;gt;Int.instAdd&amp;lt;/code&amp;gt;. The instances are found by search; [[Lean theorem prover/System/Type classes and instance resolution|type classes and instance resolution]] describes it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Coercions.&#039;&#039;&#039; The second summand was written as a natural number but is used where an integer is expected. The elaborator inserts &amp;lt;code&amp;gt;Nat.cast&amp;lt;/code&amp;gt;, which the ordinary printer shows as &amp;lt;code&amp;gt;↑&amp;lt;/code&amp;gt;. The reference manual states that a coercion is used when a term of one type appears where another is expected, and that coercions are found by type class instance synthesis.&amp;lt;ref name=&amp;quot;manual-coe&amp;quot;&amp;gt;Lean Developers, &#039;&#039;The Lean Language Reference&#039;&#039;, version 4.34.0, chapter &amp;quot;Coercions&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/Coercions/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Postponement ==&lt;br /&gt;
&lt;br /&gt;
The elaborator works through a term roughly from left to right, but information often arrives late. A subterm may need a type that a later argument determines, or an instance problem may still contain unknowns. In such cases the elaborator does not fail. It puts a &#039;&#039;&#039;synthetic metavariable&#039;&#039;&#039; in place of the unfinished work and comes back to it. In Lean 4.34.1 such a placeholder has one of four kinds: an instance to be synthesised, a coercion to be inserted, a tactic block to be run, or a term whose elaboration was postponed.&amp;lt;ref name=&amp;quot;src-termelab&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The pending placeholders are resumed in a fixed order. Lean retries them while progress is being made. When none progresses, it retries without allowing further postponement, then applies &#039;&#039;&#039;default instances&#039;&#039;&#039; to instance problems still unsolved, then forces the remaining problems to succeed or report an error. Tactic blocks run last, when the rest of the term is as complete as it will get.&amp;lt;ref name=&amp;quot;src-synth&amp;quot;&amp;gt;Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Lean/Elab/SyntheticMVars.lean&amp;lt;/code&amp;gt;: the function &amp;lt;code&amp;gt;synthesizeSyntheticMVars&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/Elab/SyntheticMVars.lean&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Default instances explain a small puzzle:&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 fun x =&amp;gt; x + 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean prints &amp;lt;code&amp;gt;fun x =&amp;gt; x + 1 : Nat → Nat&amp;lt;/code&amp;gt;, although nothing in the text says &amp;lt;code&amp;gt;Nat&amp;lt;/code&amp;gt;. The type of &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt; is unknown, so the instance problem for &amp;lt;code&amp;gt;+&amp;lt;/code&amp;gt; stays stuck through every round. At the default step, Lean&#039;s prelude marks &amp;lt;code&amp;gt;instHAdd&amp;lt;/code&amp;gt; as a default instance, which makes both summands and the result share one type, and marks &amp;lt;code&amp;gt;instOfNatNat&amp;lt;/code&amp;gt; as a low-priority default instance for numerals, which makes that type &amp;lt;code&amp;gt;Nat&amp;lt;/code&amp;gt;.&amp;lt;ref name=&amp;quot;src-prelude&amp;quot;&amp;gt;Lean 4 source code, version 4.34.1 (2026), file &amp;lt;code&amp;gt;src/Init/Prelude.lean&amp;lt;/code&amp;gt;: the attributes &amp;lt;code&amp;gt;@[default_instance]&amp;lt;/code&amp;gt; on &amp;lt;code&amp;gt;instHAdd&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;@[default_instance 100]&amp;lt;/code&amp;gt; on &amp;lt;code&amp;gt;instOfNatNat&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Init/Prelude.lean&amp;lt;/ref&amp;gt; Where no default applies, the elaborator reports the gap. Writing &amp;lt;code&amp;gt;def g := fun x =&amp;gt; x&amp;lt;/code&amp;gt; gives &amp;lt;code&amp;gt;Failed to infer type of binder `x`&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Why the elaborator is not trusted ==&lt;br /&gt;
&lt;br /&gt;
The elaborator is large, it is written in Lean, and users extend it: every new macro, elaborator or tactic becomes part of it.&amp;lt;ref name=&amp;quot;lean4-paper&amp;quot; /&amp;gt; The design does not ask anyone to trust it. Its output is checked by the Lean kernel, and the reference manual gives the reason: to guard against potential bugs in elaboration.&amp;lt;ref name=&amp;quot;manual-elab&amp;quot; /&amp;gt; The Lean kernel does no unification of its own and no termination checking; it expects the elaborator to have done that work, and checks the explicit result.&amp;lt;ref name=&amp;quot;manual-elab&amp;quot; /&amp;gt; As long as its output goes through the Lean kernel, a faulty elaborator can therefore cause a rejection, or a slow check, but not the acceptance of a false theorem. [[Lean theorem prover/System/The Lean kernel|The Lean kernel]] describes the checker.&lt;br /&gt;
&lt;br /&gt;
One thing the Lean kernel cannot protect is meaning. The elaborator decides what a statement says: which instance &amp;lt;code&amp;gt;+&amp;lt;/code&amp;gt; refers to, which coercion was inserted, which type a numeral was given. The Lean kernel then checks a proof of &#039;&#039;that&#039;&#039; statement. The reference manual&#039;s guidance on validating proofs makes the same separation: where there is doubt that a theorem means what it appears to mean, its statement and every definition it refers to must be examined, particularly where custom notation or type classes are involved.&amp;lt;ref name=&amp;quot;manual-validating&amp;quot;&amp;gt;Lean Developers, &#039;&#039;The Lean Language Reference&#039;&#039;, version 4.34.0, &amp;quot;Validating a Lean Proof&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/ValidatingProofs/&amp;lt;/ref&amp;gt; &amp;lt;code&amp;gt;pp.all&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;#print&amp;lt;/code&amp;gt; are the tools for that reading.&lt;br /&gt;
&lt;br /&gt;
== Beyond terms ==&lt;br /&gt;
&lt;br /&gt;
Elaboration also records what it did. Info trees relate the elaborated terms to the user&#039;s original syntax, and an editor uses them to show types on hover and goals in a proof.&amp;lt;ref name=&amp;quot;manual-elab&amp;quot; /&amp;gt; Commands are elaborated too. A command elaborator may add definitions, open namespaces or declare new syntax, and these are changes to Lean&#039;s state, not terms. This extensibility, a parser, elaborator and tactic framework that users can extend from Lean itself, is a design aim stated in the abstract and the conclusion of the paper that introduced Lean 4.&amp;lt;ref name=&amp;quot;lean4-paper&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 &#039;&#039;Automated Deduction – CADE 28&#039;&#039;, Lecture Notes in Computer Science 12699, Springer, 2021, pp. 625–635. doi:10.1007/978-3-030-79876-5_37&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/System/The Lean kernel|The Lean kernel]] describes what happens to the elaborated term. [[Lean theorem prover/System/Metavariables and unification|Metavariables and unification]] opens up the placeholders used above.&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>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/Foundations/Consistency_and_the_metatheory&amp;diff=6785</id>
		<title>Lean theorem prover/Foundations/Consistency and the metatheory</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Foundations/Consistency_and_the_metatheory&amp;diff=6785"/>
		<updated>2026-10-15T19:35:02Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Consistency and the metatheory}}&lt;br /&gt;
{{Plebeian|Lean theorem prover/Explainers/What has to be trusted}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;metatheory&#039;&#039;&#039; of Lean is what can be proved &#039;&#039;about&#039;&#039; its type theory rather than&lt;br /&gt;
&#039;&#039;in&#039;&#039; it. The central question is consistency: whether a closed proof of&lt;br /&gt;
&amp;lt;code&amp;gt;False&amp;lt;/code&amp;gt; can ever pass Lean&#039;s kernel. The answer known today is relative, and it was proved for the type&lt;br /&gt;
theory of Lean 3. That theory, with its three axioms, can be interpreted in Zermelo–Fraenkel&lt;br /&gt;
set theory with choice (ZFC) extended by inaccessible cardinals, one axiom &amp;quot;there are &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; inaccessible&lt;br /&gt;
cardinals&amp;quot; for each natural number &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, so it is consistent if that set theory&lt;br /&gt;
is. Several properties one might expect of a type theory fail for Lean, among them&lt;br /&gt;
decidability of definitional equality and normalisation, and none of these failures makes&lt;br /&gt;
the checker unsound. If Lean is consistent, it cannot prove its own consistency. This page sets&lt;br /&gt;
out each of these points and its source.&lt;br /&gt;
&lt;br /&gt;
== The consistency theorem ==&lt;br /&gt;
&lt;br /&gt;
Carneiro&#039;s thesis of 2019 writes down the type theory of Lean 3&amp;lt;ref name=&amp;quot;lean4lean&amp;quot; /&amp;gt; in&lt;br /&gt;
full, including [[Lean theorem prover/Foundations/The three axioms|the three axioms]], and constructs a&lt;br /&gt;
set-theoretic model of it. Its conclusion, Corollary 6.8, is that Lean is consistent if ZFC&lt;br /&gt;
together with the axioms &amp;quot;there are &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; inaccessible cardinals&amp;quot;, for every&lt;br /&gt;
natural number &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, is consistent: there is no proof of &amp;lt;code&amp;gt;False&amp;lt;/code&amp;gt; that&lt;br /&gt;
the Lean kernel verifies.&amp;lt;ref name=&amp;quot;carneiro&amp;quot;&amp;gt;Mario Carneiro, &#039;&#039;The Type Theory of Lean&#039;&#039;, Master&#039;s thesis, Carnegie Mellon University, 2019; abstract, §1.2 (pp. 4–5), §3 (pp. 15–19), Theorem 4.1 (p. 19), Theorem 6.7 (p. 37) and Corollary 6.8 (p. 41). https://github.com/digama0/lean-type-theory/releases/tag/v1.0&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\mathrm{Con}\bigl(\mathrm{ZFC} + \{\exists\, n \text{ inaccessible cardinals} : n &amp;lt; \omega\}\bigr) \;\Rightarrow\; \mathrm{Con}(\mathrm{Lean})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The model is the expected one. Types are sets and terms are their elements.&lt;br /&gt;
&amp;lt;code&amp;gt;Prop&amp;lt;/code&amp;gt; is a two-element set whose members are the empty set and a one-element&lt;br /&gt;
set, so every proposition is interpreted as empty or as a one-element set, which validates&lt;br /&gt;
proof irrelevance. Each higher universe is interpreted inside a level of the cumulative hierarchy&lt;br /&gt;
cut off at an inaccessible cardinal, because universes are closed under function types and&lt;br /&gt;
inductive types, which makes them Grothendieck universes. Lean has a universe for every&lt;br /&gt;
natural number, so the full hierarchy calls for an inaccessible for each of them; a single&lt;br /&gt;
proof mentions only finitely many universes, which is why the hypothesis is stated one&lt;br /&gt;
&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; at a time. The impredicativity of &amp;lt;code&amp;gt;Prop&amp;lt;/code&amp;gt; corresponds to full power&lt;br /&gt;
sets in ZFC.&amp;lt;ref name=&amp;quot;carneiro&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Carneiro calls the assumption optimal, for the following reason. Inside Lean one can build a&lt;br /&gt;
model of ZFC in each universe above the lowest, and define inaccessible cardinals in the&lt;br /&gt;
larger ones, so Lean proves the consistency of ZFC with any given finite number of&lt;br /&gt;
inaccessibles.&amp;lt;ref name=&amp;quot;carneiro&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Relative consistency and Werner&#039;s theorem ==&lt;br /&gt;
&lt;br /&gt;
The two directions were matched for the Calculus of Inductive Constructions, the theory&lt;br /&gt;
behind Coq, by Werner in 1997.&amp;lt;ref name=&amp;quot;werner&amp;quot;&amp;gt;Benjamin Werner, &amp;quot;Sets in types, types in sets&amp;quot;, in Martín Abadi and Takayasu Ito (eds.), &#039;&#039;Theoretical Aspects of Computer Software (TACS 1997)&#039;&#039;, Lecture Notes in Computer Science 1281, Springer, 1997, pp. 530–546. https://doi.org/10.1007/BFb0014566&amp;lt;/ref&amp;gt; Writing &amp;lt;math&amp;gt;\mathrm{ZFC}_n&amp;lt;/math&amp;gt;&lt;br /&gt;
for ZFC with &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; inaccessibles and &amp;lt;math&amp;gt;\mathrm{CIC}_n&amp;lt;/math&amp;gt; for the calculus&lt;br /&gt;
with &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; universes, Carneiro summarises Werner&#039;s result as&amp;lt;ref name=&amp;quot;carneiro&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\mathrm{ZFC}_n \vdash \mathrm{Con}(\mathrm{CIC}_{n+1}) \qquad\qquad \mathrm{CIC}_{n+2} \vdash \mathrm{Con}(\mathrm{ZFC}_n)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
so that the unions over all &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; are equiconsistent. Werner&#039;s encoding of set theory in&lt;br /&gt;
the calculus also assumes excluded middle and a type-theoretic axiom of choice.&amp;lt;ref name=&amp;quot;werner&amp;quot; /&amp;gt; Werner&#039;s construction of&lt;br /&gt;
set theory inside type theory has been replicated in Lean with minor changes, which gives&lt;br /&gt;
&amp;lt;math&amp;gt;\mathrm{Lean}_{n+2} \vdash \mathrm{Con}(\mathrm{ZFC}_n)&amp;lt;/math&amp;gt;. Carneiro&#039;s model&lt;br /&gt;
supplies the other direction, &amp;lt;math&amp;gt;\mathrm{ZFC}_{n+1} \vdash \mathrm{Con}(\mathrm{Lean}_{n+1})&amp;lt;/math&amp;gt;,&lt;br /&gt;
so Lean with all its universes is equiconsistent with both. He does not attempt sharp&lt;br /&gt;
universe bounds, and notes that matching Werner&#039;s exactly would require global choice, a&lt;br /&gt;
choice function on the whole set-theoretic universe, to interpret Lean&#039;s choice&lt;br /&gt;
axiom.&amp;lt;ref name=&amp;quot;carneiro&amp;quot; /&amp;gt; Lean&#039;s consistency strength is thus that of the union of the&lt;br /&gt;
theories &amp;lt;math&amp;gt;\mathrm{ZFC}_n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== What fails ==&lt;br /&gt;
&lt;br /&gt;
The same thesis records negative results, and later work adds one more.&amp;lt;ref name=&amp;quot;carneiro&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Definitional equality is undecidable, and so is type checking.&#039;&#039;&#039; The accessibility&lt;br /&gt;
predicate, together with proof irrelevance, lets a definitional-equality question encode&lt;br /&gt;
the halting problem. The argument is on&lt;br /&gt;
[[Lean theorem prover/Foundations/Proof irrelevance and subsingleton elimination|proof irrelevance and subsingleton elimination]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The checker&#039;s equality is weaker than the theory&#039;s.&#039;&#039;&#039; Lean&#039;s kernel implements a&lt;br /&gt;
decidable approximation, algorithmic equality, which is not transitive. Typing measured by&lt;br /&gt;
it fails subject reduction, and the reduction relation is not confluent (the Church–Rosser&lt;br /&gt;
property fails), so reducing both sides to normal form is not a decision procedure. A&lt;br /&gt;
modified reduction restores confluence at the cost of termination, enough to prove that&lt;br /&gt;
every term has a unique type up to definitional equality.&amp;lt;ref name=&amp;quot;carneiro&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Normalisation fails.&#039;&#039;&#039; Abel and Coquand showed that a type theory with an impredicative&lt;br /&gt;
&amp;lt;code&amp;gt;Prop&amp;lt;/code&amp;gt; and a proof-irrelevant equality loses normalisation. One of their&lt;br /&gt;
counterexamples uses only &amp;lt;code&amp;gt;propext&amp;lt;/code&amp;gt;, one of Lean&#039;s standard axioms, and gives a&lt;br /&gt;
closed proof with no weak head normal form; they note that it replays directly in Lean 3.4.2.&amp;lt;ref name=&amp;quot;abel-coquand&amp;quot;&amp;gt;Andreas Abel and Thierry Coquand, &amp;quot;Failure of normalization in impredicative type theory with proof-irrelevant propositional equality&amp;quot;, &#039;&#039;Logical Methods in Computer Science&#039;&#039; 16(2) (2020), paper 14. https://doi.org/10.23638/LMCS-16(2:14)2020&amp;lt;/ref&amp;gt; It&lt;br /&gt;
transcribes directly into Lean 4.34.1:&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 linter.defProp false&lt;br /&gt;
&lt;br /&gt;
def T : Prop := ∀ A : Prop, A → A&lt;br /&gt;
&lt;br /&gt;
def delta : T → T := fun z =&amp;gt; z (T → T) id z&lt;br /&gt;
&lt;br /&gt;
def omega : T := fun A a =&amp;gt; cast (propext ⟨fun _ =&amp;gt; a, fun _ =&amp;gt; id⟩ : (T → T) = A) delta&lt;br /&gt;
&lt;br /&gt;
def Omega : T := delta omega&lt;br /&gt;
&lt;br /&gt;
#print axioms Omega&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This prints &amp;lt;code&amp;gt;&#039;Omega&#039; depends on axioms: [propext]&amp;lt;/code&amp;gt;. The type &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt;&lt;br /&gt;
quantifies over all propositions, which is possible only because &amp;lt;code&amp;gt;Prop&amp;lt;/code&amp;gt; is&lt;br /&gt;
impredicative. Given any proposition &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; and a proof &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt; of it,&lt;br /&gt;
&amp;lt;code&amp;gt;propext&amp;lt;/code&amp;gt; makes &amp;lt;code&amp;gt;T → T&amp;lt;/code&amp;gt; equal to &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;, because both are&lt;br /&gt;
true; &amp;lt;code&amp;gt;omega&amp;lt;/code&amp;gt; casts &amp;lt;code&amp;gt;delta&amp;lt;/code&amp;gt; along that equation. When the cast is&lt;br /&gt;
used at &amp;lt;code&amp;gt;A = T → T&amp;lt;/code&amp;gt; itself the two sides of the equation coincide, the cast&lt;br /&gt;
reduces away, and &amp;lt;code&amp;gt;delta omega&amp;lt;/code&amp;gt; unfolds back to &amp;lt;code&amp;gt;delta omega&amp;lt;/code&amp;gt;. Asked&lt;br /&gt;
to normalise the proof, Lean gives up, even with its recursion limit raised to 20,000:&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;
set_option maxRecDepth 20000 in&lt;br /&gt;
#reduce (proofs := true) Omega&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The error is &amp;lt;code&amp;gt;maximum recursion depth has been reached&amp;lt;/code&amp;gt;. The failure reaches&lt;br /&gt;
beyond proofs. Carneiro&#039;s later paper on an&lt;br /&gt;
independent checker gives a variant in which a natural number defined by eliminating a&lt;br /&gt;
proof built from &amp;lt;code&amp;gt;Omega&amp;lt;/code&amp;gt; sends a definitional-equality check into the same&lt;br /&gt;
loop:&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;, arXiv:2403.14064, version 3, 14 September 2025; abstract, §1, §3.2.1, §4.1 and §9. https://arxiv.org/abs/2403.14064&amp;lt;/ref&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;
inductive Foo : Prop&lt;br /&gt;
  | mk : T → Foo&lt;br /&gt;
&lt;br /&gt;
def foo : Foo := Omega Foo (Foo.mk fun _ =&amp;gt; id)&lt;br /&gt;
&lt;br /&gt;
example : foo.recOn (motive := fun _ =&amp;gt; Nat) (fun _ =&amp;gt; 1) = 1 := by&lt;br /&gt;
  rfl&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean again reports &amp;lt;code&amp;gt;maximum recursion depth has been reached&amp;lt;/code&amp;gt;. Abel and Coquand&lt;br /&gt;
stress what is not at stake: consistency and canonicity are unaffected, and they compare the&lt;br /&gt;
situation to extensional type theory, which has an equality reflection rule.&amp;lt;ref name=&amp;quot;abel-coquand&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Why the checker is still sound ==&lt;br /&gt;
&lt;br /&gt;
Carneiro&#039;s argument needs one thing: whatever the checker accepts must be derivable in a&lt;br /&gt;
theory that has a model. He proves that algorithmic equality implies the ideal definitional&lt;br /&gt;
equality for well-typed terms. So if a term of type &amp;lt;code&amp;gt;False&amp;lt;/code&amp;gt; passed the algorithmic&lt;br /&gt;
typing judgment, his description of what Lean&#039;s kernel checks, that term would have type&lt;br /&gt;
&amp;lt;code&amp;gt;False&amp;lt;/code&amp;gt; in the ideal system, and the model would then contain&lt;br /&gt;
an element of the empty set. This is precisely the proof of Corollary 6.8.&amp;lt;ref name=&amp;quot;carneiro&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The failures above are therefore failures of completeness and of termination, not of&lt;br /&gt;
soundness. A checker that is incomplete rejects some correct terms. A checker that may not&lt;br /&gt;
terminate either loops or, as Lean does in the examples above, stops at a resource limit&lt;br /&gt;
and reports an error. Neither outcome accepts a false statement. Carneiro observes that the soundness proof of his&lt;br /&gt;
thesis, unlike MetaRocq&#039;s, does not depend on termination.&amp;lt;ref name=&amp;quot;lean4lean&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Proving consistency inside Lean ==&lt;br /&gt;
&lt;br /&gt;
Gödel&#039;s second incompleteness theorem sets the limit. A consistent formal system in which a&lt;br /&gt;
modest amount of arithmetic can be carried out cannot prove its own&lt;br /&gt;
consistency.&amp;lt;ref name=&amp;quot;godel&amp;quot;&amp;gt;Kurt Gödel, &amp;quot;Über formal unentscheidbare Sätze der Principia Mathematica und verwandter Systeme I&amp;quot;, &#039;&#039;Monatshefte für Mathematik und Physik&#039;&#039; 38 (1931), 173–198. https://doi.org/10.1007/BF01700692&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;sep-godel&amp;quot;&amp;gt;Panu Raatikainen, &amp;quot;Gödel&#039;s Incompleteness Theorems&amp;quot;, &#039;&#039;Stanford Encyclopedia of Philosophy&#039;&#039;, substantive revision of 8 October 2025, §1 and §3. https://plato.stanford.edu/entries/goedel-incompleteness/&amp;lt;/ref&amp;gt; Lean formalises far more than&lt;br /&gt;
that arithmetic, so if Lean is consistent, no Lean proof of &amp;quot;Lean is consistent&amp;quot; exists.&lt;br /&gt;
Carneiro&#039;s theorem respects the limit in the usual way: it is a proof in a different&lt;br /&gt;
system, ZFC with inaccessibles, and its conclusion is relative to that system&#039;s&lt;br /&gt;
consistency. The independent-checker project names Gödel&#039;s theorem as the reason&lt;br /&gt;
that nothing implying the unconditional soundness of Lean will be directly provable in Lean,&lt;br /&gt;
and plans to formalise Carneiro&#039;s relative consistency proof, which assumes large&lt;br /&gt;
cardinals.&amp;lt;ref name=&amp;quot;lean4lean&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The theory and the implementation ==&lt;br /&gt;
&lt;br /&gt;
A consistency proof covers a mathematical description of the theory, not the program that&lt;br /&gt;
checks it. The Lean 4 kernel extended the theory Carneiro analysed with features such as&lt;br /&gt;
nested inductive types and η for structures. Carneiro writes that these change the theory&lt;br /&gt;
enough that the 2019 proof no longer applies directly, pointing to later work that covers&lt;br /&gt;
some of the changes, and that some soundness bugs entered Lean&#039;s kernel during the move to&lt;br /&gt;
Lean 4.&amp;lt;ref name=&amp;quot;lean4lean&amp;quot; /&amp;gt; One response is independent checking: a&lt;br /&gt;
second complete type checker written in Lean, able to check all of Mathlib, with part of it&lt;br /&gt;
formally verified against a formalisation of the type theory. That work has already found and&lt;br /&gt;
reported one soundness bug in Lean&#039;s kernel, since fixed.&amp;lt;ref name=&amp;quot;lean4lean&amp;quot; /&amp;gt; The reference&lt;br /&gt;
manual&#039;s guide to validating proofs lists the soundness of Lean&#039;s logic among the&lt;br /&gt;
assumptions that remain even after the strictest checks.&amp;lt;ref name=&amp;quot;refman-validating&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, version 4.34.0, &amp;quot;Validating a Lean Proof&amp;quot;, section &amp;quot;Remaining Issues&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/ValidatingProofs/&amp;lt;/ref&amp;gt;&lt;br /&gt;
The checkers themselves are the subject of&lt;br /&gt;
[[Lean theorem prover/System/Proof export and independent checkers|proof export and independent checkers]].&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/System/Elaboration|Elaboration]] begins the pages on how Lean works,&lt;br /&gt;
from the text a person types to the term the Lean kernel checks.&lt;br /&gt;
[[Lean theorem prover/System/The Lean kernel|The Lean kernel]] describes the program whose&lt;br /&gt;
soundness this page has been about.&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>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/Foundations/Proof_irrelevance_and_subsingleton_elimination&amp;diff=6784</id>
		<title>Lean theorem prover/Foundations/Proof irrelevance and subsingleton elimination</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Foundations/Proof_irrelevance_and_subsingleton_elimination&amp;diff=6784"/>
		<updated>2026-10-15T19:35:01Z</updated>

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

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Classical logic from choice}}&lt;br /&gt;
{{Plebeian|Lean theorem prover/Explainers/What the axioms are}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
&lt;br /&gt;
The rules of Lean&#039;s type theory, taken alone, are constructive: to assert &amp;lt;code&amp;gt;p ∨ ¬p&amp;lt;/code&amp;gt;&lt;br /&gt;
is to know which of the two disjuncts holds, and for an arbitrary &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt; that is not&lt;br /&gt;
known.&amp;lt;ref name=&amp;quot;tpil-logic&amp;quot;&amp;gt;Jeremy Avigad, Leonardo de Moura, Soonho Kong and Sebastian Ullrich, &#039;&#039;Theorem Proving in Lean 4&#039;&#039;, chapter 3 &amp;quot;Propositions and Proofs&amp;quot;, §3.5 &amp;quot;Classical Logic&amp;quot;. https://lean-lang.org/theorem_proving_in_lean4/Propositions-and-Proofs/&amp;lt;/ref&amp;gt; Lean does not add excluded middle as an axiom. It proves it, as the theorem&lt;br /&gt;
&amp;lt;code&amp;gt;Classical.em&amp;lt;/code&amp;gt;, from the axiom of choice together with propositional and function&lt;br /&gt;
extensionality. The argument is known as &#039;&#039;&#039;Diaconescu&#039;s theorem&#039;&#039;&#039;. This page follows the&lt;br /&gt;
proof as Lean&#039;s core library carries it, then the decidability of every proposition that&lt;br /&gt;
follows from it, the &amp;lt;code&amp;gt;noncomputable&amp;lt;/code&amp;gt; marker, and what is lost computationally.&lt;br /&gt;
&lt;br /&gt;
== The statement ==&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 @Classical.em&lt;br /&gt;
#print axioms Classical.em&lt;br /&gt;
&amp;lt;/pre&amp;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;
Classical.em : ∀ (p : Prop), p ∨ ¬p&lt;br /&gt;
&#039;Classical.em&#039; depends on axioms: [propext, Classical.choice, Quot.sound]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All three axioms of [[Lean theorem prover/Foundations/The three axioms|the three axioms]]&lt;br /&gt;
appear. &amp;lt;code&amp;gt;Quot.sound&amp;lt;/code&amp;gt; enters through &amp;lt;code&amp;gt;funext&amp;lt;/code&amp;gt;, which Lean proves from&lt;br /&gt;
quotients.&lt;br /&gt;
&lt;br /&gt;
== The argument ==&lt;br /&gt;
&lt;br /&gt;
Fix a proposition &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt;. Define two predicates on propositions:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;U(x) \;:\equiv\; (x = \mathrm{True}) \lor p \qquad\qquad V(x) \;:\equiv\; (x = \mathrm{False}) \lor p&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each is inhabited: &amp;lt;math&amp;gt;U(\mathrm{True})&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;V(\mathrm{False})&amp;lt;/math&amp;gt; hold by&lt;br /&gt;
their left disjuncts. Choice therefore yields a proposition &amp;lt;math&amp;gt;u&amp;lt;/math&amp;gt; with&lt;br /&gt;
&amp;lt;math&amp;gt;U(u)&amp;lt;/math&amp;gt; and a proposition &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; with &amp;lt;math&amp;gt;V(v)&amp;lt;/math&amp;gt;. Two facts follow.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;First, either &amp;lt;math&amp;gt;u \neq v&amp;lt;/math&amp;gt; or &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt;.&#039;&#039;&#039; Each of &amp;lt;math&amp;gt;U(u)&amp;lt;/math&amp;gt; and&lt;br /&gt;
&amp;lt;math&amp;gt;V(v)&amp;lt;/math&amp;gt; is a disjunction, giving four cases. If either right disjunct holds,&lt;br /&gt;
&amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; holds. In the remaining case &amp;lt;math&amp;gt;u = \mathrm{True}&amp;lt;/math&amp;gt; and&lt;br /&gt;
&amp;lt;math&amp;gt;v = \mathrm{False}&amp;lt;/math&amp;gt;, and since &amp;lt;math&amp;gt;\mathrm{True} \neq \mathrm{False}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&amp;lt;math&amp;gt;u \neq v&amp;lt;/math&amp;gt;. This step is a case analysis on proofs of disjunctions, and it&lt;br /&gt;
produces a proposition, so it is permitted.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Second, &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; implies &amp;lt;math&amp;gt;u = v&amp;lt;/math&amp;gt;.&#039;&#039;&#039; If &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; holds, both&lt;br /&gt;
predicates are true of every &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;, so &amp;lt;math&amp;gt;U(x)&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;V(x)&amp;lt;/math&amp;gt; are&lt;br /&gt;
equivalent for each &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;. Propositional extensionality makes them equal for each&lt;br /&gt;
&amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;, and function extensionality makes &amp;lt;math&amp;gt;U = V&amp;lt;/math&amp;gt;. The choice function&lt;br /&gt;
applied to equal predicates gives equal results, so &amp;lt;math&amp;gt;u = v&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Combining the two: if &amp;lt;math&amp;gt;u \neq v&amp;lt;/math&amp;gt;, the second fact gives &amp;lt;math&amp;gt;\neg p&amp;lt;/math&amp;gt;;&lt;br /&gt;
otherwise &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt;. Either way &amp;lt;math&amp;gt;p \lor \neg p&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The core library&#039;s proof, in &amp;lt;code&amp;gt;Init/Classical.lean&amp;lt;/code&amp;gt;, follows exactly these&lt;br /&gt;
steps.&amp;lt;ref name=&amp;quot;classical&amp;quot;&amp;gt;Lean 4 source, file &amp;lt;code&amp;gt;src/Init/Classical.lean&amp;lt;/code&amp;gt;, version 4.34.1: &amp;lt;code&amp;gt;Classical.em&amp;lt;/code&amp;gt; (&amp;quot;Diaconescu&#039;s theorem&amp;quot;), &amp;lt;code&amp;gt;Classical.choose&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Classical.propDecidable&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Init/Classical.lean&amp;lt;/ref&amp;gt; Below is a copy, lightly condensed, in which one case is closed&lt;br /&gt;
by an explicit term where the original calls &amp;lt;code&amp;gt;simp&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;
open Classical in&lt;br /&gt;
theorem em&#039; (p : Prop) : p ∨ ¬p :=&lt;br /&gt;
  let U (x : Prop) : Prop := x = True ∨ p&lt;br /&gt;
  let V (x : Prop) : Prop := x = False ∨ p&lt;br /&gt;
  have exU : ∃ x, U x := ⟨True, Or.inl rfl⟩&lt;br /&gt;
  have exV : ∃ x, V x := ⟨False, Or.inl rfl⟩&lt;br /&gt;
  let u : Prop := choose exU&lt;br /&gt;
  let v : Prop := choose exV&lt;br /&gt;
  have u_def : U u := choose_spec exU&lt;br /&gt;
  have v_def : V v := choose_spec exV&lt;br /&gt;
  have not_uv_or_p : u ≠ v ∨ p :=&lt;br /&gt;
    match u_def, v_def with&lt;br /&gt;
    | Or.inr h, _ =&amp;gt; Or.inr h&lt;br /&gt;
    | _, Or.inr h =&amp;gt; Or.inr h&lt;br /&gt;
    | Or.inl hut, Or.inl hvf =&amp;gt;&lt;br /&gt;
      Or.inl fun huv =&amp;gt; true_ne_false (hut.symm.trans (huv.trans hvf))&lt;br /&gt;
  have p_implies_uv : p → u = v := fun hp =&amp;gt;&lt;br /&gt;
    have hpred : U = V :=&lt;br /&gt;
      funext fun _ =&amp;gt; propext ⟨fun _ =&amp;gt; Or.inr hp, fun _ =&amp;gt; Or.inr hp⟩&lt;br /&gt;
    have h₀ : ∀ exU exV, @choose _ U exU = @choose _ V exV := by&lt;br /&gt;
      rw [hpred]; intros; rfl&lt;br /&gt;
    h₀ _ _&lt;br /&gt;
  match not_uv_or_p with&lt;br /&gt;
  | Or.inl hne =&amp;gt; Or.inr (mt p_implies_uv hne)&lt;br /&gt;
  | Or.inr h =&amp;gt; Or.inl h&lt;br /&gt;
&lt;br /&gt;
#print axioms em&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The last line prints &amp;lt;code&amp;gt;&#039;em&#039;&#039; depends on axioms: [propext, Classical.choice, Quot.sound]&amp;lt;/code&amp;gt;.&lt;br /&gt;
The step &amp;lt;code&amp;gt;h₀&amp;lt;/code&amp;gt; is where the choice function is shown to respect equality of&lt;br /&gt;
predicates. After rewriting &amp;lt;code&amp;gt;U&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;V&amp;lt;/code&amp;gt;, the two sides are&lt;br /&gt;
&amp;lt;code&amp;gt;choose&amp;lt;/code&amp;gt; applied to the same predicate and to two proofs of the same&lt;br /&gt;
proposition, and &amp;lt;code&amp;gt;rfl&amp;lt;/code&amp;gt; closes the goal because those proofs are definitionally&lt;br /&gt;
equal.&lt;br /&gt;
&lt;br /&gt;
== Where the strength comes from ==&lt;br /&gt;
&lt;br /&gt;
The essential ingredient is not choice alone but choice combined with extensionality.&lt;br /&gt;
Constructive systems such as Bishop&#039;s constructive analysis and Martin-Löf&#039;s type theory&lt;br /&gt;
affirm a form of the axiom of choice, the statement that&lt;br /&gt;
&amp;lt;math&amp;gt;\forall x\, \exists y\, \phi(x,y)&amp;lt;/math&amp;gt; gives a function &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; with&lt;br /&gt;
&amp;lt;math&amp;gt;\forall x\, \phi(x, f(x))&amp;lt;/math&amp;gt;, without affirming excluded middle. Bell&#039;s survey&lt;br /&gt;
explains why there is no conflict. On a constructive reading that choice principle follows&lt;br /&gt;
from what existence means. The derivation of excluded middle needs more: besides choice, it&lt;br /&gt;
uses a comprehension principle and the extensionality of functions on predicates, so a&lt;br /&gt;
constructive system that affirms choice but not excluded middle must give up one of the two;&lt;br /&gt;
Bell finds a constructive justification for comprehension but none for extensionality.&amp;lt;ref name=&amp;quot;sep&amp;quot;&amp;gt;John L. Bell, &amp;quot;The Axiom of Choice&amp;quot;, &#039;&#039;Stanford Encyclopedia of Philosophy&#039;&#039;, substantive revision of 10 December 2021, §5 &amp;quot;The Axiom of Choice and Logic&amp;quot; and note 15. https://plato.stanford.edu/entries/axiom-choice/&amp;lt;/ref&amp;gt; Lean asserts both. Its &amp;lt;code&amp;gt;Classical.choice&amp;lt;/code&amp;gt; is a single&lt;br /&gt;
global choice function on all inhabited types, and &amp;lt;code&amp;gt;propext&amp;lt;/code&amp;gt; with&lt;br /&gt;
&amp;lt;code&amp;gt;funext&amp;lt;/code&amp;gt; makes it extensional. Once a choice function must give equal answers on&lt;br /&gt;
equivalent predicates, it can be made to decide &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Diaconescu first derived excluded middle from the axiom of choice, in 1975, in a&lt;br /&gt;
category-theoretic setting.&amp;lt;ref name=&amp;quot;diaconescu&amp;quot;&amp;gt;Radu Diaconescu, &amp;quot;Axiom of choice and complementation&amp;quot;, &#039;&#039;Proceedings of the American Mathematical Society&#039;&#039; 51 (1975), 176–178. https://doi.org/10.1090/S0002-9939-1975-0373893-X&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;sep&amp;quot; /&amp;gt; Goodman and Myhill&#039;s&lt;br /&gt;
note of 1978 is titled &amp;quot;Choice implies excluded middle&amp;quot;.&amp;lt;ref name=&amp;quot;goodman-myhill&amp;quot;&amp;gt;Nicolas D. Goodman and John Myhill, &amp;quot;Choice implies excluded middle&amp;quot;, &#039;&#039;Zeitschrift für mathematische Logik und Grundlagen der Mathematik&#039;&#039; 24 (1978), 461. https://doi.org/10.1002/malq.19780242514&amp;lt;/ref&amp;gt; Bell&lt;br /&gt;
traces the idea of the proof presented above, with two predicates and an extensional choice function,&lt;br /&gt;
to Goodman and Myhill, whose note built on Diaconescu&#039;s result.&amp;lt;ref name=&amp;quot;sep&amp;quot; /&amp;gt; Lean&#039;s documentation names the theorem after&lt;br /&gt;
Diaconescu.&amp;lt;ref name=&amp;quot;classical&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Decidable and propDecidable ==&lt;br /&gt;
&lt;br /&gt;
The disjunction &amp;lt;code&amp;gt;p ∨ ¬p&amp;lt;/code&amp;gt; is a proposition, and an inductive proposition with two&lt;br /&gt;
constructors can be eliminated only into propositions. A program therefore cannot branch on it. For&lt;br /&gt;
branching Lean uses a different type, &amp;lt;code&amp;gt;Decidable p&amp;lt;/code&amp;gt;, whose two constructors carry&lt;br /&gt;
the same information as the two disjuncts but which lives in &amp;lt;code&amp;gt;Type&amp;lt;/code&amp;gt;:&amp;lt;ref name=&amp;quot;tpil&amp;quot;&amp;gt;Jeremy Avigad, Leonardo de Moura, Soonho Kong and Sebastian Ullrich, &#039;&#039;Theorem Proving in Lean 4&#039;&#039;, chapter 12 &amp;quot;Axioms and Computation&amp;quot;, the introduction, §12.5 &amp;quot;Choice&amp;quot; and §12.6 &amp;quot;The Law of the Excluded Middle&amp;quot;. https://lean-lang.org/theorem_proving_in_lean4/Axioms-and-Computation/&amp;lt;/ref&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;
#print Decidable&lt;br /&gt;
#check @Classical.propDecidable&lt;br /&gt;
#eval decide (2 &amp;amp;lt; 3)&lt;br /&gt;
example : decide (2 &amp;amp;lt; 3) = true := rfl&lt;br /&gt;
&amp;lt;/pre&amp;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;
inductive Decidable : Prop → Type&lt;br /&gt;
number of parameters: 1&lt;br /&gt;
constructors:&lt;br /&gt;
Decidable.isFalse : {p : Prop} → ¬p → Decidable p&lt;br /&gt;
Decidable.isTrue : {p : Prop} → p → Decidable p&lt;br /&gt;
Classical.propDecidable : (a : Prop) → Decidable a&lt;br /&gt;
true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; expression asks for a &amp;lt;code&amp;gt;Decidable&amp;lt;/code&amp;gt; instance of its condition.&lt;br /&gt;
For &amp;lt;code&amp;gt;2 &amp;amp;lt; 3&amp;lt;/code&amp;gt; the instance is an algorithm on natural numbers, so&lt;br /&gt;
&amp;lt;code&amp;gt;decide (2 &amp;amp;lt; 3)&amp;lt;/code&amp;gt; evaluates to &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;, both in compiled code and by&lt;br /&gt;
&amp;lt;code&amp;gt;rfl&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Classical.propDecidable&amp;lt;/code&amp;gt; supplies an instance for every&lt;br /&gt;
proposition. It is defined by applying &amp;lt;code&amp;gt;Classical.choice&amp;lt;/code&amp;gt; to the fact, given by&lt;br /&gt;
&amp;lt;code&amp;gt;Classical.em&amp;lt;/code&amp;gt;, that &amp;lt;code&amp;gt;Decidable a&amp;lt;/code&amp;gt; is inhabited. It is a scoped&lt;br /&gt;
instance of low priority, active only after &amp;lt;code&amp;gt;open Classical&amp;lt;/code&amp;gt;, so that where an&lt;br /&gt;
ordinary instance also applies, the ordinary one is tried first.&amp;lt;ref name=&amp;quot;classical&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Noncomputable definitions ==&lt;br /&gt;
&lt;br /&gt;
A definition that uses the classical instance to produce data cannot be compiled, and Lean&lt;br /&gt;
requires it to say so:&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;
open Classical in&lt;br /&gt;
noncomputable def classify (p : Prop) : Bool := if p then true else false&lt;br /&gt;
&lt;br /&gt;
theorem classify_true : classify True = true := by&lt;br /&gt;
  simp [classify]&lt;br /&gt;
&lt;br /&gt;
#print axioms classify&lt;br /&gt;
#print axioms classify_true&lt;br /&gt;
#reduce classify True&lt;br /&gt;
&amp;lt;/pre&amp;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;
&#039;classify&#039; depends on axioms: [propext, Classical.choice, Quot.sound]&lt;br /&gt;
&#039;classify_true&#039; depends on axioms: [propext, Classical.choice, Quot.sound]&lt;br /&gt;
Decidable.rec (fun h =&amp;gt; false) (fun h =&amp;gt; true) (Classical.choice ⋯)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Without the marker the same definition is refused:&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;
open Classical in&lt;br /&gt;
def classify&#039; (p : Prop) : Bool := if p then true else false&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean reports: &amp;lt;code&amp;gt;failed to compile definition, consider marking it as &#039;noncomputable&#039;&lt;br /&gt;
because it depends on &#039;propDecidable&#039;, which is &#039;noncomputable&#039;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== What is lost ==&lt;br /&gt;
&lt;br /&gt;
Three things are lost when data is obtained from choice, and one is kept.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Evaluation.&#039;&#039;&#039; &amp;lt;code&amp;gt;#reduce classify True&amp;lt;/code&amp;gt; stops at&lt;br /&gt;
&amp;lt;code&amp;gt;Classical.choice&amp;lt;/code&amp;gt;, an axiom with nothing to unfold. The term is a closed&lt;br /&gt;
&amp;lt;code&amp;gt;Bool&amp;lt;/code&amp;gt; that is neither &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt; by computation,&lt;br /&gt;
although &amp;lt;code&amp;gt;classify_true&amp;lt;/code&amp;gt; proves that it equals &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;. &#039;&#039;Theorem Proving in Lean 4&#039;&#039; describes a&lt;br /&gt;
&amp;quot;computationally pure&amp;quot; fragment of Lean in which every closed term of type&lt;br /&gt;
&amp;lt;code&amp;gt;Nat&amp;lt;/code&amp;gt; reduces to a numeral; a definition that uses choice for data lies outside&lt;br /&gt;
it.&amp;lt;ref name=&amp;quot;tpil&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Compilation.&#039;&#039;&#039; There is no code to generate for an axiom, so such a definition cannot&lt;br /&gt;
be run, as the refusal above shows.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Information.&#039;&#039;&#039; A classical existence proof does not say how to find the object, and a&lt;br /&gt;
function defined with &amp;lt;code&amp;gt;Classical.choose&amp;lt;/code&amp;gt; does not say which object it picked.&lt;br /&gt;
&#039;&#039;Theorem Proving in Lean 4&#039;&#039; illustrates this with a left inverse of an injective function:&lt;br /&gt;
a function from a classical point of view, unacceptable from a constructive one, since&lt;br /&gt;
there is in general no way to implement it.&amp;lt;ref name=&amp;quot;tpil&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;What is kept&#039;&#039;&#039; is classical reasoning in proofs. Proofs are erased when Lean compiles a&lt;br /&gt;
definition, so excluded middle, proof by contradiction and the other classical principles&lt;br /&gt;
may be used freely to establish properties of programs that themselves compute.&lt;br /&gt;
&#039;&#039;Theorem Proving in Lean 4&#039;&#039; puts the line exactly there: classical principles are&lt;br /&gt;
compatible with code generation so long as they are not used to manufacture data.&amp;lt;ref name=&amp;quot;tpil&amp;quot; /&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;noncomputable&amp;lt;/code&amp;gt; marker, not the axiom list, shows on which side of the line a&lt;br /&gt;
definition falls: a theorem proved with excluded middle lists &amp;lt;code&amp;gt;Classical.choice&amp;lt;/code&amp;gt;&lt;br /&gt;
among its axioms, yet the programs it is about still run.&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/Foundations/Proof irrelevance and subsingleton elimination|Proof irrelevance and subsingleton elimination]]&lt;br /&gt;
explains why a proof of &amp;lt;code&amp;gt;p ∨ ¬p&amp;lt;/code&amp;gt; cannot be used to branch, while a proof of an&lt;br /&gt;
equation can be used to cast.&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>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/Foundations/The_three_axioms&amp;diff=6782</id>
		<title>Lean theorem prover/Foundations/The three axioms</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Foundations/The_three_axioms&amp;diff=6782"/>
		<updated>2026-10-15T19:34:58Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:The three axioms}}&lt;br /&gt;
{{Plebeian|Lean theorem prover/Explainers/What the axioms are}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
&lt;br /&gt;
Lean&#039;s type theory, with its dependent functions, universes, inductive types and quotients,&lt;br /&gt;
is extended in the core library by three &#039;&#039;&#039;axioms&#039;&#039;&#039;: propositional extensionality&lt;br /&gt;
(&amp;lt;code&amp;gt;propext&amp;lt;/code&amp;gt;), the soundness of quotients (&amp;lt;code&amp;gt;Quot.sound&amp;lt;/code&amp;gt;) and global&lt;br /&gt;
choice (&amp;lt;code&amp;gt;Classical.choice&amp;lt;/code&amp;gt;). An axiom is a constant with a type and no&lt;br /&gt;
definition; it does not reduce, and the compiler cannot generate code for it.&amp;lt;ref name=&amp;quot;refman-axioms&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, version 4.34.0, chapter 8 &amp;quot;Axioms&amp;quot;: the introduction, §8.2 &amp;quot;Consistency&amp;quot;, §8.3 &amp;quot;Reduction&amp;quot;, §8.4 &amp;quot;Standard Axioms&amp;quot; and §8.5 &amp;quot;Displaying Axiom Dependencies&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/Axioms/&amp;lt;/ref&amp;gt; Lean records, for every&lt;br /&gt;
definition and theorem, which axioms it depends on, and prints the list on request. This&lt;br /&gt;
page states the three as Lean prints them, says what each makes possible, shows the&lt;br /&gt;
dependency audit on examples, and sets out the further axioms that are not mathematics at&lt;br /&gt;
all.&lt;br /&gt;
&lt;br /&gt;
== As Lean prints 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;
#print propext&lt;br /&gt;
#print Quot.sound&lt;br /&gt;
#print Classical.choice&lt;br /&gt;
&amp;lt;/pre&amp;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;
axiom propext : ∀ {a b : Prop}, (a ↔ b) → a = b&lt;br /&gt;
axiom Quot.sound.{u} : ∀ {α : Sort u} {r : α → α → Prop} {a b : α}, r a b → Quot.mk r a = Quot.mk r b&lt;br /&gt;
axiom Classical.choice.{u} : {α : Sort u} → Nonempty α → α&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In Lean 4.34.1 &amp;lt;code&amp;gt;propext&amp;lt;/code&amp;gt; is stated in the file &amp;lt;code&amp;gt;Init/Core.lean&amp;lt;/code&amp;gt;, and&lt;br /&gt;
the other two in &amp;lt;code&amp;gt;Init/Prelude.lean&amp;lt;/code&amp;gt;.&amp;lt;ref name=&amp;quot;src&amp;quot;&amp;gt;Lean 4 source, version 4.34.1: files &amp;lt;code&amp;gt;src/Init/Core.lean&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;propext&amp;lt;/code&amp;gt;), &amp;lt;code&amp;gt;src/Init/Prelude.lean&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;Quot.sound&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Classical.choice&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;sorryAx&amp;lt;/code&amp;gt;) and &amp;lt;code&amp;gt;src/Init/Classical.lean&amp;lt;/code&amp;gt; (the proof of &amp;lt;code&amp;gt;Classical.em&amp;lt;/code&amp;gt;). Apache License 2.0. https://github.com/leanprover/lean4/tree/v4.34.1/src/Init&amp;lt;/ref&amp;gt; As rules, with&lt;br /&gt;
&amp;lt;math&amp;gt;a, b : \mathrm{Prop}&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{\Gamma \vdash h : a \leftrightarrow b}{\Gamma \vdash \mathrm{propext}\,h : a = b} \qquad \frac{\Gamma \vdash p : r\,a\,b}{\Gamma \vdash \mathrm{Quot.sound}\,p : \mathrm{Quot.mk}\,r\,a = \mathrm{Quot.mk}\,r\,b} \qquad \frac{\Gamma \vdash h : \mathrm{Nonempty}\,\alpha}{\Gamma \vdash \mathrm{Classical.choice}\,h : \alpha}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first two conclude equations, which are propositions. The third concludes an element of&lt;br /&gt;
an arbitrary type. That difference decides how each one interacts with computation.&lt;br /&gt;
&lt;br /&gt;
== What each makes possible ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Propositional extensionality&#039;&#039;&#039; says that logically equivalent propositions are equal,&lt;br /&gt;
so that one may be replaced by the other in any context. The reference manual notes that&lt;br /&gt;
the ordinary connectives respect logical equivalence provably, without the axiom, but that&lt;br /&gt;
it is needed for an unknown predicate &amp;lt;code&amp;gt;P : Prop → Prop&amp;lt;/code&amp;gt; applied to equivalent&lt;br /&gt;
arguments, and for equality between propositions itself.&amp;lt;ref name=&amp;quot;refman-props&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, version 4.34.0, §4.2 &amp;quot;Propositions&amp;quot; (the axiom &amp;lt;code&amp;gt;propext&amp;lt;/code&amp;gt; and its documentation). https://lean-lang.org/doc/reference/4.34.0/The-Type-System/Propositions/&amp;lt;/ref&amp;gt; It is&lt;br /&gt;
valid intuitionistically.&amp;lt;ref name=&amp;quot;refman-props&amp;quot; /&amp;gt; &#039;&#039;Theorem Proving in Lean 4&#039;&#039; adds that&lt;br /&gt;
it agrees with set-theoretic readings in which every proposition is either empty or a&lt;br /&gt;
one-element set.&amp;lt;ref name=&amp;quot;tpil&amp;quot;&amp;gt;Jeremy Avigad, Leonardo de Moura, Soonho Kong and Sebastian Ullrich, &#039;&#039;Theorem Proving in Lean 4&#039;&#039;, chapter 12 &amp;quot;Axioms and Computation&amp;quot;. https://lean-lang.org/theorem_proving_in_lean4/Axioms-and-Computation/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Quotient soundness&#039;&#039;&#039; identifies the classes of related elements in a&lt;br /&gt;
[[Lean theorem prover/Foundations/Quotient types|quotient type]]. It is also the only&lt;br /&gt;
axiom behind function extensionality, which Lean proves as a theorem from quotients; the&lt;br /&gt;
proof is on [[Lean theorem prover/Foundations/Propositional equality|propositional equality]]. With &amp;lt;code&amp;gt;propext&amp;lt;/code&amp;gt; it gives an extensional theory of sets represented as&lt;br /&gt;
predicates: two predicates true of the same elements are equal.&amp;lt;ref name=&amp;quot;tpil&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Global choice&#039;&#039;&#039; turns a proof that a type is inhabited into an element of it.&lt;br /&gt;
&amp;lt;code&amp;gt;Nonempty α&amp;lt;/code&amp;gt; is a proposition, and a proof of it carries no information about&lt;br /&gt;
which element exists. &amp;lt;code&amp;gt;Classical.choice&amp;lt;/code&amp;gt; nevertheless returns one, and returns the&lt;br /&gt;
same one for any proof, since all proofs of a proposition are equal. &#039;&#039;Theorem Proving in&lt;br /&gt;
Lean 4&#039;&#039; derives from it the principle of indefinite description, and, with the other two&lt;br /&gt;
axioms, excluded middle, the decidability of every proposition and Hilbert&#039;s epsilon&lt;br /&gt;
operator.&amp;lt;ref name=&amp;quot;tpil&amp;quot; /&amp;gt; That derivation is&lt;br /&gt;
[[Lean theorem prover/Foundations/Classical logic from choice|classical logic from choice]].&lt;br /&gt;
&lt;br /&gt;
The first two can block evaluation in Lean&#039;s kernel, because a cast along an equation proved by&lt;br /&gt;
an axiom does not reduce, but they are compatible with compiled code, which erases proofs.&lt;br /&gt;
Choice is not: it manufactures data from a proposition, and definitions that use it for data&lt;br /&gt;
must be marked &amp;lt;code&amp;gt;noncomputable&amp;lt;/code&amp;gt;.&amp;lt;ref name=&amp;quot;tpil&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The audit: #print axioms ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;#print axioms&amp;lt;/code&amp;gt; lists every axiom a constant depends on, directly or through the&lt;br /&gt;
definitions and theorems it uses.&amp;lt;ref name=&amp;quot;refman-axioms&amp;quot; /&amp;gt; Five small theorems show&lt;br /&gt;
the range from none to all three:&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;
theorem two_add_two : 2 + 2 = 4 := rfl&lt;br /&gt;
&lt;br /&gt;
theorem and_swap (p q : Prop) : p ∧ q ↔ q ∧ p :=&lt;br /&gt;
  ⟨fun ⟨hp, hq⟩ =&amp;gt; ⟨hq, hp⟩, fun ⟨hq, hp⟩ =&amp;gt; ⟨hp, hq⟩⟩&lt;br /&gt;
&lt;br /&gt;
theorem and_swap_eq (p q : Prop) : (p ∧ q) = (q ∧ p) :=&lt;br /&gt;
  propext (and_swap p q)&lt;br /&gt;
&lt;br /&gt;
theorem add_zero_fun : (fun n : Nat =&amp;gt; n + 0) = (fun n =&amp;gt; n) :=&lt;br /&gt;
  funext fun _ =&amp;gt; rfl&lt;br /&gt;
&lt;br /&gt;
theorem em&#039; (p : Prop) : p ∨ ¬p := Classical.em p&lt;br /&gt;
&lt;br /&gt;
#print axioms two_add_two&lt;br /&gt;
#print axioms and_swap&lt;br /&gt;
#print axioms and_swap_eq&lt;br /&gt;
#print axioms add_zero_fun&lt;br /&gt;
#print axioms em&#039;&lt;br /&gt;
&amp;lt;/pre&amp;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;
&#039;two_add_two&#039; does not depend on any axioms&lt;br /&gt;
&#039;and_swap&#039; does not depend on any axioms&lt;br /&gt;
&#039;and_swap_eq&#039; depends on axioms: [propext]&lt;br /&gt;
&#039;add_zero_fun&#039; depends on axioms: [Quot.sound]&lt;br /&gt;
&#039;em&#039;&#039; depends on axioms: [propext, Classical.choice, Quot.sound]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here the computation checked by &amp;lt;code&amp;gt;rfl&amp;lt;/code&amp;gt; and the logical equivalence need nothing, the&lt;br /&gt;
equation between propositions needs &amp;lt;code&amp;gt;propext&amp;lt;/code&amp;gt;, and the equation between functions&lt;br /&gt;
needs &amp;lt;code&amp;gt;Quot.sound&amp;lt;/code&amp;gt;, through &amp;lt;code&amp;gt;funext&amp;lt;/code&amp;gt;. Excluded middle needs all three,&lt;br /&gt;
because the proof of &amp;lt;code&amp;gt;Classical.em&amp;lt;/code&amp;gt; in the core library uses choice,&lt;br /&gt;
&amp;lt;code&amp;gt;propext&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;funext&amp;lt;/code&amp;gt;.&amp;lt;ref name=&amp;quot;src&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sorry and sorryAx ==&lt;br /&gt;
&lt;br /&gt;
The term &amp;lt;code&amp;gt;sorry&amp;lt;/code&amp;gt; closes any goal. It elaborates to the axiom&lt;br /&gt;
&amp;lt;code&amp;gt;sorryAx&amp;lt;/code&amp;gt;, which inhabits every type, and so it is used for unfinished work and&lt;br /&gt;
never belongs in a finished proof.&amp;lt;ref name=&amp;quot;refman-axioms&amp;quot; /&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;
#print sorryAx&lt;br /&gt;
&lt;br /&gt;
theorem unfinished : 1 = 2 := sorry&lt;br /&gt;
&lt;br /&gt;
theorem uses_unfinished : 2 = 3 := congrArg (· + 1) unfinished&lt;br /&gt;
&lt;br /&gt;
#print axioms uses_unfinished&lt;br /&gt;
&amp;lt;/pre&amp;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;
axiom sorryAx.{u} : (α : Sort u) → Bool → α&lt;br /&gt;
&#039;uses_unfinished&#039; depends on axioms: [sorryAx]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean warns once, with &amp;lt;code&amp;gt;declaration uses `sorry`&amp;lt;/code&amp;gt;, at &amp;lt;code&amp;gt;unfinished&amp;lt;/code&amp;gt;,&lt;br /&gt;
where &amp;lt;code&amp;gt;sorry&amp;lt;/code&amp;gt; is written. The&lt;br /&gt;
theorem &amp;lt;code&amp;gt;uses_unfinished&amp;lt;/code&amp;gt; raises no warning of its own, yet it proves a falsehood,&lt;br /&gt;
and only the axiom list shows why. The reference manual makes the same point about the&lt;br /&gt;
editor&#039;s check marks: they appear even when a dependency uses &amp;lt;code&amp;gt;sorry&amp;lt;/code&amp;gt;, and&lt;br /&gt;
printing the axioms is what detects it.&amp;lt;ref name=&amp;quot;refman-validating&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, version 4.34.0, &amp;quot;Validating a Lean Proof&amp;quot;, sections &amp;quot;The Blue Double Check Marks&amp;quot;, &amp;quot;Printing Axioms&amp;quot; and &amp;quot;On Lean.trustCompiler (up to Lean 4.28.0)&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/ValidatingProofs/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Axioms that are not mathematics ==&lt;br /&gt;
&lt;br /&gt;
Any user can write an axiom, and Lean accepts it. Lean cannot check that a&lt;br /&gt;
new axiom is consistent with the others.&amp;lt;ref name=&amp;quot;refman-axioms&amp;quot; /&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;
axiom everything_is_equal : ∀ (a b : Nat), a = b&lt;br /&gt;
&lt;br /&gt;
theorem one_eq_two : 1 = 2 := everything_is_equal 1 2&lt;br /&gt;
&lt;br /&gt;
#print axioms one_eq_two&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The last line prints &amp;lt;code&amp;gt;&#039;one_eq_two&#039; depends on axioms: [everything_is_equal]&amp;lt;/code&amp;gt;.&lt;br /&gt;
The theorem is checked and accepted; the audit is what exposes its premise.&lt;br /&gt;
&lt;br /&gt;
An axiom can also be harmless on its own and inconsistent with the standard three. The&lt;br /&gt;
reference manual&#039;s example is a &amp;quot;free theorem&amp;quot; of parametricity, which says that a function&lt;br /&gt;
polymorphic in the element type of a list commutes with mapping over the list. With excluded&lt;br /&gt;
middle every proposition is decidable, so a function can test whether its type argument is&lt;br /&gt;
&amp;lt;code&amp;gt;Nat&amp;lt;/code&amp;gt; and behave differently when it is. That function is not parametric, and&lt;br /&gt;
together with the free theorem it proves &amp;lt;code&amp;gt;False&amp;lt;/code&amp;gt;.&amp;lt;ref name=&amp;quot;refman-axioms&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The core library itself states three further axioms, &amp;lt;code&amp;gt;Lean.trustCompiler&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;Lean.ofReduceBool&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Lean.ofReduceNat&amp;lt;/code&amp;gt;. The reference manual&lt;br /&gt;
describes them as mathematically trivial: they mark proofs that depend on the correctness of&lt;br /&gt;
the whole compiler rather than only on Lean&#039;s small kernel.&amp;lt;ref name=&amp;quot;refman-axioms&amp;quot; /&amp;gt; The&lt;br /&gt;
tactic &amp;lt;code&amp;gt;native_decide&amp;lt;/code&amp;gt;, which settles a decidable statement by running compiled&lt;br /&gt;
code, creates a dedicated axiom for each use, stating exactly the fact the compiled code&lt;br /&gt;
asserted:&amp;lt;ref name=&amp;quot;refman-axioms&amp;quot; /&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;
theorem big : 123456 * 654321 = 80779853376 := by native_decide&lt;br /&gt;
&lt;br /&gt;
#print axioms big&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean 4.34.1 prints &amp;lt;code&amp;gt;&#039;big&#039; depends on axioms: [big._native.native_decide.ax_1_1]&amp;lt;/code&amp;gt;.&lt;br /&gt;
Such a theorem rests on the correctness of the whole compiler, not only on Lean&#039;s kernel and&lt;br /&gt;
the three axioms: each use of the tactic widens what has to be trusted.&amp;lt;ref name=&amp;quot;refman-validating&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Why audit per theorem ==&lt;br /&gt;
&lt;br /&gt;
The three standard axioms are, in the reference manual&#039;s words, &amp;quot;known to be&lt;br /&gt;
consistent&amp;quot;.&amp;lt;ref name=&amp;quot;refman-axioms&amp;quot; /&amp;gt; Carneiro&#039;s model of Lean&#039;s type theory in set&lt;br /&gt;
theory, published in 2019, covers all three axioms together;&amp;lt;ref name=&amp;quot;carneiro&amp;quot;&amp;gt;Mario Carneiro, &#039;&#039;The Type Theory of Lean&#039;&#039;, Master&#039;s thesis, Carnegie Mellon University, 2019; abstract, §2.7 (pp. 12–13) and Corollary 6.8 (p. 41). https://github.com/digama0/lean-type-theory/releases/tag/v1.0&amp;lt;/ref&amp;gt; it is described, with its limits, in&lt;br /&gt;
[[Lean theorem prover/Foundations/Consistency and the metatheory|consistency and the metatheory]].&lt;br /&gt;
Every other axiom is a premise the reader has to accept separately. The manual&#039;s guide to&lt;br /&gt;
validating a proof therefore asks that &amp;lt;code&amp;gt;#print axioms&amp;lt;/code&amp;gt; report only&lt;br /&gt;
&amp;lt;code&amp;gt;propext&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Classical.choice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Quot.sound&amp;lt;/code&amp;gt;: a&lt;br /&gt;
&amp;lt;code&amp;gt;sorryAx&amp;lt;/code&amp;gt; means an incomplete proof, &amp;lt;code&amp;gt;Lean.trustCompiler&amp;lt;/code&amp;gt; means trust in&lt;br /&gt;
native evaluation, and anything else means a custom axiom on which the result is&lt;br /&gt;
conditional.&amp;lt;ref name=&amp;quot;refman-validating&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A list of axioms also says what kind of result a theorem is. A theorem whose list omits&lt;br /&gt;
&amp;lt;code&amp;gt;Classical.choice&amp;lt;/code&amp;gt; uses no classical reasoning obtained from it, and one with an&lt;br /&gt;
empty list holds in the type theory alone. The check can be made permanent. The manual suggests pairing &amp;lt;code&amp;gt;#print axioms&amp;lt;/code&amp;gt; with&lt;br /&gt;
&amp;lt;code&amp;gt;#guard_msgs&amp;lt;/code&amp;gt;, so that a change in a library one depends on cannot silently add&lt;br /&gt;
an axiom:&amp;lt;ref name=&amp;quot;refman-axioms&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;
/-- info: &#039;two_add_two&#039; does not depend on any axioms -/&lt;br /&gt;
#guard_msgs in&lt;br /&gt;
#print axioms two_add_two&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the proof of &amp;lt;code&amp;gt;two_add_two&amp;lt;/code&amp;gt; ever came to depend on an axiom, the message would&lt;br /&gt;
change, and this command would fail.&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/Foundations/Classical logic from choice|Classical logic from choice]]&lt;br /&gt;
follows the third axiom into excluded middle.&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>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/Foundations/Quotient_types&amp;diff=6781</id>
		<title>Lean theorem prover/Foundations/Quotient types</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Foundations/Quotient_types&amp;diff=6781"/>
		<updated>2026-10-15T19:34:56Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Quotient types}}&lt;br /&gt;
{{Plebeian|Lean theorem prover/Explainers/What the axioms are}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;quotient type&#039;&#039;&#039; is a type whose elements are those of an existing type, with every&lt;br /&gt;
pair related by a given relation made equal. Mathematics constructs such objects constantly:&lt;br /&gt;
the integers modulo &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, rational numbers as fractions up to cancellation, finite&lt;br /&gt;
sets as lists up to order and repetition. Lean provides quotients as a primitive of its type theory: four&lt;br /&gt;
constants, one axiom and one computation rule. This page sets out those rules, the&lt;br /&gt;
&amp;lt;code&amp;gt;Setoid&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Quotient&amp;lt;/code&amp;gt; layer built on them, a worked example, and&lt;br /&gt;
what the computation rule buys.&lt;br /&gt;
&lt;br /&gt;
== The primitives ==&lt;br /&gt;
&lt;br /&gt;
The constants are introduced early in Lean&#039;s core library by a dedicated command,&lt;br /&gt;
&amp;lt;code&amp;gt;init_quot&amp;lt;/code&amp;gt;, not by an inductive definition.&amp;lt;ref name=&amp;quot;prelude&amp;quot;&amp;gt;Lean 4 source, file &amp;lt;code&amp;gt;src/Init/Prelude.lean&amp;lt;/code&amp;gt;, version 4.34.1: the &amp;lt;code&amp;gt;init_quot&amp;lt;/code&amp;gt; command and the documentation of &amp;lt;code&amp;gt;Quot&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Quot.mk&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Quot.lift&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Quot.ind&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Quot.sound&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Quot.lcInv&amp;lt;/code&amp;gt;. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Init/Prelude.lean&amp;lt;/ref&amp;gt; Lean prints&lt;br /&gt;
them so:&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 Quot&lt;br /&gt;
#check @Quot.mk&lt;br /&gt;
#check @Quot.lift&lt;br /&gt;
#check @Quot.ind&lt;br /&gt;
#check @Quot.sound&lt;br /&gt;
&amp;lt;/pre&amp;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;
Quotient primitive Quot.{u} : {α : Sort u} → (α → α → Prop) → Sort u&lt;br /&gt;
@Quot.mk : {α : Sort u_1} → (r : α → α → Prop) → α → Quot r&lt;br /&gt;
@Quot.lift : {α : Sort u_1} →&lt;br /&gt;
  {r : α → α → Prop} → {β : Sort u_2} → (f : α → β) → (∀ (a b : α), r a b → f a = f b) → Quot r → β&lt;br /&gt;
@Quot.ind : ∀ {α : Sort u_1} {r : α → α → Prop} {β : Quot r → Prop}, (∀ (a : α), β (Quot.mk r a)) → ∀ (q : Quot r), β q&lt;br /&gt;
@Quot.sound : ∀ {α : Sort u_1} {r : α → α → Prop} {a b : α}, r a b → Quot.mk r a = Quot.mk r b&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As rules: for any relation &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt; on &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; there is a type, and every&lt;br /&gt;
element of &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; gives an element of it,&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{\Gamma \vdash A : \mathrm{Sort}\,u \quad \Gamma \vdash r : A \to A \to \mathrm{Prop}}{\Gamma \vdash \mathrm{Quot}\,r : \mathrm{Sort}\,u} \qquad \frac{\Gamma \vdash a : A}{\Gamma \vdash \mathrm{Quot.mk}\,r\,a : \mathrm{Quot}\,r}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A function out of the quotient is a function out of &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; together with a proof&lt;br /&gt;
that it respects &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{\Gamma \vdash f : A \to B \quad \Gamma \vdash h : \Pi (a\,b : A).\, r\,a\,b \to f\,a = f\,b}{\Gamma \vdash \mathrm{Quot.lift}\,f\,h : \mathrm{Quot}\,r \to B}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and it computes on representatives:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\mathrm{Quot.lift}\,f\,h\,(\mathrm{Quot.mk}\,r\,a) \equiv f\,a&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The induction principle &amp;lt;code&amp;gt;Quot.ind&amp;lt;/code&amp;gt; says that, for proving a proposition, every&lt;br /&gt;
element may be taken to be some &amp;lt;code&amp;gt;Quot.mk r a&amp;lt;/code&amp;gt;. Finally the axiom identifies&lt;br /&gt;
related representatives:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{\Gamma \vdash p : r\,a\,b}{\Gamma \vdash \mathrm{Quot.sound}\,p : \mathrm{Quot.mk}\,r\,a = \mathrm{Quot.mk}\,r\,b}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Only &amp;lt;code&amp;gt;Quot.sound&amp;lt;/code&amp;gt; is an axiom in any real sense.&#039;&#039;&#039; Carneiro observes that&lt;br /&gt;
&amp;lt;code&amp;gt;Quot&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Quot.mk&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Quot.lift&amp;lt;/code&amp;gt; and the computation rule are all&lt;br /&gt;
satisfied by reading the quotient as &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; itself, &amp;lt;code&amp;gt;Quot.mk&amp;lt;/code&amp;gt; as the&lt;br /&gt;
identity and &amp;lt;code&amp;gt;Quot.lift f h&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt;; &#039;&#039;Theorem Proving in Lean 4&#039;&#039; notes&lt;br /&gt;
that &amp;lt;code&amp;gt;Quot.ind&amp;lt;/code&amp;gt; holds under the same reading.&amp;lt;ref name=&amp;quot;tpil&amp;quot; /&amp;gt; What that reading cannot satisfy is the identification of distinct&lt;br /&gt;
representatives. Because the computation rule is a reduction and not a constant, Carneiro calls&lt;br /&gt;
quotients a semi-built-in feature: Lean&#039;s kernel has to know about them, and they are&lt;br /&gt;
switched on as a whole.&amp;lt;ref name=&amp;quot;carneiro&amp;quot;&amp;gt;Mario Carneiro, &#039;&#039;The Type Theory of Lean&#039;&#039;, Master&#039;s thesis, Carnegie Mellon University, 2019; §2.7.1 (p. 13), §2.8 (p. 15) and §3.1.1 (p. 17). https://github.com/digama0/lean-type-theory/releases/tag/v1.0&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The relation need not be an equivalence relation. The rules for &amp;lt;code&amp;gt;Quot&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;Eq&amp;lt;/code&amp;gt; together make equality in &amp;lt;code&amp;gt;Quot r&amp;lt;/code&amp;gt; the equivalence relation&lt;br /&gt;
generated by &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt;.&amp;lt;ref name=&amp;quot;refman-quot&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, version 4.34.0, §4.5 &amp;quot;Quotients&amp;quot;: the introduction, §4.5.5 &amp;quot;Logical Model&amp;quot;, §4.5.5.2 &amp;quot;Quotients and Inductive Types&amp;quot;, §4.5.6 &amp;quot;Quotients and Function Extensionality&amp;quot; and §4.5.7 &amp;quot;Squash Types&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/The-Type-System/Quotients/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== An example: unordered pairs ==&lt;br /&gt;
&lt;br /&gt;
An unordered pair is an ordered pair taken up to swapping its components. The relation&lt;br /&gt;
below holds when one pair is the other reversed. It is symmetric but not reflexive, and&lt;br /&gt;
&amp;lt;code&amp;gt;Quot&amp;lt;/code&amp;gt; does not mind.&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;
/-- `p` and `q` are related when `q` is `p` with its components swapped. -/&lt;br /&gt;
def Swapped (α : Type) (p q : α × α) : Prop := p.1 = q.2 ∧ p.2 = q.1&lt;br /&gt;
&lt;br /&gt;
def UPair (α : Type) : Type := Quot (Swapped α)&lt;br /&gt;
&lt;br /&gt;
def UPair.mk {α : Type} (a b : α) : UPair α := Quot.mk (Swapped α) (a, b)&lt;br /&gt;
&lt;br /&gt;
theorem UPair.mk_comm {α : Type} (a b : α) : UPair.mk a b = UPair.mk b a :=&lt;br /&gt;
  Quot.sound ⟨rfl, rfl⟩&lt;br /&gt;
&lt;br /&gt;
def UPair.sum (u : UPair Nat) : Nat :=&lt;br /&gt;
  Quot.lift (fun p =&amp;gt; p.1 + p.2)&lt;br /&gt;
    (fun p q (h : Swapped Nat p q) =&amp;gt; by rw [h.1, h.2, Nat.add_comm])&lt;br /&gt;
    u&lt;br /&gt;
&lt;br /&gt;
example : UPair.sum (UPair.mk 3 4) = 7 := rfl&lt;br /&gt;
#eval UPair.sum (UPair.mk 3 4)&lt;br /&gt;
&lt;br /&gt;
theorem UPair.sum_pos (u : UPair Nat) (h : ∀ a b, UPair.mk a b = u → 0 &amp;amp;lt; a) :&lt;br /&gt;
    0 &amp;amp;lt; UPair.sum u := by&lt;br /&gt;
  induction u using Quot.ind with&lt;br /&gt;
  | mk p =&amp;gt; exact Nat.lt_of_lt_of_le (h p.1 p.2 rfl) (Nat.le_add_right _ _)&lt;br /&gt;
&lt;br /&gt;
#print axioms UPair.mk_comm&lt;br /&gt;
#print axioms UPair.sum&lt;br /&gt;
#print axioms UPair.sum_pos&lt;br /&gt;
&amp;lt;/pre&amp;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;
7&lt;br /&gt;
&#039;UPair.mk_comm&#039; depends on axioms: [Quot.sound]&lt;br /&gt;
&#039;UPair.sum&#039; does not depend on any axioms&lt;br /&gt;
&#039;UPair.sum_pos&#039; does not depend on any axioms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each primitive has its part. &amp;lt;code&amp;gt;UPair.mk_comm&amp;lt;/code&amp;gt; is the one statement that needs the&lt;br /&gt;
axiom: it asserts that two different representatives give the same element. The sum is&lt;br /&gt;
defined by &amp;lt;code&amp;gt;Quot.lift&amp;lt;/code&amp;gt;, and the obligation it carries is the proof that swapping&lt;br /&gt;
the components does not change &amp;lt;code&amp;gt;p.1 + p.2&amp;lt;/code&amp;gt;. A function that does not respect the&lt;br /&gt;
relation, such as the first component, cannot be lifted, because no such proof exists.&lt;br /&gt;
The &amp;lt;code&amp;gt;example&amp;lt;/code&amp;gt; is closed by &amp;lt;code&amp;gt;rfl&amp;lt;/code&amp;gt;: the computation rule reduces&lt;br /&gt;
&amp;lt;code&amp;gt;UPair.sum (UPair.mk 3 4)&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;3 + 4&amp;lt;/code&amp;gt;, and then to &amp;lt;code&amp;gt;7&amp;lt;/code&amp;gt;.&lt;br /&gt;
The theorem &amp;lt;code&amp;gt;UPair.sum_pos&amp;lt;/code&amp;gt; uses &amp;lt;code&amp;gt;Quot.ind&amp;lt;/code&amp;gt; to reduce a statement about&lt;br /&gt;
every unordered pair to one about representatives. Neither the definition nor the induction&lt;br /&gt;
uses an axiom; only the identification of representatives does.&lt;br /&gt;
&lt;br /&gt;
== Setoid and Quotient ==&lt;br /&gt;
&lt;br /&gt;
When the relation is an equivalence relation, the core library bundles it as a&lt;br /&gt;
&#039;&#039;&#039;setoid&#039;&#039;&#039;: a type with a chosen relation and a proof that it is reflexive, symmetric and&lt;br /&gt;
transitive. &amp;lt;code&amp;gt;Quotient s&amp;lt;/code&amp;gt; is then &amp;lt;code&amp;gt;Quot&amp;lt;/code&amp;gt; applied to the setoid&#039;s&lt;br /&gt;
relation.&amp;lt;ref name=&amp;quot;core&amp;quot;&amp;gt;Lean 4 source, file &amp;lt;code&amp;gt;src/Init/Core.lean&amp;lt;/code&amp;gt;, version 4.34.1: the definitions of &amp;lt;code&amp;gt;Setoid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Quotient&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Quotient.exact&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;&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 Setoid&lt;br /&gt;
#print Quotient&lt;br /&gt;
&lt;br /&gt;
instance parity : Setoid Nat where&lt;br /&gt;
  r a b := a % 2 = b % 2&lt;br /&gt;
  iseqv := ⟨fun _ =&amp;gt; rfl, fun h =&amp;gt; h.symm, fun h₁ h₂ =&amp;gt; h₁.trans h₂⟩&lt;br /&gt;
&lt;br /&gt;
def Mod2 : Type := Quotient parity&lt;br /&gt;
&lt;br /&gt;
def Mod2.ofNat (n : Nat) : Mod2 := Quotient.mk parity n&lt;br /&gt;
&lt;br /&gt;
def Mod2.isOdd : Mod2 → Bool :=&lt;br /&gt;
  Quotient.lift (fun n =&amp;gt; n % 2 == 1) (fun a b (h : a % 2 = b % 2) =&amp;gt; by rw [h])&lt;br /&gt;
&lt;br /&gt;
example : Mod2.ofNat 3 = Mod2.ofNat 7 := Quotient.sound rfl&lt;br /&gt;
example : Mod2.isOdd (Mod2.ofNat 7) = true := rfl&lt;br /&gt;
&lt;br /&gt;
theorem Mod2.two_ne_three : Mod2.ofNat 2 ≠ Mod2.ofNat 3 := fun h =&amp;gt;&lt;br /&gt;
  absurd (show 2 % 2 = 3 % 2 from Quotient.exact h) (by decide)&lt;br /&gt;
&lt;br /&gt;
#print axioms Mod2.two_ne_three&lt;br /&gt;
&amp;lt;/pre&amp;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;
class Setoid.{u} (α : Sort u) : Sort (max 1 u)&lt;br /&gt;
number of parameters: 1&lt;br /&gt;
fields:&lt;br /&gt;
  Setoid.r : α → α → Prop&lt;br /&gt;
  Setoid.iseqv : Equivalence Setoid.r&lt;br /&gt;
constructor:&lt;br /&gt;
  Setoid.mk.{u} {α : Sort u} (r : α → α → Prop) (iseqv : Equivalence r) : Setoid α&lt;br /&gt;
def Quotient.{u} : {α : Sort u} → Setoid α → Sort u :=&lt;br /&gt;
fun {α} s =&amp;gt; Quot Setoid.r&lt;br /&gt;
&#039;Mod2.two_ne_three&#039; depends on axioms: [propext]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Mod2&amp;lt;/code&amp;gt; is the integers modulo 2, built from the natural numbers. Showing that&lt;br /&gt;
&amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;7&amp;lt;/code&amp;gt; have the same class is &amp;lt;code&amp;gt;Quotient.sound&amp;lt;/code&amp;gt; applied to&lt;br /&gt;
a proof that &amp;lt;code&amp;gt;3 % 2 = 7 % 2&amp;lt;/code&amp;gt;, which holds by computation. Showing that&lt;br /&gt;
&amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt; have different classes needs the converse, that equal&lt;br /&gt;
classes come from related representatives. That is &amp;lt;code&amp;gt;Quotient.exact&amp;lt;/code&amp;gt;, and it is&lt;br /&gt;
where the equivalence relation matters. Its proof lifts the relation itself to a&lt;br /&gt;
proposition-valued function on pairs of classes; the obligation is that related inputs give&lt;br /&gt;
equal propositions, which needs propositional extensionality, and reflexivity then closes&lt;br /&gt;
the argument.&amp;lt;ref name=&amp;quot;core&amp;quot; /&amp;gt; The output records it: the proof that two classes differ&lt;br /&gt;
depends on &amp;lt;code&amp;gt;propext&amp;lt;/code&amp;gt;, not on &amp;lt;code&amp;gt;Quot.sound&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== What the computation rule buys ==&lt;br /&gt;
&lt;br /&gt;
Because &amp;lt;code&amp;gt;Quot.lift&amp;lt;/code&amp;gt; reduces on &amp;lt;code&amp;gt;Quot.mk&amp;lt;/code&amp;gt;, a function defined on a&lt;br /&gt;
quotient computes. &amp;lt;code&amp;gt;rfl&amp;lt;/code&amp;gt; proves &amp;lt;code&amp;gt;UPair.sum (UPair.mk 3 4) = 7&amp;lt;/code&amp;gt;, and&lt;br /&gt;
&amp;lt;code&amp;gt;#eval&amp;lt;/code&amp;gt; runs the same function. The reference manual contrasts this with working&lt;br /&gt;
directly on sets of equivalence classes: functions out of such sets need non-computational&lt;br /&gt;
classical principles, whereas functions out of a quotient are ordinary functions that also&lt;br /&gt;
respect a relation.&amp;lt;ref name=&amp;quot;refman-quot&amp;quot; /&amp;gt; It also notes that the quotient leaves&lt;br /&gt;
definitional equality untouched: two elements of a quotient are definitionally equal exactly&lt;br /&gt;
when their representatives are.&amp;lt;ref name=&amp;quot;refman-quot&amp;quot; /&amp;gt; Elements made equal by&lt;br /&gt;
&amp;lt;code&amp;gt;Quot.sound&amp;lt;/code&amp;gt; are equal propositionally, by a proof.&lt;br /&gt;
&lt;br /&gt;
The rule is also what makes [[Lean theorem prover/Foundations/Propositional equality|function extensionality]]&lt;br /&gt;
a theorem. Quotienting a function type by pointwise equality and applying each class to an&lt;br /&gt;
argument reduces, by this rule, back to the original function. A propositional version of&lt;br /&gt;
the rule would not do, because using it under a binder would already need function&lt;br /&gt;
extensionality.&amp;lt;ref name=&amp;quot;refman-quot&amp;quot; /&amp;gt; &#039;&#039;Theorem Proving in Lean 4&#039;&#039; likewise presents&lt;br /&gt;
function extensionality as a consequence of the quotient construction.&amp;lt;ref name=&amp;quot;tpil&amp;quot;&amp;gt;Jeremy Avigad, Leonardo de Moura, Soonho Kong and Sebastian Ullrich, &#039;&#039;Theorem Proving in Lean 4&#039;&#039;, chapter 12 &amp;quot;Axioms and Computation&amp;quot;, §12.3 and §12.4. https://lean-lang.org/theorem_proving_in_lean4/Axioms-and-Computation/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The compiler erases &amp;lt;code&amp;gt;Quot.lift&amp;lt;/code&amp;gt;. The core library carries an unsafe constant,&lt;br /&gt;
&amp;lt;code&amp;gt;Quot.lcInv&amp;lt;/code&amp;gt;, documented as the device for doing so,&amp;lt;ref name=&amp;quot;prelude&amp;quot; /&amp;gt; and the&lt;br /&gt;
reference manual notes that &amp;lt;code&amp;gt;Squash α&amp;lt;/code&amp;gt;, the quotient of &amp;lt;code&amp;gt;α&amp;lt;/code&amp;gt; by the&lt;br /&gt;
relation that relates everything, is represented at run time exactly as &amp;lt;code&amp;gt;α&amp;lt;/code&amp;gt;&lt;br /&gt;
is.&amp;lt;ref name=&amp;quot;refman-quot&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Limits ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Quot&amp;lt;/code&amp;gt; is not an inductive type. In consequence, a recursive occurrence of the&lt;br /&gt;
type being defined may not appear inside a quotient in an inductive definition, as it may&lt;br /&gt;
inside a &amp;lt;code&amp;gt;List&amp;lt;/code&amp;gt;:&amp;lt;ref name=&amp;quot;refman-quot&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;
inductive SetTree (α : Type u) where&lt;br /&gt;
  | leaf : α → SetTree α&lt;br /&gt;
  | branch : Quot (fun (xs ys : List (SetTree α)) =&amp;gt; True) → SetTree α&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean rejects it with &amp;lt;code&amp;gt;(kernel) arg #2 of &#039;SetTree.branch&#039; contains a non valid occurrence&lt;br /&gt;
of the datatypes being declared&amp;lt;/code&amp;gt;. The reference manual&#039;s remedy is to define the&lt;br /&gt;
type without the nested quotient and then quotient the whole type by a relation that&lt;br /&gt;
identifies the intended trees.&amp;lt;ref name=&amp;quot;refman-quot&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Quotients are also one of the places where the checker&#039;s algorithm and the type theory part&lt;br /&gt;
company. Carneiro shows that a quotient of a proposition behaves like a subsingleton&lt;br /&gt;
eliminator, and with it gives an instance where the checker&#039;s definitional-equality test&lt;br /&gt;
is not transitive.&amp;lt;ref name=&amp;quot;carneiro&amp;quot; /&amp;gt; The page on&lt;br /&gt;
[[Lean theorem prover/Foundations/Proof irrelevance and subsingleton elimination|proof irrelevance and subsingleton elimination]]&lt;br /&gt;
treats the main case of this, which comes from the accessibility predicate.&lt;br /&gt;
&lt;br /&gt;
Other proof assistants make different choices. Carneiro noted in 2019 that Coq had no quotient&lt;br /&gt;
types with a computation rule, so that its users worked with setoids, types paired with an&lt;br /&gt;
equivalence relation that stands in for equality.&amp;lt;ref name=&amp;quot;carneiro&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/Foundations/The three axioms|The three axioms]] places&lt;br /&gt;
&amp;lt;code&amp;gt;Quot.sound&amp;lt;/code&amp;gt; beside &amp;lt;code&amp;gt;propext&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Classical.choice&amp;lt;/code&amp;gt;.&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>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/Foundations/Propositional_equality&amp;diff=6780</id>
		<title>Lean theorem prover/Foundations/Propositional equality</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Foundations/Propositional_equality&amp;diff=6780"/>
		<updated>2026-10-15T19:34:55Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Propositional equality}}&lt;br /&gt;
{{Plebeian|Lean theorem prover/Explainers/Two kinds of equality}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Propositional equality&#039;&#039;&#039; is the proposition &amp;lt;code&amp;gt;a = b&amp;lt;/code&amp;gt;. A proof of it is a term&lt;br /&gt;
of that type, built and used like any other proof. It is distinct from&lt;br /&gt;
[[Lean theorem prover/Foundations/Definitional equality|definitional equality]], which is a&lt;br /&gt;
judgment the checker tests by computation and which no term records. Lean defines&lt;br /&gt;
propositional equality as an inductive family with a single constructor. Symmetry,&lt;br /&gt;
transitivity, substitution and congruence are all derived from its eliminator. Function&lt;br /&gt;
extensionality is a theorem, proved from quotient types. Uniqueness of identity proofs&lt;br /&gt;
holds with no axiom at all.&lt;br /&gt;
&lt;br /&gt;
== Equality as an inductive family ==&lt;br /&gt;
&lt;br /&gt;
Lean&#039;s core library defines &amp;lt;code&amp;gt;Eq&amp;lt;/code&amp;gt; as an inductive type in &amp;lt;code&amp;gt;Prop&amp;lt;/code&amp;gt; with&lt;br /&gt;
one constructor, &amp;lt;code&amp;gt;Eq.refl&amp;lt;/code&amp;gt;.&amp;lt;ref name=&amp;quot;prelude&amp;quot;&amp;gt;Lean 4 source, file &amp;lt;code&amp;gt;src/Init/Prelude.lean&amp;lt;/code&amp;gt;, version 4.34.1: the definitions of &amp;lt;code&amp;gt;Eq&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HEq&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;cast&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;congrArg&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;congr&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;congrFun&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;funext&amp;lt;/code&amp;gt;, with their documentation comments. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Init/Prelude.lean&amp;lt;/ref&amp;gt; Lean prints it so:&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 Eq&lt;br /&gt;
example : 2 + 2 = 4 := rfl&lt;br /&gt;
&amp;lt;/pre&amp;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;
inductive Eq.{u_1} : {α : Sort u_1} → α → α → Prop&lt;br /&gt;
number of parameters: 2&lt;br /&gt;
constructors:&lt;br /&gt;
Eq.refl : ∀ {α : Sort u_1} (a : α), a = a&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The two parameters are the type &amp;lt;code&amp;gt;α&amp;lt;/code&amp;gt; and the left-hand side &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;. The&lt;br /&gt;
right-hand side is an &#039;&#039;&#039;index&#039;&#039;&#039;: it varies between the type and the constructor&#039;s result,&lt;br /&gt;
and the constructor fixes it to &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;. The constructor alone therefore proves only&lt;br /&gt;
statements of the form &amp;lt;code&amp;gt;a = a&amp;lt;/code&amp;gt;; every other equation needs an argument that ends&lt;br /&gt;
in one. Written as rules, formation and introduction are&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{\Gamma \vdash A : \mathrm{Sort}\,u \quad \Gamma \vdash a : A \quad \Gamma \vdash b : A}{\Gamma \vdash a = b : \mathrm{Prop}} \qquad \frac{\Gamma \vdash a : A}{\Gamma \vdash \mathrm{Eq.refl}\,a : a = a}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The term &amp;lt;code&amp;gt;rfl&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;Eq.refl&amp;lt;/code&amp;gt; with its argument left implicit. The&lt;br /&gt;
example &amp;lt;code&amp;gt;2 + 2 = 4 := rfl&amp;lt;/code&amp;gt; is accepted because the checker finds&lt;br /&gt;
&amp;lt;code&amp;gt;2 + 2&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt; definitionally equal; &amp;lt;code&amp;gt;rfl&amp;lt;/code&amp;gt; then has the&lt;br /&gt;
type the statement asks for. Every proof by &amp;lt;code&amp;gt;rfl&amp;lt;/code&amp;gt; is a definitional equality&lt;br /&gt;
packaged as a propositional one. Not every propositional equality is definitional: most&lt;br /&gt;
equations in mathematics need an argument, because no amount of computation turns one side&lt;br /&gt;
into the other.&lt;br /&gt;
&lt;br /&gt;
== The eliminator ==&lt;br /&gt;
&lt;br /&gt;
The recursor that [[Lean theorem prover/Foundations/Inductive types and recursors|every inductive type receives]]&lt;br /&gt;
is, for &amp;lt;code&amp;gt;Eq&amp;lt;/code&amp;gt;, the principle that makes equality useful.&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 pp.proofs true in&lt;br /&gt;
#check @Eq.rec&lt;br /&gt;
&amp;lt;/pre&amp;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;
@Eq.rec : {α : Sort u_2} →&lt;br /&gt;
  {a : α} → {motive : (a_1 : α) → a = a_1 → Sort u_1} → motive a (Eq.refl a) → {a_1 : α} → (t : a = a_1) → motive a_1 t&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The motive, written &amp;lt;math&amp;gt;C&amp;lt;/math&amp;gt; below, is a family over every right-hand side &amp;lt;code&amp;gt;y&amp;lt;/code&amp;gt; and every&lt;br /&gt;
proof that &amp;lt;code&amp;gt;a = y&amp;lt;/code&amp;gt;. To produce an element of &amp;lt;code&amp;gt;C b h&amp;lt;/code&amp;gt; it suffices to&lt;br /&gt;
produce one at the constructor, &amp;lt;code&amp;gt;C a (Eq.refl a)&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{\Gamma \vdash C : \Pi (y : A).\, a = y \to \mathrm{Sort}\,v \quad \Gamma \vdash c : C\,a\,(\mathrm{Eq.refl}\,a) \quad \Gamma \vdash h : a = b}{\Gamma \vdash \mathrm{Eq.rec}\,c\,h : C\,b\,h}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
with the computation rule&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\mathrm{Eq.rec}\,c\,(\mathrm{Eq.refl}\,a) \equiv c&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The motive may land in any universe, not only in &amp;lt;code&amp;gt;Prop&amp;lt;/code&amp;gt;.&#039;&#039;&#039; A proof of an&lt;br /&gt;
equation can therefore change the type of a piece of data. This is unusual for a&lt;br /&gt;
proposition: Lean permits it only because &amp;lt;code&amp;gt;Eq&amp;lt;/code&amp;gt; passes the test for subsingleton&lt;br /&gt;
elimination, which is the subject of&lt;br /&gt;
[[Lean theorem prover/Foundations/Proof irrelevance and subsingleton elimination|proof irrelevance and subsingleton elimination]].&amp;lt;ref name=&amp;quot;refman-ind&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, version 4.34.0, §4.4 &amp;quot;Inductive Types&amp;quot;, subsection &amp;quot;Subsingleton Elimination&amp;quot; (the recursor of &amp;lt;code&amp;gt;Eq&amp;lt;/code&amp;gt;). https://lean-lang.org/doc/reference/4.34.0/The-Type-System/Inductive-Types/#subsingleton-elimination&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Transport ==&lt;br /&gt;
&lt;br /&gt;
Applying the eliminator with a motive that does not depend on the proof gives&lt;br /&gt;
&#039;&#039;&#039;transport&#039;&#039;&#039;: from &amp;lt;code&amp;gt;h : a = b&amp;lt;/code&amp;gt; and a term whose type mentions &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;,&lt;br /&gt;
obtain the same term at &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt;. Lean&#039;s core library defines &amp;lt;code&amp;gt;Eq.subst&amp;lt;/code&amp;gt;&lt;br /&gt;
and &amp;lt;code&amp;gt;cast&amp;lt;/code&amp;gt; this way.&amp;lt;ref name=&amp;quot;prelude&amp;quot; /&amp;gt; The triangle &amp;lt;code&amp;gt;h ▸ e&amp;lt;/code&amp;gt; is a&lt;br /&gt;
macro over &amp;lt;code&amp;gt;Eq.rec&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Eq.symm&amp;lt;/code&amp;gt;: it tries both orientations of&lt;br /&gt;
&amp;lt;code&amp;gt;h&amp;lt;/code&amp;gt;, and rewrites the expected type when there is one, otherwise the type of&lt;br /&gt;
&amp;lt;code&amp;gt;e&amp;lt;/code&amp;gt;.&amp;lt;ref name=&amp;quot;parser&amp;quot;&amp;gt;Lean 4 source, file &amp;lt;code&amp;gt;src/Lean/Parser/Term.lean&amp;lt;/code&amp;gt;, version 4.34.1: the documentation comment of the &amp;lt;code&amp;gt;h ▸ e&amp;lt;/code&amp;gt; syntax. Apache License 2.0. https://github.com/leanprover/lean4/blob/v4.34.1/src/Lean/Parser/Term.lean&amp;lt;/ref&amp;gt; With it the familiar laws of equality are one line&lt;br /&gt;
each:&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;
theorem symm&#039; {α : Sort u} {a b : α} (h : a = b) : b = a :=&lt;br /&gt;
  h ▸ rfl&lt;br /&gt;
&lt;br /&gt;
theorem trans&#039; {α : Sort u} {a b c : α} (h₁ : a = b) (h₂ : b = c) : a = c :=&lt;br /&gt;
  h₂ ▸ h₁&lt;br /&gt;
&lt;br /&gt;
theorem subst&#039; {α : Sort u} {a b : α} (p : α → Prop) (h : a = b) (ha : p a) : p b :=&lt;br /&gt;
  h ▸ ha&lt;br /&gt;
&lt;br /&gt;
theorem congrArg&#039; {α : Sort u} {β : Sort v} {a₁ a₂ : α} (f : α → β) (h : a₁ = a₂) :&lt;br /&gt;
    f a₁ = f a₂ :=&lt;br /&gt;
  h ▸ rfl&lt;br /&gt;
&lt;br /&gt;
def castAlong {α β : Type} (h : α = β) (x : α) : β :=&lt;br /&gt;
  h ▸ x&lt;br /&gt;
&lt;br /&gt;
#print axioms trans&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The last command prints &amp;lt;code&amp;gt;&#039;trans&#039;&#039; does not depend on any axioms&amp;lt;/code&amp;gt;. Nothing beyond&lt;br /&gt;
the inductive definition is used. The definition &amp;lt;code&amp;gt;castAlong&amp;lt;/code&amp;gt; is the case that&lt;br /&gt;
needs the large motive: its result is data of type &amp;lt;code&amp;gt;β&amp;lt;/code&amp;gt;, obtained from data of&lt;br /&gt;
type &amp;lt;code&amp;gt;α&amp;lt;/code&amp;gt; by a proof that the two types are equal.&lt;br /&gt;
&lt;br /&gt;
== Congruence ==&lt;br /&gt;
&lt;br /&gt;
The theorem &amp;lt;code&amp;gt;congrArg&amp;lt;/code&amp;gt; above is the first congruence principle: equal arguments&lt;br /&gt;
give equal values. The core library adds &amp;lt;code&amp;gt;congrFun&amp;lt;/code&amp;gt; (equal functions give equal&lt;br /&gt;
values at one argument) and &amp;lt;code&amp;gt;congr&amp;lt;/code&amp;gt; (both at once), each proved by transport in&lt;br /&gt;
the same way. The library&#039;s documentation notes that tactics such as &amp;lt;code&amp;gt;congr&amp;lt;/code&amp;gt;&lt;br /&gt;
and &amp;lt;code&amp;gt;simp&amp;lt;/code&amp;gt; use &amp;lt;code&amp;gt;congrArg&amp;lt;/code&amp;gt; internally to apply equalities inside&lt;br /&gt;
subterms.&amp;lt;ref name=&amp;quot;prelude&amp;quot; /&amp;gt; &amp;lt;code&amp;gt;congrArg&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;congr&amp;lt;/code&amp;gt; are stated for non-dependent functions. When the type of the&lt;br /&gt;
result depends on the argument, &amp;lt;code&amp;gt;f a₁&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f a₂&amp;lt;/code&amp;gt; have different&lt;br /&gt;
types, and the statement &amp;lt;code&amp;gt;f a₁ = f a₂&amp;lt;/code&amp;gt; cannot even be formed. That case needs a&lt;br /&gt;
different relation.&lt;br /&gt;
&lt;br /&gt;
== Heterogeneous equality ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Heterogeneous equality&#039;&#039;&#039; relates terms whose types are not known to be definitionally&lt;br /&gt;
equal. It is a second inductive family, written &amp;lt;code&amp;gt;a ≍ b&amp;lt;/code&amp;gt; in Lean 4.34.1:&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 HEq&lt;br /&gt;
#check fun (n m : Nat) (x : Fin (n + m)) (y : Fin (m + n)) =&amp;gt; x ≍ y&lt;br /&gt;
#check @type_eq_of_heq&lt;br /&gt;
#check @eq_of_heq&lt;br /&gt;
&amp;lt;/pre&amp;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;
inductive HEq.{u} : {α : Sort u} → α → {β : Sort u} → β → Prop&lt;br /&gt;
number of parameters: 2&lt;br /&gt;
constructors:&lt;br /&gt;
HEq.refl : ∀ {α : Sort u} (a : α), a ≍ a&lt;br /&gt;
fun n m x y =&amp;gt; x ≍ y : (n m : Nat) → Fin (n + m) → Fin (m + n) → Prop&lt;br /&gt;
@type_eq_of_heq : ∀ {α β : Sort u_1} {a : α} {b : β}, a ≍ b → α = β&lt;br /&gt;
@eq_of_heq : ∀ {α : Sort u_1} {a a&#039; : α}, a ≍ a&#039; → a = a&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The statement &amp;lt;code&amp;gt;x ≍ y&amp;lt;/code&amp;gt; is well formed even though &amp;lt;code&amp;gt;Fin (n + m)&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;Fin (m + n)&amp;lt;/code&amp;gt; are equal only by a theorem about addition. The same statement&lt;br /&gt;
with &amp;lt;code&amp;gt;=&amp;lt;/code&amp;gt; is rejected:&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;
#check fun (n m : Nat) (x : Fin (n + m)) (y : Fin (m + n)) =&amp;gt; x = y&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean reports &amp;lt;code&amp;gt;Type mismatch&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;y&amp;lt;/code&amp;gt; has type &amp;lt;code&amp;gt;Fin (m + n)&amp;lt;/code&amp;gt; but&lt;br /&gt;
is expected to have type &amp;lt;code&amp;gt;Fin (n + m)&amp;lt;/code&amp;gt;. A proof of &amp;lt;code&amp;gt;x ≍ y&amp;lt;/code&amp;gt; carries a&lt;br /&gt;
proof that the types agree, which &amp;lt;code&amp;gt;type_eq_of_heq&amp;lt;/code&amp;gt; extracts, and at a single type&lt;br /&gt;
it collapses to ordinary equality by &amp;lt;code&amp;gt;eq_of_heq&amp;lt;/code&amp;gt;. The core library&#039;s own&lt;br /&gt;
documentation advises avoiding &amp;lt;code&amp;gt;HEq&amp;lt;/code&amp;gt; where possible: the analogue of&lt;br /&gt;
&amp;lt;code&amp;gt;congr&amp;lt;/code&amp;gt; fails for it, since from &amp;lt;code&amp;gt;f ≍ g&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;x ≍ y&amp;lt;/code&amp;gt; it does&lt;br /&gt;
not follow that &amp;lt;code&amp;gt;f x ≍ g y&amp;lt;/code&amp;gt;; the equality of types that &amp;lt;code&amp;gt;HEq&amp;lt;/code&amp;gt; carries is&lt;br /&gt;
often too weak.&amp;lt;ref name=&amp;quot;prelude&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Function extensionality ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Function extensionality&#039;&#039;&#039; says that functions which agree at every argument are equal.&lt;br /&gt;
The eliminator of &amp;lt;code&amp;gt;Eq&amp;lt;/code&amp;gt; offers no way to compare two lambda terms by their&lt;br /&gt;
values. The Lean reference manual notes that function extensionality would have to be an&lt;br /&gt;
axiom in Lean, were it not for quotient types, whose lifting operator has a definitional&lt;br /&gt;
computation rule.&amp;lt;ref name=&amp;quot;refman-quot&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, version 4.34.0, §4.5.6 &amp;quot;Quotients and Function Extensionality&amp;quot;. https://lean-lang.org/doc/reference/4.34.0/The-Type-System/Quotients/#quotient-funext&amp;lt;/ref&amp;gt; The proof in the&lt;br /&gt;
core library forms the quotient of the function type by pointwise equality and applies each&lt;br /&gt;
class to an argument:&amp;lt;ref name=&amp;quot;prelude&amp;quot; /&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;
theorem funext&#039; {α : Sort u} {β : α → Sort v} {f g : (x : α) → β x}&lt;br /&gt;
    (h : ∀ x, f x = g x) : f = g :=&lt;br /&gt;
  let eqv (f g : (x : α) → β x) : Prop := ∀ x, f x = g x&lt;br /&gt;
  let app (q : Quot eqv) (x : α) : β x := Quot.lift (fun f =&amp;gt; f x) (fun _ _ h =&amp;gt; h x) q&lt;br /&gt;
  congrArg app (Quot.sound h)&lt;br /&gt;
&lt;br /&gt;
#print axioms funext&#039;&lt;br /&gt;
#print axioms funext&lt;br /&gt;
&amp;lt;/pre&amp;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;
&#039;funext&#039;&#039; depends on axioms: [Quot.sound]&lt;br /&gt;
&#039;funext&#039; depends on axioms: [Quot.sound]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The axiom &amp;lt;code&amp;gt;Quot.sound&amp;lt;/code&amp;gt; makes the classes of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;g&amp;lt;/code&amp;gt;&lt;br /&gt;
equal, and &amp;lt;code&amp;gt;congrArg&amp;lt;/code&amp;gt; carries that equality through &amp;lt;code&amp;gt;app&amp;lt;/code&amp;gt;. The proof&lt;br /&gt;
type-checks only because &amp;lt;code&amp;gt;app (Quot.mk eqv f)&amp;lt;/code&amp;gt; reduces, by the computation rule&lt;br /&gt;
for &amp;lt;code&amp;gt;Quot.lift&amp;lt;/code&amp;gt;, to &amp;lt;code&amp;gt;fun x =&amp;gt; f x&amp;lt;/code&amp;gt;, which is &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; up to&lt;br /&gt;
η. A merely propositional computation rule would not do: rewriting under the binder would&lt;br /&gt;
already need function extensionality.&amp;lt;ref name=&amp;quot;refman-quot&amp;quot; /&amp;gt; The axiom itself, and why&lt;br /&gt;
it is one, are on [[Lean theorem prover/Foundations/The three axioms|the three axioms]].&lt;br /&gt;
&lt;br /&gt;
== Uniqueness of identity proofs ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Uniqueness of identity proofs&#039;&#039;&#039; (UIP) says that any two proofs of&lt;br /&gt;
&amp;lt;code&amp;gt;a = b&amp;lt;/code&amp;gt; are equal. Streicher&#039;s &#039;&#039;&#039;axiom K&#039;&#039;&#039; is the special case that every&lt;br /&gt;
proof of &amp;lt;code&amp;gt;a = a&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;Eq.refl a&amp;lt;/code&amp;gt;, and the two are equivalent.&amp;lt;ref name=&amp;quot;hott&amp;quot;&amp;gt;The Univalent Foundations Program, &#039;&#039;Homotopy Type Theory: Univalent Foundations of Mathematics&#039;&#039;, Institute for Advanced Study, 2013; Notes to Chapter 1, Example 3.1.9 and §7.2. https://homotopytypetheory.org/book/&amp;lt;/ref&amp;gt;&lt;br /&gt;
In Lean both hold by definition:&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;
theorem uip {α : Sort u} {a b : α} (h₁ h₂ : a = b) : h₁ = h₂ := rfl&lt;br /&gt;
&lt;br /&gt;
theorem axiomK {α : Sort u} {a : α} (C : α → Sort v) (h : a = a) (x : C a) :&lt;br /&gt;
    h ▸ x = x := rfl&lt;br /&gt;
&lt;br /&gt;
#print axioms uip&lt;br /&gt;
#print axioms axiomK&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Both report that they do not depend on any axioms. The first is definitional proof&lt;br /&gt;
irrelevance: &amp;lt;code&amp;gt;a = b&amp;lt;/code&amp;gt; is a proposition, so any two of its proofs are definitionally&lt;br /&gt;
equal. The second is what Carneiro calls K-like reduction: for a subsingleton eliminator,&lt;br /&gt;
proof irrelevance lets the major premise be replaced by the constructor, after which the&lt;br /&gt;
ordinary computation rule applies. For &amp;lt;code&amp;gt;Eq&amp;lt;/code&amp;gt; this means that transport along&lt;br /&gt;
&amp;lt;code&amp;gt;h : a = a&amp;lt;/code&amp;gt; reduces to the identity, whatever &amp;lt;code&amp;gt;h&amp;lt;/code&amp;gt; is.&amp;lt;ref name=&amp;quot;carneiro&amp;quot;&amp;gt;Mario Carneiro, &#039;&#039;The Type Theory of Lean&#039;&#039;, Master&#039;s thesis, Carnegie Mellon University, 2019; p. 4 (UIP and univalence), p. 12 (K-like reduction), p. 15 (proof irrelevance and axiom K in Lean and Coq). https://github.com/digama0/lean-type-theory/releases/tag/v1.0&amp;lt;/ref&amp;gt;&lt;br /&gt;
Carneiro lists proof irrelevance and axiom K among the axioms commonly added to Coq, and&lt;br /&gt;
observes that they hold in Lean with no axioms.&amp;lt;ref name=&amp;quot;carneiro&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Homotopy type theory takes the opposite course. It reads a proof of equality as a path,&lt;br /&gt;
keeps proofs of equality relevant, and treats UIP as a property some types have rather&lt;br /&gt;
than an axiom.&amp;lt;ref name=&amp;quot;hott&amp;quot; /&amp;gt; Its univalence axiom identifies equivalent types. The&lt;br /&gt;
two-element type then has a non-trivial self-equality, the swap, so the universe is not a&lt;br /&gt;
set, and univalence is inconsistent with UIP.&amp;lt;ref name=&amp;quot;hott&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;carneiro&amp;quot; /&amp;gt;&lt;br /&gt;
Because Lean&#039;s UIP is part of definitional equality rather than an axiom that could be&lt;br /&gt;
left out, univalence cannot be added to Lean without making it inconsistent.&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/Foundations/Quotient types|Quotient types]] treats the construction&lt;br /&gt;
that the proof of function extensionality used.&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>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/Foundations/Definitional_equality&amp;diff=6779</id>
		<title>Lean theorem prover/Foundations/Definitional equality</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Foundations/Definitional_equality&amp;diff=6779"/>
		<updated>2026-10-15T19:34:53Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&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;
{{Lean theorem prover map}}&lt;br /&gt;
&lt;br /&gt;
Two terms are &#039;&#039;&#039;definitionally equal&#039;&#039;&#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&#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&#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&#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&#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, &#039;&#039;The Type Theory of Lean&#039;&#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;&#039;&#039;The Lean&lt;br /&gt;
Language Reference&#039;&#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;
* &#039;&#039;&#039;Beta&#039;&#039;&#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;
* &#039;&#039;&#039;Delta&#039;&#039;&#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;
* &#039;&#039;&#039;Iota&#039;&#039;&#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;
* &#039;&#039;&#039;Zeta&#039;&#039;&#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;
* &#039;&#039;&#039;Eta for functions&#039;&#039;&#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;
* &#039;&#039;&#039;Eta for structures&#039;&#039;&#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 &#039;&#039;31st International Conference on Types for Proofs and Programs (TYPES 2025)&#039;&#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;
* &#039;&#039;&#039;Proof irrelevance&#039;&#039;&#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&#039; : p}{\Gamma \vdash h \equiv h&#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;&#039;&#039;The&lt;br /&gt;
Lean Language Reference&#039;&#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&#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;&#039;&#039;The Lean Language Reference&#039;&#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, &#039;&#039;Type Checking in Lean 4&#039;&#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;&#039;big_mul&#039; does not depend on any axioms&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;&#039;pow_mod&#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;
&#039;&#039;&#039;Weak head normal form.&#039;&#039;&#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&#039;s &#039;&#039;&#039;weak head normal form&#039;&#039;&#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;
&#039;&#039;&#039;Cheap tests.&#039;&#039;&#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;
&#039;&#039;&#039;Lazy delta.&#039;&#039;&#039; When both sides are headed by definitions, Lean&#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 &#039;&#039;&#039;reducibility hint&#039;&#039;&#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 &#039;&#039;&#039;definitional height&#039;&#039;&#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;
&#039;&#039;&#039;Extensionality.&#039;&#039;&#039; When one side is an abstraction and the other is not, Lean&#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&#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&#039;s kernel checks as an &#039;&#039;&#039;algorithmic definitional equality&#039;&#039;&#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&#039;&amp;lt;/math&amp;gt; implies &amp;lt;math&amp;gt;e \equiv e&#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&#039;s full theory no algorithm could be.&lt;br /&gt;
&lt;br /&gt;
Carneiro proved in 2019 that definitional equality in Lean&#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 &#039;&#039;&#039;subject reduction&#039;&#039;&#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&#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;
&#039;&#039;Logical Methods in Computer Science&#039;&#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&#039; : Prop := ∀ p : Prop, p → p&lt;br /&gt;
&lt;br /&gt;
def om : True&#039; := fun A a =&amp;gt;&lt;br /&gt;
  @cast (True&#039; → True&#039;) A&lt;br /&gt;
    (propext ⟨fun _ =&amp;gt; a, fun _ =&amp;gt; id⟩)&lt;br /&gt;
    (fun z =&amp;gt; z (True&#039; → True&#039;) id z)&lt;br /&gt;
&lt;br /&gt;
def Om : True&#039; := om (True&#039; → True&#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&#039;s theorem.&lt;br /&gt;
&lt;br /&gt;
The reference manual states the position plainly. Lean&#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;&#039;&#039;The Lean Language Reference&#039;&#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&#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>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/Foundations/Structural_and_well-founded_recursion&amp;diff=6778</id>
		<title>Lean theorem prover/Foundations/Structural and well-founded recursion</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"/>
		<updated>2026-10-15T19:34:51Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&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;
{{Lean theorem prover map}}&lt;br /&gt;
&lt;br /&gt;
Lean lets a function be defined by calling itself, but Lean&#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;
&#039;&#039;&#039;structural recursion&#039;&#039;&#039; is compiled through the recursor, how &#039;&#039;&#039;well-founded recursion&#039;&#039;&#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;&#039;&#039;The Lean Language Reference&#039;&#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&#039;s&lt;br /&gt;
logic therefore treats every function as &#039;&#039;&#039;total&#039;&#039;&#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;&#039;&#039;The Lean Language Reference&#039;&#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&#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;&#039;&#039;The Lean Language Reference&#039;&#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 &#039;&#039;&#039;pre-definition&#039;&#039;&#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 &#039;&#039;&#039;structurally recursive&#039;&#039;&#039; when every recursive call is on a strict&lt;br /&gt;
sub-term of one fixed argument, the &#039;&#039;&#039;decreasing parameter&#039;&#039;&#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 &#039;&#039;&#039;course-of-values recursion&#039;&#039;&#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;&#039;&#039;The Lean Language Reference&#039;&#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;
&#039;&#039;Types for Proofs and Programs&#039;&#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&#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 &#039;&#039;&#039;well-founded&#039;&#039;&#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&#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 &#039;&#039;&#039;&amp;lt;code&amp;gt;termination_by&amp;lt;/code&amp;gt;&#039;&#039;&#039; and the proofs of decrease with&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;decreasing_by&amp;lt;/code&amp;gt;&#039;&#039;&#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;&#039;&#039;The Lean Language Reference&#039;&#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&#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;&#039;&#039;The Lean&lt;br /&gt;
Language Reference&#039;&#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 &#039;&#039;&#039;&amp;lt;code&amp;gt;partial&amp;lt;/code&amp;gt;&#039;&#039;&#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 &#039;&#039;&#039;opaque constant&#039;&#039;&#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&#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 &#039;partial&#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 &#039;&#039;&#039;&amp;lt;code&amp;gt;unsafe&amp;lt;/code&amp;gt;&#039;&#039;&#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 &#039;spin&#039;&amp;lt;/code&amp;gt;.&lt;br /&gt;
The prefix shows that the refusal is made by Lean&#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&#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>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/Foundations/Inductive_types_and_recursors&amp;diff=6777</id>
		<title>Lean theorem prover/Foundations/Inductive types and recursors</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Foundations/Inductive_types_and_recursors&amp;diff=6777"/>
		<updated>2026-10-15T19:34:50Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Inductive types and recursors}}&lt;br /&gt;
{{Plebeian|Lean theorem prover/Explainers/Building things from constructors|Lean theorem prover/Explainers/Induction, as the machine sees it}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
&lt;br /&gt;
Apart from universes, function types and quotient types, which are built in, every type in&lt;br /&gt;
Lean is an &#039;&#039;&#039;inductive type&#039;&#039;&#039; or is defined in terms of universes, functions and inductive&lt;br /&gt;
types.&amp;lt;ref name=&amp;quot;refman-ind&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, for Lean 4.34.0, lean-lang.org,&lt;br /&gt;
2026, section 4.4, &amp;quot;Inductive Types&amp;quot;.&lt;br /&gt;
https://lean-lang.org/doc/reference/4.34.0/The-Type-System/Inductive-Types/&amp;lt;/ref&amp;gt; The&lt;br /&gt;
natural numbers, lists, pairs, conjunction and disjunction, equality and the existential&lt;br /&gt;
quantifier are all inductive types. An inductive type is given by its constructors, and from&lt;br /&gt;
them Lean derives one more constant, the &#039;&#039;&#039;recursor&#039;&#039;&#039;, which is at once the type&#039;s induction&lt;br /&gt;
principle and its means of primitive recursion. This page describes what an inductive&lt;br /&gt;
definition adds to Lean&#039;s environment, its table of definitions and theorems; the reduction&lt;br /&gt;
rule that makes recursors compute; the strict positivity condition and why it is needed; and,&lt;br /&gt;
briefly, indexed, mutual and nested types.&lt;br /&gt;
&lt;br /&gt;
== What a definition adds ==&lt;br /&gt;
&lt;br /&gt;
An inductive definition names a &#039;&#039;&#039;type constructor&#039;&#039;&#039; and a list of &#039;&#039;&#039;constructors&#039;&#039;&#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;
#print Nat&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;
inductive Nat : Type&lt;br /&gt;
number of parameters: 0&lt;br /&gt;
constructors:&lt;br /&gt;
Nat.zero : Nat&lt;br /&gt;
Nat.succ : Nat → Nat&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type constructor &amp;lt;code&amp;gt;Nat&amp;lt;/code&amp;gt;, the constructors &amp;lt;code&amp;gt;Nat.zero&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;Nat.succ&amp;lt;/code&amp;gt;, and the recursor &amp;lt;code&amp;gt;Nat.rec&amp;lt;/code&amp;gt; are new constants with no&lt;br /&gt;
defining term: Lean adds them as axiomatic constants.&amp;lt;ref name=&amp;quot;carneiro2019&amp;quot;&amp;gt;Mario&lt;br /&gt;
Carneiro, &#039;&#039;The Type Theory of Lean&#039;&#039;, MSc thesis, Carnegie Mellon University, 2019.&lt;br /&gt;
https://github.com/digama0/lean-type-theory/releases/tag/v1.0&amp;lt;/ref&amp;gt; The&lt;br /&gt;
recursor in particular has a function type but is primitive, and cannot be defined using&lt;br /&gt;
&amp;lt;code&amp;gt;fun&amp;lt;/code&amp;gt;.&amp;lt;ref name=&amp;quot;refman-ind&amp;quot; /&amp;gt;&lt;br /&gt;
What makes them more than arbitrary axioms is that their types are computed from the&lt;br /&gt;
definition by a fixed scheme, and that the definition must pass checks, described below,&lt;br /&gt;
which guarantee that adding them cannot make the logic inconsistent. The checks are&lt;br /&gt;
conservative: some harmless definitions are rejected too.&amp;lt;ref name=&amp;quot;refman-ind&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Every other property of the type is derived from the recursor. Injectivity of the&lt;br /&gt;
constructors, the fact that distinct constructors give distinct values, case analysis and&lt;br /&gt;
structural recursion are theorems and definitions built from &amp;lt;code&amp;gt;Nat.rec&amp;lt;/code&amp;gt;, not&lt;br /&gt;
further primitives.&amp;lt;ref name=&amp;quot;refman-ind&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The recursor ==&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.rec&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;&lt;br /&gt;
Nat.rec.{u} {motive : Nat → Sort u} (zero : motive Nat.zero) (succ : (n : Nat) → motive n → motive n.succ) (t : Nat) :&lt;br /&gt;
  motive t&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The arguments have standard names.&amp;lt;ref name=&amp;quot;refman-ind&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;carneiro2019&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* The &#039;&#039;&#039;motive&#039;&#039;&#039; is a family of types indexed by the inductive type, &amp;lt;code&amp;gt;motive : Nat → Sort u&amp;lt;/code&amp;gt;. It says what is being constructed or proved for each number.&lt;br /&gt;
* There is one &#039;&#039;&#039;minor premise&#039;&#039;&#039; per constructor. The one for &amp;lt;code&amp;gt;zero&amp;lt;/code&amp;gt; is a value of &amp;lt;code&amp;gt;motive zero&amp;lt;/code&amp;gt;. The one for &amp;lt;code&amp;gt;succ&amp;lt;/code&amp;gt; takes &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt; and a value of &amp;lt;code&amp;gt;motive n&amp;lt;/code&amp;gt;, the result for the recursive argument, and returns a value of &amp;lt;code&amp;gt;motive (n + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* The &#039;&#039;&#039;major premise&#039;&#039;&#039; &amp;lt;code&amp;gt;t&amp;lt;/code&amp;gt; is the value the recursion runs on, and the result has type &amp;lt;code&amp;gt;motive t&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Because the motive may land in any universe &amp;lt;code&amp;gt;Sort u&amp;lt;/code&amp;gt;, the same constant does two&lt;br /&gt;
jobs. With a motive into &amp;lt;code&amp;gt;Prop&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Nat.rec&amp;lt;/code&amp;gt; is mathematical induction:&lt;br /&gt;
the minor premises are the base case and the induction step. With a motive into&lt;br /&gt;
&amp;lt;code&amp;gt;Type&amp;lt;/code&amp;gt;, it is primitive recursion. Both uses below are checked by the same rule:&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;
def double (n : Nat) : Nat :=&lt;br /&gt;
  Nat.rec (motive := fun _ =&amp;gt; Nat) 0 (fun _ ih =&amp;gt; ih + 2) n&lt;br /&gt;
&lt;br /&gt;
#reduce double 3&lt;br /&gt;
&lt;br /&gt;
theorem zero_add&#039; (n : Nat) : 0 + n = n :=&lt;br /&gt;
  Nat.rec (motive := fun k =&amp;gt; 0 + k = k) rfl (fun _ ih =&amp;gt; congrArg Nat.succ ih) n&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;#reduce double 3&amp;lt;/code&amp;gt; prints &amp;lt;code&amp;gt;6&amp;lt;/code&amp;gt;. In general the recursor&#039;s type is&lt;br /&gt;
determined by the constructors alone: each constructor contributes a minor premise that&lt;br /&gt;
assumes the motive for each of its recursive arguments.&amp;lt;ref name=&amp;quot;carneiro2019&amp;quot; /&amp;gt; Dybjer&lt;br /&gt;
gave a general formulation of this idea for Martin-Löf&#039;s type theory, in which the&lt;br /&gt;
elimination and equality rules of a new type are derived from its formation and introduction&lt;br /&gt;
rules, and Lean&#039;s treatment of inductive types is based on his.&amp;lt;ref name=&amp;quot;lean4lean&amp;quot;&amp;gt;Mario Carneiro, &amp;quot;Lean4Lean: Verifying a&lt;br /&gt;
Typechecker for Lean, in Lean&amp;quot;, in &#039;&#039;31st International Conference on Types for Proofs and&lt;br /&gt;
Programs (TYPES 2025)&#039;&#039;, LIPIcs vol. 384, pp. 2:1–2:23, 2026.&lt;br /&gt;
https://doi.org/10.4230/LIPIcs.TYPES.2025.2 (read in the version arXiv:2403.14064v2)&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;dybjer1994&amp;quot;&amp;gt;Peter Dybjer, &amp;quot;Inductive families&amp;quot;, &#039;&#039;Formal Aspects of&lt;br /&gt;
Computing&#039;&#039; 6(4), 1994, pp. 440–465. https://doi.org/10.1007/BF01211308&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean&#039;s core has recursors but no pattern matching and no recursive definitions. Pattern&lt;br /&gt;
matching and recursion in source text are compiled into uses of the recursor, so the&lt;br /&gt;
recursor is also what guarantees that recursive functions terminate; how that is done is the&lt;br /&gt;
subject of [[Lean theorem prover/Foundations/Structural and well-founded recursion|Structural and well-founded recursion]].&lt;br /&gt;
&lt;br /&gt;
== Iota reduction ==&lt;br /&gt;
&lt;br /&gt;
A recursor applied to a constructor reduces to the corresponding minor premise, applied to&lt;br /&gt;
the constructor&#039;s arguments. This is&lt;br /&gt;
&#039;&#039;&#039;iota reduction&#039;&#039;&#039;, and it is part of definitional equality. For &amp;lt;code&amp;gt;Nat&amp;lt;/code&amp;gt; the two&lt;br /&gt;
rules are&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\mathrm{Nat.rec}\;C\;z\;s\;\mathrm{zero} \equiv z \qquad \mathrm{Nat.rec}\;C\;z\;s\;(\mathrm{succ}\;n) \equiv s\;n\;(\mathrm{Nat.rec}\;C\;z\;s\;n)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When a constructor has recursive arguments, the minor premise receives the recursor applied&lt;br /&gt;
to them, which is how recursion proceeds.&amp;lt;ref name=&amp;quot;refman-ind&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;carneiro2019&amp;quot; /&amp;gt;&lt;br /&gt;
Both rules hold by &amp;lt;code&amp;gt;rfl&amp;lt;/code&amp;gt;, with the step function and the starting value left as&lt;br /&gt;
variables:&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 (z : Nat) (s : Nat → Nat → Nat) :&lt;br /&gt;
    Nat.rec (motive := fun _ =&amp;gt; Nat) z s 0 = z := rfl&lt;br /&gt;
&lt;br /&gt;
example (z : Nat) (s : Nat → Nat → Nat) (n : Nat) :&lt;br /&gt;
    Nat.rec (motive := fun _ =&amp;gt; Nat) z s (n + 1)&lt;br /&gt;
      = s n (Nat.rec (motive := fun _ =&amp;gt; Nat) z s n) := rfl&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The second example is stated with &amp;lt;code&amp;gt;n + 1&amp;lt;/code&amp;gt;, which is definitionally equal to&lt;br /&gt;
&amp;lt;code&amp;gt;Nat.succ n&amp;lt;/code&amp;gt;. Iota&lt;br /&gt;
reduction is the computational content of an inductive type. Without it the recursor would&lt;br /&gt;
be an axiom stating that induction holds; with it, &amp;lt;code&amp;gt;double 3&amp;lt;/code&amp;gt; is&lt;br /&gt;
&amp;lt;code&amp;gt;6&amp;lt;/code&amp;gt; by calculation, and a proof by &amp;lt;code&amp;gt;rfl&amp;lt;/code&amp;gt; is a computation the Lean kernel&lt;br /&gt;
carries out. See [[Lean theorem prover/Foundations/Definitional equality|Definitional equality]].&lt;br /&gt;
&lt;br /&gt;
== Strict positivity ==&lt;br /&gt;
&lt;br /&gt;
Not every list of constructors is acceptable. Every occurrence of the type being defined in&lt;br /&gt;
the type of a constructor argument must be &#039;&#039;&#039;strictly positive&#039;&#039;&#039;: it may not appear to the&lt;br /&gt;
left of an arrow, however deeply nested, and it may appear as an argument only of the type&lt;br /&gt;
constructor of another inductive type.&amp;lt;ref name=&amp;quot;refman-ind&amp;quot; /&amp;gt; The following definition&lt;br /&gt;
breaks the rule, because &amp;lt;code&amp;gt;Liar&amp;lt;/code&amp;gt; appears as the domain of a function argument:&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;
inductive Liar where&lt;br /&gt;
  | mk : (Liar → False) → Liar&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean 4.34.1 rejects it with&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;
(kernel) arg #1 of &#039;Liar.mk&#039; has a non positive occurrence of the datatypes being declared&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The message comes from Lean&#039;s kernel, not the elaborator: the check is part of the trusted&lt;br /&gt;
core.&lt;br /&gt;
&lt;br /&gt;
The reason is that such a type would prove &amp;lt;code&amp;gt;False&amp;lt;/code&amp;gt;. If &amp;lt;code&amp;gt;Liar&amp;lt;/code&amp;gt; existed,&lt;br /&gt;
its constructor would give &amp;lt;code&amp;gt;mk : (Liar → False) → Liar&amp;lt;/code&amp;gt;, and case analysis on its&lt;br /&gt;
one constructor would give a function &amp;lt;code&amp;gt;unmk : Liar → (Liar → False)&amp;lt;/code&amp;gt; that returns&lt;br /&gt;
the function a value was built from. Those two functions are all that is needed:&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;
example (L : Type) (mk : (L → False) → L) (unmk : L → L → False) : False :=&lt;br /&gt;
  let notL : L → False := fun l =&amp;gt; unmk l l&lt;br /&gt;
  notL (mk notL)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean accepts this. &amp;lt;code&amp;gt;notL&amp;lt;/code&amp;gt; applies a value to itself, as in Russell&#039;s paradox, and&lt;br /&gt;
feeding it its own image under &amp;lt;code&amp;gt;mk&amp;lt;/code&amp;gt; yields a proof of &amp;lt;code&amp;gt;False&amp;lt;/code&amp;gt; with no&lt;br /&gt;
induction at all. Strict positivity excludes every definition of this shape. Its exclusion of&lt;br /&gt;
an occurrence nested under an arbitrary function, as in&lt;br /&gt;
&amp;lt;code&amp;gt;f (Fix f) → Fix f&amp;lt;/code&amp;gt; for a parameter &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt;, is needed because a suitable&lt;br /&gt;
&amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; would rebuild the same circularity.&amp;lt;ref name=&amp;quot;refman-ind&amp;quot; /&amp;gt; Dybjer&#039;s criteria&lt;br /&gt;
for well-formed inductive families are likewise stated for strictly positive&lt;br /&gt;
definitions.&amp;lt;ref name=&amp;quot;dybjer1994&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Other checks concern universes: the arguments of a constructor must live in universes no&lt;br /&gt;
larger than that of the type being defined, except that a type in &amp;lt;code&amp;gt;Prop&amp;lt;/code&amp;gt; may take&lt;br /&gt;
arguments from any universe. A type in &amp;lt;code&amp;gt;Prop&amp;lt;/code&amp;gt; also has a restricted recursor whose motive can only be&lt;br /&gt;
a proposition, unless it has at most one constructor whose arguments are all propositions,&lt;br /&gt;
parameters or indices; this is &#039;&#039;&#039;subsingleton elimination&#039;&#039;&#039;, treated on&lt;br /&gt;
[[Lean theorem prover/Foundations/Proof irrelevance and subsingleton elimination|Proof irrelevance and subsingleton elimination]].&amp;lt;ref name=&amp;quot;refman-ind&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Indexed families ==&lt;br /&gt;
&lt;br /&gt;
A type constructor may take two kinds of argument. &#039;&#039;&#039;Parameters&#039;&#039;&#039; are fixed across the whole&lt;br /&gt;
definition. &#039;&#039;&#039;Indices&#039;&#039;&#039; may differ from one constructor to another, so an indexed&lt;br /&gt;
definition defines a whole family of types at once, each member with its own&lt;br /&gt;
constructors.&amp;lt;ref name=&amp;quot;refman-ind&amp;quot; /&amp;gt; Equality is the leading 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;
#print Eq&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;
inductive Eq.{u_1} : {α : Sort u_1} → α → α → Prop&lt;br /&gt;
number of parameters: 2&lt;br /&gt;
constructors:&lt;br /&gt;
Eq.refl : ∀ {α : Sort u_1} (a : α), a = a&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type &amp;lt;code&amp;gt;α&amp;lt;/code&amp;gt; and the left-hand side &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt; are parameters; the right-hand&lt;br /&gt;
side is an index. There is one constructor, and it produces only &amp;lt;code&amp;gt;a = a&amp;lt;/code&amp;gt;. The&lt;br /&gt;
family &amp;lt;code&amp;gt;a = b&amp;lt;/code&amp;gt; is therefore inhabited exactly when &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; is&lt;br /&gt;
&amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;, and its recursor, &amp;lt;code&amp;gt;Eq.rec&amp;lt;/code&amp;gt;, is the principle of substituting equals&lt;br /&gt;
for equals; [[Lean theorem prover/Foundations/Propositional equality|Propositional equality]] follows it further.&lt;br /&gt;
&lt;br /&gt;
A second example is a list whose length is part of its type:&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;
inductive Vect (α : Type u) : Nat → Type u where&lt;br /&gt;
  | nil : Vect α 0&lt;br /&gt;
  | cons : α → Vect α n → Vect α (n + 1)&lt;br /&gt;
&lt;br /&gt;
def Vect.head : Vect α (n + 1) → α&lt;br /&gt;
  | cons a _ =&amp;gt; a&lt;br /&gt;
&lt;br /&gt;
#eval (Vect.cons 1 (Vect.cons 2 Vect.nil)).head&lt;br /&gt;
#check Vect.rec&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The evaluation prints &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Vect.head&amp;lt;/code&amp;gt; needs no case for&lt;br /&gt;
&amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt;: an argument of type &amp;lt;code&amp;gt;Vect α (n + 1)&amp;lt;/code&amp;gt; cannot be &amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt;,&lt;br /&gt;
whose index is 0, and the pattern-match compiler uses the index to see this. The recursor&#039;s&lt;br /&gt;
motive now takes the index as well as the value,&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;
Vect.rec.{u_1, u} {α : Type u} {motive : (a : Nat) → Vect α a → Sort u_1} (nil : motive 0 Vect.nil)&lt;br /&gt;
  (cons : {n : Nat} → (a : α) → (a_1 : Vect α n) → motive n a_1 → motive (n + 1) (Vect.cons a a_1)) {a✝ : Nat}&lt;br /&gt;
  (t : Vect α a✝) : motive a✝ t&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and each minor premise fixes the index that its constructor produces. Indexed definitions of&lt;br /&gt;
this kind are Dybjer&#039;s &#039;&#039;&#039;inductive families&#039;&#039;&#039;.&amp;lt;ref name=&amp;quot;dybjer1994&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutual and nested types ==&lt;br /&gt;
&lt;br /&gt;
Several types may be defined together in a &amp;lt;code&amp;gt;mutual&amp;lt;/code&amp;gt; block, each constructor&lt;br /&gt;
referring to any of them; the predicates &amp;quot;even&amp;quot; and &amp;quot;odd&amp;quot; on the natural numbers are a&lt;br /&gt;
standard case. The recursor of a mutual group takes one motive per type and one minor&lt;br /&gt;
premise per constructor of every type in the group.&amp;lt;ref name=&amp;quot;refman-ind&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;nested&#039;&#039;&#039; type is one in which the type being defined occurs as an argument of another&lt;br /&gt;
inductive type, as in a tree whose node holds a list of subtrees:&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;
inductive Tree (α : Type) where&lt;br /&gt;
  | node : α → List (Tree α) → Tree α&lt;br /&gt;
&lt;br /&gt;
#check @Tree.rec&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;
@Tree.rec : {α : Type} →&lt;br /&gt;
  {motive_1 : Tree α → Sort u_1} →&lt;br /&gt;
    {motive_2 : List (Tree α) → Sort u_1} →&lt;br /&gt;
      ((a : α) → (a_1 : List (Tree α)) → motive_2 a_1 → motive_1 (Tree.node a a_1)) →&lt;br /&gt;
        motive_2 [] →&lt;br /&gt;
          ((head : Tree α) → (tail : List (Tree α)) → motive_1 head → motive_2 tail → motive_2 (head :: tail)) →&lt;br /&gt;
            (t : Tree α) → motive_1 t&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The recursor has a second motive, for lists of trees, with minor premises for the empty list&lt;br /&gt;
and for a list cell. It has the shape of the recursor of a mutual pair of types, trees and&lt;br /&gt;
lists of trees, because that is how Lean&#039;s kernel justifies a nested type: it translates the&lt;br /&gt;
nested definition into a mutual one and accepts the original only if the translation&lt;br /&gt;
succeeds.&amp;lt;ref name=&amp;quot;refman-ind&amp;quot; /&amp;gt; Direct support for nested types is one of the extensions of&lt;br /&gt;
the Lean 4 kernel over its predecessor, and Carneiro identifies it, with eta for structures,&lt;br /&gt;
as one of the two extensions that change the theory rather than abbreviate it.&amp;lt;ref name=&amp;quot;lean4lean&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Where the scheme comes from ==&lt;br /&gt;
&lt;br /&gt;
In the pure Calculus of Constructions, data and predicates could be represented by&lt;br /&gt;
higher-order quantification, an encoding that was inefficient as a program and weak as a&lt;br /&gt;
logic; the calculus was therefore extended with a primitive notion of inductive&lt;br /&gt;
definition.&amp;lt;ref name=&amp;quot;pm1993&amp;quot;&amp;gt;Christine Paulin-Mohring, &amp;quot;Inductive definitions in the&lt;br /&gt;
system Coq: rules and properties&amp;quot;, in &#039;&#039;Typed Lambda Calculi and Applications&#039;&#039; (TLCA 1993),&lt;br /&gt;
Lecture Notes in Computer Science, Springer, 1993, pp. 328–345.&lt;br /&gt;
https://doi.org/10.1007/BFb0037116&amp;lt;/ref&amp;gt; The result, the Calculus of Inductive&lt;br /&gt;
Constructions, is the theory Lean was based on when the project began in 2013.&amp;lt;ref name=&amp;quot;lean4&amp;quot;&amp;gt;Leonardo de&lt;br /&gt;
Moura and Sebastian Ullrich, &amp;quot;The Lean 4 Theorem Prover and Programming Language (System&lt;br /&gt;
Description)&amp;quot;, in &#039;&#039;Automated Deduction – CADE 28&#039;&#039;, Lecture Notes in Computer Science,&lt;br /&gt;
Springer, 2021, pp. 625–635. https://doi.org/10.1007/978-3-030-79876-5_37&amp;lt;/ref&amp;gt; Lean&#039;s&lt;br /&gt;
presentation differs visibly from Coq&#039;s here: Coq&#039;s core uses primitive&lt;br /&gt;
&amp;lt;code&amp;gt;fix&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;match&amp;lt;/code&amp;gt;, with a check that each recursive call is made on a&lt;br /&gt;
component produced by a &amp;lt;code&amp;gt;match&amp;lt;/code&amp;gt;, while Lean&#039;s core has only recursors, and&lt;br /&gt;
definitions written with recursion and matching are compiled into them before the Lean kernel&lt;br /&gt;
sees them.&amp;lt;ref name=&amp;quot;carneiro2019&amp;quot; /&amp;gt; The history is told on&lt;br /&gt;
[[Lean theorem prover/History/The Calculus of Constructions|The Calculus of Constructions]].&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/Foundations/Structural and well-founded recursion|Structural and well-founded recursion]] shows how ordinary recursive definitions&lt;br /&gt;
are turned into recursor applications, and what happens when they cannot be.&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>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/Foundations/Universes_and_Prop&amp;diff=6776</id>
		<title>Lean theorem prover/Foundations/Universes and Prop</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Foundations/Universes_and_Prop&amp;diff=6776"/>
		<updated>2026-10-15T19:34:49Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Universes and Prop}}&lt;br /&gt;
{{Plebeian|Lean theorem prover/Explainers/Why there is no type of all types}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
&lt;br /&gt;
In Lean every type is itself a term, so every type has a type. The types of types are called&lt;br /&gt;
&#039;&#039;&#039;universes&#039;&#039;&#039; or &#039;&#039;&#039;sorts&#039;&#039;&#039;. They form a hierarchy: &amp;lt;code&amp;gt;Sort 0&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;Sort 1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Sort 2&amp;lt;/code&amp;gt; and so on, each a member of the next, with no top.&lt;br /&gt;
The bottom level, &amp;lt;code&amp;gt;Sort 0&amp;lt;/code&amp;gt;, is &amp;lt;code&amp;gt;Prop&amp;lt;/code&amp;gt;, the universe of propositions,&lt;br /&gt;
and it obeys different rules from the levels above it. This page sets out the hierarchy, the&lt;br /&gt;
rule that assigns a universe to a function type, the operation &amp;lt;math&amp;gt;\mathrm{imax}&amp;lt;/math&amp;gt; that&lt;br /&gt;
rule needs, universe polymorphism, and the paradox that makes a hierarchy necessary.&lt;br /&gt;
&lt;br /&gt;
== Sorts and their names ==&lt;br /&gt;
&lt;br /&gt;
Each universe has a &#039;&#039;&#039;level&#039;&#039;&#039;, and &amp;lt;code&amp;gt;Sort u&amp;lt;/code&amp;gt; is the universe at level&lt;br /&gt;
&amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;. Two abbreviations name the cases that matter in practice:&lt;br /&gt;
&amp;lt;code&amp;gt;Prop&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;Sort 0&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;Type u&amp;lt;/code&amp;gt; is&lt;br /&gt;
&amp;lt;code&amp;gt;Sort (u + 1)&amp;lt;/code&amp;gt;, with &amp;lt;code&amp;gt;Type&amp;lt;/code&amp;gt; alone meaning &amp;lt;code&amp;gt;Type 0&amp;lt;/code&amp;gt;, that is,&lt;br /&gt;
&amp;lt;code&amp;gt;Sort 1&amp;lt;/code&amp;gt;.&amp;lt;ref name=&amp;quot;refman-univ&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, for Lean&lt;br /&gt;
4.34.0, lean-lang.org, 2026, section 4.3, &amp;quot;Universes&amp;quot;.&lt;br /&gt;
https://lean-lang.org/doc/reference/4.34.0/The-Type-System/Universes/&amp;lt;/ref&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;
#check Prop&lt;br /&gt;
#check Type&lt;br /&gt;
#check Type 3&lt;br /&gt;
#check Sort 0&lt;br /&gt;
example : Sort 0 = Prop := rfl&lt;br /&gt;
example : Sort 1 = Type := rfl&lt;br /&gt;
example : Sort (3 + 1) = Type 3 := rfl&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean prints &amp;lt;code&amp;gt;Prop : Type&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Type : Type 1&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;Type 3 : Type 4&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Prop : Type&amp;lt;/code&amp;gt;, and accepts the three equations&lt;br /&gt;
by &amp;lt;code&amp;gt;rfl&amp;lt;/code&amp;gt;: the names are notation for the same terms. The typing rule behind the&lt;br /&gt;
first four lines is the sort 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 \mathrm{Sort}\,u : \mathrm{Sort}\,(u+1)}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and nothing else gives a universe a type. In particular no universe is a member of itself:&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;
example : Type := Type&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean 4.34.1 rejects it:&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;
  Type&lt;br /&gt;
has type&lt;br /&gt;
  Type 1&lt;br /&gt;
of sort `Type 2` but is expected to have type&lt;br /&gt;
  Type&lt;br /&gt;
of sort `Type 1`&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean&#039;s universes are also &#039;&#039;&#039;not cumulative&#039;&#039;&#039;: a type in &amp;lt;code&amp;gt;Type 0&amp;lt;/code&amp;gt; is not&lt;br /&gt;
thereby in &amp;lt;code&amp;gt;Type 1&amp;lt;/code&amp;gt;, and each type has exactly one universe.&amp;lt;ref name=&amp;quot;refman-univ&amp;quot; /&amp;gt;&lt;br /&gt;
A type is moved up explicitly, by wrapping it:&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;
example : Type 1 := Nat&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
fails with &amp;lt;code&amp;gt;Type mismatch&amp;lt;/code&amp;gt;, reporting that &amp;lt;code&amp;gt;Nat&amp;lt;/code&amp;gt; has type&lt;br /&gt;
&amp;lt;code&amp;gt;Type&amp;lt;/code&amp;gt; but is expected to have type &amp;lt;code&amp;gt;Type 1&amp;lt;/code&amp;gt;. The standard wrapper is&lt;br /&gt;
&amp;lt;code&amp;gt;ULift&amp;lt;/code&amp;gt;, a structure with one field, &amp;lt;code&amp;gt;down&amp;lt;/code&amp;gt;, whose universe parameter&lt;br /&gt;
says how far to lift:&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 (ULift.{1} Nat)&lt;br /&gt;
example : Type 1 := ULift.{1} Nat&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean prints &amp;lt;code&amp;gt;ULift Nat : Type 1&amp;lt;/code&amp;gt; and accepts the example. Coq, by contrast, has cumulative universes; Carneiro notes that&lt;br /&gt;
cumulativity breaks the unique-typing theorem his analysis of Lean relies on.&amp;lt;ref name=&amp;quot;carneiro2019&amp;quot;&amp;gt;Mario&lt;br /&gt;
Carneiro, &#039;&#039;The Type Theory of Lean&#039;&#039;, MSc thesis, Carnegie Mellon University, 2019.&lt;br /&gt;
https://github.com/digama0/lean-type-theory/releases/tag/v1.0&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The universe of a function type ==&lt;br /&gt;
&lt;br /&gt;
A dependent function type &amp;lt;code&amp;gt;(x : A) → B&amp;lt;/code&amp;gt; is a type, so it lives in some universe.&lt;br /&gt;
The formation rule decides which:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{\Gamma \vdash A : \mathrm{Sort}\,u \qquad \Gamma, x : A \vdash B : \mathrm{Sort}\,v}{\Gamma \vdash (x : A) \to B : \mathrm{Sort}\,(\mathrm{imax}\,u\,v)}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\mathrm{imax}\,u\,v = \begin{cases} 0 &amp;amp; \text{if } v = 0 \\ \max(u, v) &amp;amp; \text{otherwise.} \end{cases}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are two cases.&amp;lt;ref name=&amp;quot;refman-univ&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;carneiro2019&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;The codomain is data&#039;&#039;&#039; (&amp;lt;math&amp;gt;v \geq 1&amp;lt;/math&amp;gt;). The function type lives in the larger of the two universes. A type in &amp;lt;code&amp;gt;Type u&amp;lt;/code&amp;gt; may only quantify over types in universes no larger than its own; this is &#039;&#039;&#039;predicativity&#039;&#039;&#039;.&lt;br /&gt;
* &#039;&#039;&#039;The codomain is a proposition&#039;&#039;&#039; (&amp;lt;math&amp;gt;v = 0&amp;lt;/math&amp;gt;). The function type is a proposition, whatever the domain. A proposition may quantify over all propositions, or over all types at any level, and still be a proposition; this is &#039;&#039;&#039;impredicativity&#039;&#039;&#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;
#check ∀ (p : Prop), p → p&lt;br /&gt;
#check (α : Type) → α → α&lt;br /&gt;
#check (α : Type 2) → Prop&lt;br /&gt;
#check (n : Nat) → n = n&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The output is&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;
∀ (p : Prop), p → p : Prop&lt;br /&gt;
(α : Type) → α → α : Type 1&lt;br /&gt;
Type 2 → Prop : Type 3&lt;br /&gt;
∀ (n : Nat), n = n : Prop&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first statement quantifies over every proposition, including itself, and is a&lt;br /&gt;
proposition. The second, the type of the polymorphic identity function on&lt;br /&gt;
&amp;lt;code&amp;gt;Type&amp;lt;/code&amp;gt;, quantifies over &amp;lt;code&amp;gt;Type&amp;lt;/code&amp;gt; and so lands one level up, in&lt;br /&gt;
&amp;lt;code&amp;gt;Type 1&amp;lt;/code&amp;gt;. The third is a function type into &amp;lt;code&amp;gt;Prop&amp;lt;/code&amp;gt;, not a function type&lt;br /&gt;
whose values are proofs, so it is data: its codomain &amp;lt;code&amp;gt;Prop&amp;lt;/code&amp;gt; lives in&lt;br /&gt;
&amp;lt;code&amp;gt;Sort 1&amp;lt;/code&amp;gt;, and the result is in &amp;lt;math&amp;gt;\mathrm{Sort}\,(\max(4, 1)) =&amp;lt;/math&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;Type 3&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Why imax ==&lt;br /&gt;
&lt;br /&gt;
The two cases could be stated as two rules. A single operation on levels is needed because of&lt;br /&gt;
universe polymorphism. A definition may be stated for an arbitrary level variable&lt;br /&gt;
&amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt;, and the rule must give the function type a universe without knowing whether&lt;br /&gt;
&amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; will later be 0. With &amp;lt;math&amp;gt;\max&amp;lt;/math&amp;gt; alone that is impossible. The obvious&lt;br /&gt;
candidate, &amp;lt;math&amp;gt;\max\,u\,v&amp;lt;/math&amp;gt;, goes wrong when &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; is set to 0: a&lt;br /&gt;
proposition that quantifies over a type in &amp;lt;code&amp;gt;Sort u&amp;lt;/code&amp;gt; would land in&lt;br /&gt;
&amp;lt;math&amp;gt;\mathrm{Sort}\,(\max(u, 0)) = \mathrm{Sort}\,u&amp;lt;/math&amp;gt; instead of in&lt;br /&gt;
&amp;lt;code&amp;gt;Prop&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;Prop&amp;lt;/code&amp;gt; would not be impredicative. No other expression&lt;br /&gt;
built from &amp;lt;math&amp;gt;\max&amp;lt;/math&amp;gt; and successor does better: one that mentions &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt; is&lt;br /&gt;
never below &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;, so it is not 0 when &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; is 0 and &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt; is&lt;br /&gt;
not, and one that does not mention &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt; cannot equal &amp;lt;math&amp;gt;\max(u, v)&amp;lt;/math&amp;gt;&lt;br /&gt;
for every &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;. &amp;lt;math&amp;gt;\mathrm{imax}&amp;lt;/math&amp;gt; is the level expression that reduces&lt;br /&gt;
to the right case once &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; is known.&amp;lt;ref name=&amp;quot;refman-univ&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Level expressions are built from numerals, variables, successor, &amp;lt;math&amp;gt;\max&amp;lt;/math&amp;gt; and&lt;br /&gt;
&amp;lt;math&amp;gt;\mathrm{imax}&amp;lt;/math&amp;gt;, and two levels are equal when they denote the same number under&lt;br /&gt;
every assignment of numbers to their variables.&amp;lt;ref name=&amp;quot;carneiro2019&amp;quot; /&amp;gt; Lean will not&lt;br /&gt;
treat &amp;lt;math&amp;gt;\mathrm{imax}\,u\,v&amp;lt;/math&amp;gt; as &amp;lt;math&amp;gt;\max\,u\,v&amp;lt;/math&amp;gt;, because the two differ&lt;br /&gt;
when &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; is 0:&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;
universe u v&lt;br /&gt;
&lt;br /&gt;
def Fn (α : Sort u) (β : Sort v) : Sort (imax u v) := α → β&lt;br /&gt;
&lt;br /&gt;
#check Fn.{1, 0}&lt;br /&gt;
#check Fn.{1, 1}&lt;br /&gt;
#check Fn.{0, 2}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The three instances print as &amp;lt;code&amp;gt;Fn : Type → Prop → Prop&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;Fn : Type → Type → Type&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Fn : Prop → Type 1 → Type 1&amp;lt;/code&amp;gt;: the&lt;br /&gt;
same definition gives a proposition-valued result in the first case and data in the other&lt;br /&gt;
two. Stating the result universe as &amp;lt;code&amp;gt;Sort (max u v)&amp;lt;/code&amp;gt; instead is rejected:&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;
universe u v&lt;br /&gt;
&lt;br /&gt;
def Fn2 (α : Sort u) (β : Sort v) : Sort (max u v) := α → β&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;
  α → β&lt;br /&gt;
has type&lt;br /&gt;
  Sort (imax u v)&lt;br /&gt;
of sort `Type (imax u v)` but is expected to have type&lt;br /&gt;
  Sort (max u v)&lt;br /&gt;
of sort `Type (max u v)`&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Universe polymorphism ==&lt;br /&gt;
&lt;br /&gt;
A definition may take &#039;&#039;&#039;universe parameters&#039;&#039;&#039;, written after its name as&lt;br /&gt;
&amp;lt;code&amp;gt;.{u, v}&amp;lt;/code&amp;gt;. It is then a schema: each use instantiates the parameters with level&lt;br /&gt;
expressions, and instantiations at different levels need not be definitionally&lt;br /&gt;
equal.&amp;lt;ref name=&amp;quot;refman-univ&amp;quot; /&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;
set_option pp.universes true in&lt;br /&gt;
#check @id&lt;br /&gt;
#check @id.{0}&lt;br /&gt;
#check List.{0}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean prints &amp;lt;code&amp;gt;@id.{u_1} : {α : Sort u_1} → α → α&amp;lt;/code&amp;gt;, then&lt;br /&gt;
&amp;lt;code&amp;gt;@id : ∀ {α : Prop}, α → α&amp;lt;/code&amp;gt; for the instance at level 0, where the identity&lt;br /&gt;
function on proofs is itself a proof of a proposition, and &amp;lt;code&amp;gt;List : Type → Type&amp;lt;/code&amp;gt;.&lt;br /&gt;
This is what lets one identity function, one list type and one equality serve at every&lt;br /&gt;
level. Without it each would have to be defined once per universe.&lt;br /&gt;
&lt;br /&gt;
== Prop ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Prop&amp;lt;/code&amp;gt; is the universe of propositions. Besides impredicativity, it has&lt;br /&gt;
properties that the levels above it lack:&amp;lt;ref name=&amp;quot;refman-props&amp;quot;&amp;gt;&#039;&#039;The Lean Language&lt;br /&gt;
Reference&#039;&#039;, for Lean 4.34.0, lean-lang.org, 2026, section 4.2, &amp;quot;Propositions&amp;quot;.&lt;br /&gt;
https://lean-lang.org/doc/reference/4.34.0/The-Type-System/Propositions/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Definitional proof irrelevance&#039;&#039;&#039;: any two proofs of the same proposition are definitionally equal.&lt;br /&gt;
* &#039;&#039;&#039;Run-time irrelevance&#039;&#039;&#039;: proofs are erased from compiled code.&lt;br /&gt;
* &#039;&#039;&#039;Restricted elimination&#039;&#039;&#039;: except for a class of propositions with at most one proof, a proof cannot be used to produce data, only other proofs.&lt;br /&gt;
* &#039;&#039;&#039;Extensionality&#039;&#039;&#039;: logically equivalent propositions are equal, by the axiom &amp;lt;code&amp;gt;propext&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
An impredicative universe of propositions is a feature of the Calculus of Constructions of&lt;br /&gt;
Coquand and Huet, and the theory implemented by Lean&#039;s kernel is a version of that&lt;br /&gt;
calculus.&amp;lt;ref name=&amp;quot;refman-elab&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#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;&amp;lt;ref name=&amp;quot;coc&amp;quot;&amp;gt;Thierry Coquand and Gérard Huet, &amp;quot;The calculus of&lt;br /&gt;
constructions&amp;quot;, &#039;&#039;Information and Computation&#039;&#039; 76(2–3), 1988, pp. 95–120.&lt;br /&gt;
https://doi.org/10.1016/0890-5401(88)90005-3&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;abelcoquand&amp;quot;&amp;gt;Andreas Abel and&lt;br /&gt;
Thierry Coquand, &amp;quot;Failure of Normalization in Impredicative Type Theory with Proof-Irrelevant&lt;br /&gt;
Propositional Equality&amp;quot;, &#039;&#039;Logical Methods in Computer Science&#039;&#039; 16(2), 2020.&lt;br /&gt;
https://doi.org/10.23638/LMCS-16(2:14)2020&amp;lt;/ref&amp;gt; Its strength is real: Carneiro observes that&lt;br /&gt;
impredicativity corresponds, in a set-theoretic model, to having full power sets.&amp;lt;ref name=&amp;quot;carneiro2019&amp;quot; /&amp;gt;&lt;br /&gt;
The restriction on elimination is how the rules ensure that no computation can tell which&lt;br /&gt;
proof of a proposition it has received, as proof irrelevance&lt;br /&gt;
requires;&amp;lt;ref name=&amp;quot;refman-subsing&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, for Lean 4.34.0,&lt;br /&gt;
lean-lang.org, 2026, section 4.4.3.1.1.1, &amp;quot;Subsingleton Elimination&amp;quot;.&lt;br /&gt;
https://lean-lang.org/doc/reference/4.34.0/The-Type-System/Inductive-Types/&amp;lt;/ref&amp;gt; it is&lt;br /&gt;
treated on [[Lean theorem prover/Foundations/Proof irrelevance and subsingleton elimination|Proof irrelevance and subsingleton elimination]].&lt;br /&gt;
&lt;br /&gt;
== Why there is a hierarchy ==&lt;br /&gt;
&lt;br /&gt;
The simplest design would be a single universe containing every type, itself included:&lt;br /&gt;
&amp;lt;code&amp;gt;Type : Type&amp;lt;/code&amp;gt;. That design is inconsistent. In 1972 Girard derived a&lt;br /&gt;
contradiction in a type system called System U, by formalising a paradox in the style of&lt;br /&gt;
Burali-Forti&#039;s paradox of the largest ordinal. The same argument shows that the first version&lt;br /&gt;
of Martin-Löf&#039;s type theory, which had &amp;lt;code&amp;gt;Type : Type&amp;lt;/code&amp;gt;, proves falsity; in type&lt;br /&gt;
theory the argument is known as &#039;&#039;&#039;Girard&#039;s paradox&#039;&#039;&#039;.&amp;lt;ref name=&amp;quot;nlab&amp;quot;&amp;gt;nLab, &amp;quot;Burali-Forti&#039;s paradox&amp;quot;, section &amp;quot;In type theory: Girard&#039;s&lt;br /&gt;
paradox&amp;quot;, revision of 24 November 2023. https://ncatlab.org/nlab/show/Girard%27s+paradox&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;hurkens&amp;quot;&amp;gt;Antonius&lt;br /&gt;
J. C. Hurkens, &amp;quot;A simplification of Girard&#039;s paradox&amp;quot;, in &#039;&#039;Typed Lambda Calculi and&lt;br /&gt;
Applications&#039;&#039; (TLCA 1995), Lecture Notes in Computer Science 902, Springer, 1995,&lt;br /&gt;
pp. 266–278. https://doi.org/10.1007/BFb0014058&amp;lt;/ref&amp;gt; The &#039;&#039;Homotopy Type Theory&#039;&#039; book makes&lt;br /&gt;
the same point for a universe that contains itself: every type, including the empty one,&lt;br /&gt;
becomes inhabited.&amp;lt;ref name=&amp;quot;hott&amp;quot;&amp;gt;The Univalent Foundations Program, &#039;&#039;Homotopy Type&lt;br /&gt;
Theory: Univalent Foundations of Mathematics&#039;&#039;, Institute for Advanced Study, 2013,&lt;br /&gt;
section 1.3, &amp;quot;Universes and families&amp;quot;. https://homotopytypetheory.org/book/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hurkens&#039;s paper locates the problem precisely. Higher-order logic, in which propositions may&lt;br /&gt;
quantify over all propositions, is consistent. Adding a single rule, which lets a type be&lt;br /&gt;
formed by quantifying over the sort of all types, gives the system called&lt;br /&gt;
&amp;lt;math&amp;gt;\lambda U^-&amp;lt;/math&amp;gt;, which Coquand had already shown inconsistent; Hurkens gives a short&lt;br /&gt;
term in it whose type is falsity.&amp;lt;ref name=&amp;quot;hurkens&amp;quot; /&amp;gt; Impredicativity for propositions&lt;br /&gt;
alone is therefore consistent, and adding it for types as well is not. Lean&#039;s design&lt;br /&gt;
follows the line exactly: &amp;lt;code&amp;gt;Prop&amp;lt;/code&amp;gt; is impredicative, and every universe above it is&lt;br /&gt;
predicative and contained in the next. The plain-language account is&lt;br /&gt;
[[Lean theorem prover/Explainers/Why there is no type of all types|Why there is no type of all types]].&lt;br /&gt;
&lt;br /&gt;
How strong the resulting hierarchy is, measured against set theory, is the subject of&lt;br /&gt;
[[Lean theorem prover/Foundations/Consistency and the metatheory|Consistency and the metatheory]].&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/Foundations/Inductive types and recursors|Inductive types and recursors]] shows how every type other than universes and function types is introduced, and&lt;br /&gt;
how the universe rules constrain it.&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>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/Foundations/Dependent_function_types&amp;diff=6775</id>
		<title>Lean theorem prover/Foundations/Dependent function types</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Foundations/Dependent_function_types&amp;diff=6775"/>
		<updated>2026-10-15T19:34:47Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Dependent function types}}&lt;br /&gt;
{{Plebeian|Lean theorem prover/Explainers/Propositions as types|Lean theorem prover/Explainers/Types as specifications}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;dependent function type&#039;&#039;&#039; is the type of functions whose result type may vary with the&lt;br /&gt;
argument. In Lean it is written &amp;lt;code&amp;gt;(x : A) → B&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; may mention&lt;br /&gt;
&amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt;, and in the literature it is often written&lt;br /&gt;
&amp;lt;math&amp;gt;\Pi x : A.\, B&amp;lt;/math&amp;gt;. It is the only kind of function type in Lean&#039;s core theory. The&lt;br /&gt;
ordinary arrow &amp;lt;code&amp;gt;A → B&amp;lt;/code&amp;gt;, universal quantification &amp;lt;code&amp;gt;∀ x : A, P x&amp;lt;/code&amp;gt; and&lt;br /&gt;
implication &amp;lt;code&amp;gt;P → Q&amp;lt;/code&amp;gt; are all instances of it. This page gives its rules, shows how&lt;br /&gt;
the familiar forms arise as special cases, and explains the implicit and instance-implicit&lt;br /&gt;
arguments that the elaborator adds on top of the same type.&lt;br /&gt;
&lt;br /&gt;
== What the type means ==&lt;br /&gt;
&lt;br /&gt;
Given a type &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; and, for each &amp;lt;code&amp;gt;a : A&amp;lt;/code&amp;gt;, a type &amp;lt;code&amp;gt;B a&amp;lt;/code&amp;gt;, a&lt;br /&gt;
function &amp;lt;code&amp;gt;f : (x : A) → B x&amp;lt;/code&amp;gt; is a function that sends each &amp;lt;code&amp;gt;a : A&amp;lt;/code&amp;gt; to&lt;br /&gt;
an element &amp;lt;code&amp;gt;f a&amp;lt;/code&amp;gt; of &amp;lt;code&amp;gt;B a&amp;lt;/code&amp;gt;. The type of the result depends on the&lt;br /&gt;
argument.&amp;lt;ref name=&amp;quot;tpil&amp;quot;&amp;gt;Jeremy Avigad, Leonardo de Moura, Soonho Kong and Sebastian&lt;br /&gt;
Ullrich, &#039;&#039;Theorem Proving in Lean 4&#039;&#039;, lean-lang.org (version for Lean 4.33.0), chapter 2,&lt;br /&gt;
&amp;quot;Dependent Type Theory&amp;quot;.&lt;br /&gt;
https://lean-lang.org/theorem_proving_in_lean4/Dependent-Type-Theory/&amp;lt;/ref&amp;gt; Read as sets,&lt;br /&gt;
such a function is an element of the product &amp;lt;math&amp;gt;\prod_{a \in A} B(a)&amp;lt;/math&amp;gt;, which is why&lt;br /&gt;
these types are also called &#039;&#039;&#039;dependent products&#039;&#039;&#039; or &amp;lt;math&amp;gt;\Pi&amp;lt;/math&amp;gt;-types.&amp;lt;ref name=&amp;quot;refman-fn&amp;quot;&amp;gt;&#039;&#039;The&lt;br /&gt;
Lean Language Reference&#039;&#039;, for 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;
A small example: &amp;lt;code&amp;gt;Fin k&amp;lt;/code&amp;gt; is the type of natural numbers less than&lt;br /&gt;
&amp;lt;code&amp;gt;k&amp;lt;/code&amp;gt;, so a function that returns the number 0 as an element of&lt;br /&gt;
&amp;lt;code&amp;gt;Fin (n + 1)&amp;lt;/code&amp;gt; has a different result type for every &amp;lt;code&amp;gt;n&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 zeroFin : (n : Nat) → Fin (n + 1) := fun n =&amp;gt; ⟨0, Nat.succ_pos n⟩&lt;br /&gt;
&lt;br /&gt;
#check zeroFin 4&lt;br /&gt;
#check zeroFin 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean 4.34.1 prints &amp;lt;code&amp;gt;zeroFin 4 : Fin (4 + 1)&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;zeroFin 0 : Fin (0 + 1)&amp;lt;/code&amp;gt;: one function, two result types.&lt;br /&gt;
&lt;br /&gt;
== The rules ==&lt;br /&gt;
&lt;br /&gt;
The type has the usual four kinds of rule, in the notation of&lt;br /&gt;
[[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]].&lt;br /&gt;
They are Carneiro&#039;s rules for Lean, with &amp;lt;math&amp;gt;\mathrm{Sort}\,u&amp;lt;/math&amp;gt; for his&lt;br /&gt;
&amp;lt;math&amp;gt;\mathrm{U}_u&amp;lt;/math&amp;gt;; as on that page, the introduction rule also requires the domain&lt;br /&gt;
to be a type.&amp;lt;ref name=&amp;quot;carneiro2019&amp;quot;&amp;gt;Mario Carneiro, &#039;&#039;The Type Theory of&lt;br /&gt;
Lean&#039;&#039;, MSc thesis, Carnegie Mellon University, 2019.&lt;br /&gt;
https://github.com/digama0/lean-type-theory/releases/tag/v1.0&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Formation.&#039;&#039;&#039; A dependent function type exists when its domain is a type and its codomain&lt;br /&gt;
is a type in the context extended by the bound variable:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{\Gamma \vdash A : \mathrm{Sort}\,u \qquad \Gamma, x : A \vdash B : \mathrm{Sort}\,v}{\Gamma \vdash (x : A) \to B : \mathrm{Sort}\,(\mathrm{imax}\,u\,v)}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The universe of the result is &amp;lt;math&amp;gt;\mathrm{imax}\,u\,v&amp;lt;/math&amp;gt;, which equals&lt;br /&gt;
&amp;lt;math&amp;gt;\max(u, v)&amp;lt;/math&amp;gt; unless &amp;lt;math&amp;gt;v = 0&amp;lt;/math&amp;gt;, in which case it is 0. That exception&lt;br /&gt;
makes a function type whose codomain is a proposition itself a proposition, whatever its&lt;br /&gt;
domain; why it is&lt;br /&gt;
needed is the subject of [[Lean theorem prover/Foundations/Universes and Prop|Universes and Prop]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Introduction.&#039;&#039;&#039; A function is made by abstraction. If &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; is a type and&lt;br /&gt;
&amp;lt;math&amp;gt;e&amp;lt;/math&amp;gt; has type &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; when &amp;lt;math&amp;gt;x : A&amp;lt;/math&amp;gt; is assumed, then&lt;br /&gt;
&amp;lt;math&amp;gt;\lambda x : A.\, e&amp;lt;/math&amp;gt; has the dependent function type:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{\Gamma \vdash A : \mathrm{Sort}\,u \qquad \Gamma, x : A \vdash e : B}{\Gamma \vdash \lambda x : A.\, e : (x : A) \to B}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Elimination.&#039;&#039;&#039; A function is used by application, and the argument is substituted into&lt;br /&gt;
the result type:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{\Gamma \vdash f : (x : A) \to B \qquad \Gamma \vdash a : A}{\Gamma \vdash f\,a : B[a/x]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The substitution &amp;lt;math&amp;gt;B[a/x]&amp;lt;/math&amp;gt; is where dependency shows: in the example above,&lt;br /&gt;
&amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; is &amp;lt;code&amp;gt;Fin (n + 1)&amp;lt;/code&amp;gt; and applying to 4 gives&lt;br /&gt;
&amp;lt;code&amp;gt;Fin (4 + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Computation and uniqueness.&#039;&#039;&#039; Applying an abstraction reduces by substitution, the&lt;br /&gt;
&#039;&#039;&#039;beta&#039;&#039;&#039; rule; and every function equals the abstraction of its own application, the&lt;br /&gt;
&#039;&#039;&#039;eta&#039;&#039;&#039; rule:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;(\lambda x : A.\, e)\,a \equiv e[a/x] \qquad\qquad \lambda x : A.\, f\,x \equiv f&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Both are definitional equalities in Lean, so both can be proved 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;
example : (fun x : Nat =&amp;gt; x + 1) 2 = 3 := rfl&lt;br /&gt;
example (f : Nat → Nat) : (fun x =&amp;gt; f x) = f := rfl&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Definitional equality of functions goes no further than this. Two functions that agree on&lt;br /&gt;
every argument but are computed differently are not, in general, definitionally equal; that&lt;br /&gt;
they are equal is a theorem, &amp;lt;code&amp;gt;funext&amp;lt;/code&amp;gt;, which Lean proves using quotient&lt;br /&gt;
types.&amp;lt;ref name=&amp;quot;refman-fn&amp;quot; /&amp;gt; See [[Lean theorem prover/Foundations/Definitional equality|Definitional equality]] and [[Lean theorem prover/Foundations/Quotient types|Quotient types]].&lt;br /&gt;
&lt;br /&gt;
In the core language every function takes exactly one argument. A function &amp;quot;of two&lt;br /&gt;
arguments&amp;quot; is a function that returns a function, and Lean&#039;s notation for several arguments&lt;br /&gt;
is an abbreviation for this nesting.&amp;lt;ref name=&amp;quot;refman-fn&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The arrow is the non-dependent case ==&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; does not mention &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt;, the type &amp;lt;code&amp;gt;(x : A) → B&amp;lt;/code&amp;gt; is&lt;br /&gt;
written &amp;lt;code&amp;gt;A → B&amp;lt;/code&amp;gt;. Nothing else changes: the core language has only one function&lt;br /&gt;
type, and a non-dependent function type is a dependent one whose bound variable is&lt;br /&gt;
unused.&amp;lt;ref name=&amp;quot;refman-fn&amp;quot; /&amp;gt; Lean confirms that the two spellings denote the same type:&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 : ((x : Nat) → Bool) = (Nat → Bool) := rfl&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The same construction gives the logical connectives. When &amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; is a proposition,&lt;br /&gt;
&amp;lt;code&amp;gt;(x : A) → B&amp;lt;/code&amp;gt; is the proposition &amp;quot;for every &amp;lt;code&amp;gt;x : A&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt;&amp;quot;,&lt;br /&gt;
and Lean prints it with &amp;lt;code&amp;gt;∀&amp;lt;/code&amp;gt;. When moreover &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; is a proposition and&lt;br /&gt;
&amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; does not mention &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt;, it is the implication &amp;lt;code&amp;gt;A → B&amp;lt;/code&amp;gt;. A&lt;br /&gt;
proof of a universal statement is a function from instances to proofs, and using the&lt;br /&gt;
statement is applying the function:&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 add_zero&#039; : ∀ n : Nat, n + 0 = n := fun n =&amp;gt; Nat.add_zero n&lt;br /&gt;
&lt;br /&gt;
#check add_zero&#039; 5&lt;br /&gt;
#check fun (p q : Prop) (hp : p) (_ : q) =&amp;gt; hp&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The output is &amp;lt;code&amp;gt;add_zero&#039; 5 : 5 + 0 = 5&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;fun p q hp x =&amp;gt; hp : ∀ (p q : Prop), p → q → p&amp;lt;/code&amp;gt;. The second term is a proof of&lt;br /&gt;
the propositional tautology &amp;lt;math&amp;gt;p \to (q \to p)&amp;lt;/math&amp;gt;, and its type is printed with&lt;br /&gt;
&amp;lt;code&amp;gt;∀&amp;lt;/code&amp;gt; for the dependent binders and &amp;lt;code&amp;gt;→&amp;lt;/code&amp;gt; for the others. This&lt;br /&gt;
correspondence between propositions and types, proofs and terms, is described in plain&lt;br /&gt;
language in [[Lean theorem prover/Explainers/Propositions as types|Propositions as types]].&lt;br /&gt;
&lt;br /&gt;
== Implicit and instance-implicit arguments ==&lt;br /&gt;
&lt;br /&gt;
A binder in a function type carries a mark saying how the elaborator should supply the&lt;br /&gt;
argument at a call site:&amp;lt;ref name=&amp;quot;refman-fntypes&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, for Lean&lt;br /&gt;
4.34.0, lean-lang.org, 2026, section 13.2, &amp;quot;Function Types&amp;quot;.&lt;br /&gt;
https://lean-lang.org/doc/reference/4.34.0/Terms/Function-Types/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;(x : A)&amp;lt;/code&amp;gt;, &#039;&#039;&#039;explicit&#039;&#039;&#039;: the caller writes the argument.&lt;br /&gt;
* &amp;lt;code&amp;gt;{x : A}&amp;lt;/code&amp;gt;, &#039;&#039;&#039;implicit&#039;&#039;&#039;: the elaborator inserts a placeholder and fills it by unification, from the other arguments and the expected type.&lt;br /&gt;
* &amp;lt;code&amp;gt;⦃x : A⦄&amp;lt;/code&amp;gt;, &#039;&#039;&#039;strict implicit&#039;&#039;&#039;: as implicit, but the placeholder is inserted only once a later explicit argument is given.&lt;br /&gt;
* &amp;lt;code&amp;gt;[C]&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;[inst : C]&amp;lt;/code&amp;gt;, &#039;&#039;&#039;instance implicit&#039;&#039;&#039;: the elaborator finds the argument by type class instance synthesis ([[Lean theorem prover/System/Type classes and instance resolution|Type classes and instance resolution]]).&lt;br /&gt;
&lt;br /&gt;
The mark is stored in the term as a &amp;lt;code&amp;gt;BinderInfo&amp;lt;/code&amp;gt; field of the binder. It is&lt;br /&gt;
information for the elaborator only. It does not affect type checking or definitional&lt;br /&gt;
equality in the core theory, and two function types that differ only in it are&lt;br /&gt;
definitionally equal.&amp;lt;ref name=&amp;quot;refman-fn&amp;quot; /&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;
import Lean&lt;br /&gt;
open Lean Meta&lt;br /&gt;
&lt;br /&gt;
def double {α : Type} [inst : Add α] (x : α) : α := x + x&lt;br /&gt;
&lt;br /&gt;
#check @double&lt;br /&gt;
#eval double 21&lt;br /&gt;
#eval @double Nat instAddNat 21&lt;br /&gt;
example : ({α : Type} → α → α) = ((α : Type) → α → α) := rfl&lt;br /&gt;
&lt;br /&gt;
#eval show MetaM Unit from do&lt;br /&gt;
  let some c := (← getEnv).find? ``double | throwError &amp;quot;missing&amp;quot;&lt;br /&gt;
  IO.println (repr c.type)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;#check @double&amp;lt;/code&amp;gt; prints &amp;lt;code&amp;gt;@double : {α : Type} → [inst : Add α] → α → α&amp;lt;/code&amp;gt;;&lt;br /&gt;
the &amp;lt;code&amp;gt;@&amp;lt;/code&amp;gt; asks for every argument to be shown and accepted explicitly. Both&lt;br /&gt;
evaluations print &amp;lt;code&amp;gt;42&amp;lt;/code&amp;gt;: in the first the elaborator found &amp;lt;code&amp;gt;α := Nat&amp;lt;/code&amp;gt; by&lt;br /&gt;
unification and the instance &amp;lt;code&amp;gt;instAddNat&amp;lt;/code&amp;gt; by synthesis; in the second both were&lt;br /&gt;
written out. The &amp;lt;code&amp;gt;example&amp;lt;/code&amp;gt; is accepted, so an implicit and an explicit binder give&lt;br /&gt;
definitionally equal types. The last command prints the stored type of&lt;br /&gt;
&amp;lt;code&amp;gt;double&amp;lt;/code&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;
Lean.Expr.forallE&lt;br /&gt;
  `α&lt;br /&gt;
  (Lean.Expr.sort (Lean.Level.succ (Lean.Level.zero)))&lt;br /&gt;
  (Lean.Expr.forallE&lt;br /&gt;
    `inst&lt;br /&gt;
    (Lean.Expr.app (Lean.Expr.const `Add [Lean.Level.zero]) (Lean.Expr.bvar 0))&lt;br /&gt;
    (Lean.Expr.forallE `x (Lean.Expr.bvar 1) (Lean.Expr.bvar 2) (Lean.BinderInfo.default))&lt;br /&gt;
    (Lean.BinderInfo.instImplicit))&lt;br /&gt;
  (Lean.BinderInfo.implicit)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is three nested &amp;lt;code&amp;gt;forallE&amp;lt;/code&amp;gt; binders, as for any function of three arguments; the&lt;br /&gt;
only trace of the braces and brackets is the last field of each binder,&lt;br /&gt;
&amp;lt;code&amp;gt;implicit&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;instImplicit&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt;. To the core theory,&lt;br /&gt;
&amp;lt;code&amp;gt;double&amp;lt;/code&amp;gt; is a function of three explicit arguments, the first a type and the&lt;br /&gt;
second a structure of operations on it.&lt;br /&gt;
&lt;br /&gt;
Implicit arguments are a convenience, and they can fail. When nothing determines an implicit&lt;br /&gt;
argument, the elaborator reports it rather than guessing:&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;
def nothing := List.nil&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean 4.34.1 reports &amp;lt;code&amp;gt;don&#039;t know how to synthesize implicit argument `α`&amp;lt;/code&amp;gt;, showing&lt;br /&gt;
the partial term &amp;lt;code&amp;gt;@List.nil ?m.3&amp;lt;/code&amp;gt;, in which &amp;lt;code&amp;gt;?m.3&amp;lt;/code&amp;gt; is the unfilled&lt;br /&gt;
placeholder: no element type for the empty list was given or can be inferred.&lt;br /&gt;
&lt;br /&gt;
== Polymorphism ==&lt;br /&gt;
&lt;br /&gt;
Because a domain may itself be a universe, the same type expresses polymorphism. The&lt;br /&gt;
identity function is a single term of type &amp;lt;code&amp;gt;{α : Sort u} → α → α&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;
#check @id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean prints &amp;lt;code&amp;gt;@id : {α : Sort u_1} → α → α&amp;lt;/code&amp;gt;. Its first argument is a type, and the type of its&lt;br /&gt;
second argument depends on the first. There is no separate mechanism for generic functions:&lt;br /&gt;
a generic function is a dependent function whose first argument is a type. Quantifying over&lt;br /&gt;
types this way raises the question of what universe the function type itself lives in, which&lt;br /&gt;
is answered by the &amp;lt;math&amp;gt;\mathrm{imax}&amp;lt;/math&amp;gt; in the formation rule and taken up on the next&lt;br /&gt;
page.&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/Foundations/Universes and Prop|Universes and Prop]] explains the&lt;br /&gt;
universe levels in the formation rule, the impredicativity of &amp;lt;code&amp;gt;Prop&amp;lt;/code&amp;gt;, and why&lt;br /&gt;
there is no type of all types.&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>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/Foundations/Terms,_types_and_judgments&amp;diff=6774</id>
		<title>Lean theorem prover/Foundations/Terms, types and judgments</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Foundations/Terms,_types_and_judgments&amp;diff=6774"/>
		<updated>2026-10-15T19:34:46Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Terms, types and judgments}}&lt;br /&gt;
{{Plebeian|Lean theorem prover/Explainers/Checking instead of convincing|Lean theorem prover/Explainers/Propositions as types}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
&lt;br /&gt;
Lean&#039;s logic is a dependent type theory. Everything in it, a number, a function, a type, a&lt;br /&gt;
proposition, a proof, is a &#039;&#039;&#039;term&#039;&#039;&#039;, and the theory consists of rules that say which terms&lt;br /&gt;
have which types. This page sets out the basic statement the rules are about, the typing&lt;br /&gt;
judgment; the contexts it is made in; the small term language that Lean&#039;s kernel actually&lt;br /&gt;
receives; the way that language writes bound variables; and the difference between checking&lt;br /&gt;
a type and inferring one. The later Foundations pages add one feature at a time to what is&lt;br /&gt;
set out here.&lt;br /&gt;
&lt;br /&gt;
== The typing judgment ==&lt;br /&gt;
&lt;br /&gt;
The basic statement of the theory is the &#039;&#039;&#039;typing judgment&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\Gamma \vdash e : A&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
read &amp;quot;in the context &amp;lt;math&amp;gt;\Gamma&amp;lt;/math&amp;gt;, the term &amp;lt;math&amp;gt;e&amp;lt;/math&amp;gt; has type &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;&amp;quot;.&lt;br /&gt;
A &#039;&#039;&#039;context&#039;&#039;&#039; is a list of variables with their types,&lt;br /&gt;
&amp;lt;math&amp;gt;x_1 : A_1, \ldots, x_n : A_n&amp;lt;/math&amp;gt;, in which each type may mention the variables&lt;br /&gt;
before it. A term is &#039;&#039;&#039;well-typed&#039;&#039;&#039; when some judgment of this form can be derived for it,&lt;br /&gt;
and only well-typed terms have a meaning.&amp;lt;ref name=&amp;quot;refman-ts&amp;quot;&amp;gt;&#039;&#039;The Lean Language&lt;br /&gt;
Reference&#039;&#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;
A judgment is not a proposition inside the theory. It is a statement about the theory, made&lt;br /&gt;
by its rules. A &#039;&#039;&#039;derivation&#039;&#039;&#039; is a finite tree of rule applications whose root is the&lt;br /&gt;
judgment in question. Lean does not store derivations. Its terms carry enough information,&lt;br /&gt;
binder types included, for a derivation to be reconstructed from the term alone, so the term&lt;br /&gt;
itself is the evidence; this is what makes a proof term something an independent program can&lt;br /&gt;
check.&amp;lt;ref name=&amp;quot;refman-ts&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Two further judgments travel with the first. &amp;lt;math&amp;gt;\Gamma \vdash e \equiv e&#039;&amp;lt;/math&amp;gt; says that&lt;br /&gt;
two terms are &#039;&#039;&#039;definitionally equal&#039;&#039;&#039;: equal by computation, without proof. And&lt;br /&gt;
&amp;lt;math&amp;gt;\Gamma\ \mathrm{ok}&amp;lt;/math&amp;gt; says that a context is well formed. A precise presentation&lt;br /&gt;
of all three for Lean, with every rule written out, is Carneiro&#039;s thesis &#039;&#039;The Type Theory of&lt;br /&gt;
Lean&#039;&#039;.&amp;lt;ref name=&amp;quot;carneiro2019&amp;quot;&amp;gt;Mario Carneiro, &#039;&#039;The Type Theory of Lean&#039;&#039;, MSc thesis,&lt;br /&gt;
Carnegie Mellon University, 2019. https://github.com/digama0/lean-type-theory/releases/tag/v1.0&amp;lt;/ref&amp;gt;&lt;br /&gt;
The thesis describes Lean 3. The Lean 4 kernel extends that theory with natural-number&lt;br /&gt;
literals, nested inductive types, primitive projections and eta for structures. Carneiro&lt;br /&gt;
notes that two of these, nested inductive types and eta for structures, change the theory&lt;br /&gt;
enough that the 2019 soundness proof does not apply to Lean 4 directly.&amp;lt;ref name=&amp;quot;lean4lean&amp;quot;&amp;gt;Mario Carneiro, &amp;quot;Lean4Lean: Verifying a Typechecker for Lean,&lt;br /&gt;
in Lean&amp;quot;, in &#039;&#039;31st International Conference on Types for Proofs and Programs (TYPES 2025)&#039;&#039;,&lt;br /&gt;
LIPIcs vol. 384, pp. 2:1–2:23, 2026. https://doi.org/10.4230/LIPIcs.TYPES.2025.2 (read in&lt;br /&gt;
the version arXiv:2403.14064v2)&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Contexts ==&lt;br /&gt;
&lt;br /&gt;
A context is built one variable at a time, and each new variable must be given a type:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{}{\cdot\ \mathrm{ok}} \qquad \frac{\Gamma\ \mathrm{ok} \qquad \Gamma \vdash A : \mathrm{Sort}\,u}{\Gamma, x : A\ \mathrm{ok}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The empty context is well formed, and a well-formed context may be extended by &amp;lt;math&amp;gt;x : A&amp;lt;/math&amp;gt; when&lt;br /&gt;
&amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; is itself a well-typed term whose type is a universe,&lt;br /&gt;
&amp;lt;math&amp;gt;\mathrm{Sort}\,u&amp;lt;/math&amp;gt;. Universes are the subject of&lt;br /&gt;
[[Lean theorem prover/Foundations/Universes and Prop|Universes and Prop]]; here it is enough&lt;br /&gt;
that &amp;quot;&amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; has type &amp;lt;math&amp;gt;\mathrm{Sort}\,u&amp;lt;/math&amp;gt; for some &amp;lt;math&amp;gt;u&amp;lt;/math&amp;gt;&amp;quot; is what&lt;br /&gt;
&amp;quot;&amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; is a type&amp;quot; means. A variable then has the type the context gives it:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{(x : A) \in \Gamma}{\Gamma \vdash x : A}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the form of the variable rule that Carneiro shows can take the place of a separate&lt;br /&gt;
weakening rule.&amp;lt;ref name=&amp;quot;carneiro2019&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The core term language ==&lt;br /&gt;
&lt;br /&gt;
Lean&#039;s surface syntax, with its notation, implicit arguments, pattern matching and tactics,&lt;br /&gt;
is not what the Lean kernel checks. The elaborator translates it into a much smaller language,&lt;br /&gt;
and that smaller language is the data type &amp;lt;code&amp;gt;Lean.Expr&amp;lt;/code&amp;gt;. Lean can print its own&lt;br /&gt;
definition:&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;
#print Lean.Expr&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean 4.34.1 prints twelve constructors:&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;
inductive Lean.Expr : Type&lt;br /&gt;
number of parameters: 0&lt;br /&gt;
constructors:&lt;br /&gt;
Lean.Expr.bvar : Nat → Lean.Expr&lt;br /&gt;
Lean.Expr.fvar : Lean.FVarId → Lean.Expr&lt;br /&gt;
Lean.Expr.mvar : Lean.MVarId → Lean.Expr&lt;br /&gt;
Lean.Expr.sort : Lean.Level → Lean.Expr&lt;br /&gt;
Lean.Expr.const : Lean.Name → List Lean.Level → Lean.Expr&lt;br /&gt;
Lean.Expr.app : Lean.Expr → Lean.Expr → Lean.Expr&lt;br /&gt;
Lean.Expr.lam : Lean.Name → Lean.Expr → Lean.Expr → Lean.BinderInfo → Lean.Expr&lt;br /&gt;
Lean.Expr.forallE : Lean.Name → Lean.Expr → Lean.Expr → Lean.BinderInfo → Lean.Expr&lt;br /&gt;
Lean.Expr.letE : Lean.Name → Lean.Expr → Lean.Expr → Lean.Expr → Bool → Lean.Expr&lt;br /&gt;
Lean.Expr.lit : Lean.Literal → Lean.Expr&lt;br /&gt;
Lean.Expr.mdata : Lean.MData → Lean.Expr → Lean.Expr&lt;br /&gt;
Lean.Expr.proj : Lean.Name → Nat → Lean.Expr → Lean.Expr&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Read as a grammar, they are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;bvar&amp;lt;/code&amp;gt;&#039;&#039;&#039;: a bound variable, written as a number (next section).&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;fvar&amp;lt;/code&amp;gt;&#039;&#039;&#039;: a free variable, named by a unique identifier. The Lean kernel creates these itself when it works under a binder; they do not occur in terms submitted to it.&amp;lt;ref name=&amp;quot;lean4lean&amp;quot; /&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;mvar&amp;lt;/code&amp;gt;&#039;&#039;&#039;: a metavariable, a hole the elaborator has yet to fill. Terms sent to the Lean kernel contain none.&amp;lt;ref name=&amp;quot;lean4lean&amp;quot; /&amp;gt; Metavariables belong to [[Lean theorem prover/System/Metavariables and unification|metavariables and unification]].&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;sort&amp;lt;/code&amp;gt;&#039;&#039;&#039;: a universe &amp;lt;math&amp;gt;\mathrm{Sort}\,u&amp;lt;/math&amp;gt;, for a universe level &amp;lt;math&amp;gt;u&amp;lt;/math&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt;&#039;&#039;&#039;: a constant, that is, a definition, theorem, axiom, inductive type, constructor or recursor in Lean&#039;s environment, its table of definitions and theorems, together with the universe levels at which it is used.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;app&amp;lt;/code&amp;gt;&#039;&#039;&#039;: application of a function to one argument. A function of several arguments is applied one argument at a time.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;lam&amp;lt;/code&amp;gt;&#039;&#039;&#039;: a function abstraction, &amp;lt;math&amp;gt;\lambda x : A.\, e&amp;lt;/math&amp;gt;, with the binder&#039;s name, its type and its body.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;forallE&amp;lt;/code&amp;gt;&#039;&#039;&#039;: a dependent function type, &amp;lt;math&amp;gt;(x : A) \to B&amp;lt;/math&amp;gt;. Implication, universal quantification and ordinary function types are all this one constructor ([[Lean theorem prover/Foundations/Dependent function types|Dependent function types]]).&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;letE&amp;lt;/code&amp;gt;&#039;&#039;&#039;: a local definition, &amp;lt;math&amp;gt;\mathrm{let}\ x : A := v;\ e&amp;lt;/math&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;lit&amp;lt;/code&amp;gt;&#039;&#039;&#039;: a natural-number literal or a string literal, stored directly rather than as a chain of constructors.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;mdata&amp;lt;/code&amp;gt;&#039;&#039;&#039;: annotations for the elaborator and printer, which the Lean kernel ignores.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;proj&amp;lt;/code&amp;gt;&#039;&#039;&#039;: the &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-th field of a value of a structure type.&lt;br /&gt;
&lt;br /&gt;
The names stored in &amp;lt;code&amp;gt;lam&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;forallE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;letE&amp;lt;/code&amp;gt;, and the&lt;br /&gt;
&amp;lt;code&amp;gt;BinderInfo&amp;lt;/code&amp;gt; that marks an argument implicit or explicit, matter only to the&lt;br /&gt;
elaborator and the printer; they play no part in type checking.&amp;lt;ref name=&amp;quot;lean4lean&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Bound variables and de Bruijn indices ==&lt;br /&gt;
&lt;br /&gt;
The Lean kernel does not identify a bound variable by its name. It uses a &#039;&#039;&#039;de Bruijn index&#039;&#039;&#039;:&lt;br /&gt;
the number of binders between the variable&#039;s occurrence and the binder that introduces&lt;br /&gt;
it, so that the nearest binder has index 0; de Bruijn&#039;s own numbering also counted the&lt;br /&gt;
introducing binder, and so started at 1.&amp;lt;ref name=&amp;quot;debruijn1972&amp;quot;&amp;gt;N. G. de Bruijn, &amp;quot;Lambda calculus notation with nameless&lt;br /&gt;
dummies, a tool for automatic formula manipulation, with application to the Church-Rosser&lt;br /&gt;
theorem&amp;quot;, &#039;&#039;Indagationes Mathematicae (Proceedings)&#039;&#039; 75(5), 1972, pp. 381–392.&lt;br /&gt;
https://doi.org/10.1016/1385-7258(72)90034-0&amp;lt;/ref&amp;gt; Lean can show the term it stores for a&lt;br /&gt;
small definition:&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;
open Lean Meta&lt;br /&gt;
&lt;br /&gt;
def apply1 (x : Nat) (f : Nat → Nat) : Nat := f x&lt;br /&gt;
&lt;br /&gt;
#eval show MetaM Unit from do&lt;br /&gt;
  let some e := (← getEnv).find? ``apply1 |&amp;gt;.bind (·.value?) | throwError &amp;quot;no value&amp;quot;&lt;br /&gt;
  IO.println (repr e)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The output is&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;
Lean.Expr.lam&lt;br /&gt;
  `x&lt;br /&gt;
  (Lean.Expr.const `Nat [])&lt;br /&gt;
  (Lean.Expr.lam&lt;br /&gt;
    `f&lt;br /&gt;
    (Lean.Expr.forallE&lt;br /&gt;
      (Lean.Name.mkNum `a._@._internal._hyg 0)&lt;br /&gt;
      (Lean.Expr.const `Nat [])&lt;br /&gt;
      (Lean.Expr.const `Nat [])&lt;br /&gt;
      (Lean.BinderInfo.default))&lt;br /&gt;
    (Lean.Expr.app (Lean.Expr.bvar 0) (Lean.Expr.bvar 1))&lt;br /&gt;
    (Lean.BinderInfo.default))&lt;br /&gt;
  (Lean.BinderInfo.default)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The body &amp;lt;code&amp;gt;f x&amp;lt;/code&amp;gt; has become &amp;lt;code&amp;gt;app (bvar 0) (bvar 1)&amp;lt;/code&amp;gt;: index 0 is the&lt;br /&gt;
nearest enclosing binder, &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt;, and index 1 the next one out, &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt;. The&lt;br /&gt;
names &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; survive only as labels on the binders. The type&lt;br /&gt;
&amp;lt;code&amp;gt;Nat → Nat&amp;lt;/code&amp;gt; appears as a &amp;lt;code&amp;gt;forallE&amp;lt;/code&amp;gt; whose bound variable has an internal&lt;br /&gt;
name and is never used: an ordinary function type is a dependent function type that does not&lt;br /&gt;
depend.&lt;br /&gt;
&lt;br /&gt;
Indices make two terms that differ only in the names of bound variables the same data apart&lt;br /&gt;
from those labels, which comparison ignores, so renaming never has to be checked, and substitution cannot capture a variable by&lt;br /&gt;
accident. When the Lean kernel needs to work under a binder it replaces the bound variable by a&lt;br /&gt;
fresh free variable carrying the binder&#039;s type, does its work, and abstracts the free&lt;br /&gt;
variable back into an index afterwards. This mixture of indices for bound variables and&lt;br /&gt;
names for free ones is called the &#039;&#039;&#039;locally nameless&#039;&#039;&#039; representation.&amp;lt;ref name=&amp;quot;lean4lean&amp;quot; /&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, &#039;&#039;Type Checking in Lean 4&#039;&#039; (online&lt;br /&gt;
book), chapters &amp;quot;Type Inference&amp;quot; and &amp;quot;Declarations&amp;quot;.&lt;br /&gt;
https://ammkrn.github.io/type_checking_in_lean4/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The rules ==&lt;br /&gt;
&lt;br /&gt;
With contexts and terms in place, the typing rules for the base language are short. Each is&lt;br /&gt;
written with its premises above the line and its conclusion below. They follow the variant&lt;br /&gt;
of Carneiro&#039;s presentation that has no weakening rule, with &amp;lt;math&amp;gt;\mathrm{Sort}\,u&amp;lt;/math&amp;gt; for&lt;br /&gt;
his &amp;lt;math&amp;gt;\mathrm{U}_u&amp;lt;/math&amp;gt;. In that variant the variable and universe rules apply in any&lt;br /&gt;
context, and the constant rule is written here in the same way; that the context is well&lt;br /&gt;
formed is checked separately, by the two rules above, and a typing judgment counts only when&lt;br /&gt;
its context is well formed.&amp;lt;ref name=&amp;quot;carneiro2019&amp;quot; /&amp;gt; Without&lt;br /&gt;
weakening, a well-typed body no longer shows that the type of its binder is a type, so the&lt;br /&gt;
abstraction rule here also requires &amp;lt;math&amp;gt;A : \mathrm{Sort}\,u&amp;lt;/math&amp;gt;, as Lean&#039;s kernel&lt;br /&gt;
does.&amp;lt;ref name=&amp;quot;lean4lean&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{}{\Gamma \vdash \mathrm{Sort}\,u : \mathrm{Sort}\,(u+1)} \qquad \frac{c.\{\bar u\} : A \text{ is in Lean&#039;s environment}}{\Gamma \vdash c.\{\bar \ell\} : A[\bar\ell/\bar u]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{\Gamma \vdash A : \mathrm{Sort}\,u \qquad \Gamma, x : A \vdash B : \mathrm{Sort}\,v}{\Gamma \vdash (x : A) \to B : \mathrm{Sort}\,(\mathrm{imax}\,u\,v)}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{\Gamma \vdash A : \mathrm{Sort}\,u \qquad \Gamma, x : A \vdash e : B}{\Gamma \vdash \lambda x : A.\, e : (x : A) \to B} \qquad \frac{\Gamma \vdash f : (x : A) \to B \qquad \Gamma \vdash a : A}{\Gamma \vdash f\,a : B[a/x]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{\Gamma \vdash v : A \qquad \Gamma \vdash e[v/x] : B}{\Gamma \vdash (\mathrm{let}\ x : A := v;\ e) : B} \qquad \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;
The first says each universe lives in the next. The second lets a constant be used at any&lt;br /&gt;
instance &amp;lt;math&amp;gt;\bar\ell&amp;lt;/math&amp;gt; of its universe parameters &amp;lt;math&amp;gt;\bar u&amp;lt;/math&amp;gt;. The next three&lt;br /&gt;
are the formation, introduction and elimination rules of the dependent function type, taken&lt;br /&gt;
up in [[Lean theorem prover/Foundations/Dependent function types|Dependent function types]].&lt;br /&gt;
The let rule types the body with the value substituted for the variable, so the body may&lt;br /&gt;
rely on what the variable stands for. The last, the &#039;&#039;&#039;conversion rule&#039;&#039;&#039;, says that a term&lt;br /&gt;
of type &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; also has every type definitionally equal to &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;. Conversion&lt;br /&gt;
is where computation enters typing, and it is the subject of&lt;br /&gt;
[[Lean theorem prover/Foundations/Definitional equality|Definitional equality]].&lt;br /&gt;
&lt;br /&gt;
Literals and projections add rules of the same kind: a natural-number literal has&lt;br /&gt;
type &amp;lt;code&amp;gt;Nat&amp;lt;/code&amp;gt;, a string literal has type &amp;lt;code&amp;gt;String&amp;lt;/code&amp;gt;, and a projection has&lt;br /&gt;
the type of the field it selects. Inductive types add their type formers, constructors and&lt;br /&gt;
recursors as constants, each with its own type&lt;br /&gt;
([[Lean theorem prover/Foundations/Inductive types and recursors|Inductive types and recursors]]).&lt;br /&gt;
&lt;br /&gt;
== Checking against inference ==&lt;br /&gt;
&lt;br /&gt;
There are two ways to use the rules. &#039;&#039;&#039;Type inference&#039;&#039;&#039; takes a context and a term and&lt;br /&gt;
computes a type for it. &#039;&#039;&#039;Type checking&#039;&#039;&#039; takes a context, a term and a proposed type, and&lt;br /&gt;
decides whether the term has that type.&lt;br /&gt;
&lt;br /&gt;
Lean&#039;s kernel is built around inference. For an application &amp;lt;code&amp;gt;f a&amp;lt;/code&amp;gt; it infers the&lt;br /&gt;
type of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt;, reduces that type until a function type &amp;lt;math&amp;gt;(x : A) \to B&amp;lt;/math&amp;gt;&lt;br /&gt;
appears, infers the type of &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;, asks whether that type is definitionally equal to&lt;br /&gt;
&amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt;, and returns &amp;lt;math&amp;gt;B[a/x]&amp;lt;/math&amp;gt;. Checking a definition or theorem with stated&lt;br /&gt;
type &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; and value &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; is done the same way: the Lean kernel infers the type&lt;br /&gt;
of &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; and asks whether it is definitionally equal to &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;. For a theorem&lt;br /&gt;
this comparison is the heart of proof checking: the inferred type is what the proof actually proves, and&lt;br /&gt;
the comparison confirms that it is what was claimed.&amp;lt;ref name=&amp;quot;bailey&amp;quot; /&amp;gt; The Lean kernel&#039;s&lt;br /&gt;
inference function also has a mode that skips the checks and only computes a type, for terms&lt;br /&gt;
already known to be well typed.&amp;lt;ref name=&amp;quot;lean4lean&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The elaborator uses both directions. &amp;lt;code&amp;gt;#check&amp;lt;/code&amp;gt; asks it to infer:&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 fun (n : Nat) =&amp;gt; n + 1&lt;br /&gt;
#check (fun n =&amp;gt; n + 1 : Int → Int)&lt;br /&gt;
#check let x := 2; x * x&lt;br /&gt;
#check (Prod.mk 1 true).2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean prints &amp;lt;code&amp;gt;fun n =&amp;gt; n + 1 : Nat → Nat&amp;lt;/code&amp;gt;, then &amp;lt;code&amp;gt;fun n =&amp;gt; n + 1 : Int → Int&amp;lt;/code&amp;gt;,&lt;br /&gt;
then &amp;lt;code&amp;gt;let x := 2; x * x : Nat&amp;lt;/code&amp;gt; (over two lines) and &amp;lt;code&amp;gt;(1, true).snd : Bool&amp;lt;/code&amp;gt;.&lt;br /&gt;
The second term is the same text as the first, but the ascription &amp;lt;code&amp;gt;(… : Int → Int)&amp;lt;/code&amp;gt;&lt;br /&gt;
gives the elaborator an &#039;&#039;&#039;expected type&#039;&#039;&#039; to check against, and it uses that type to decide&lt;br /&gt;
what &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;+&amp;lt;/code&amp;gt; mean.&amp;lt;ref name=&amp;quot;tpil&amp;quot;&amp;gt;Jeremy Avigad, Leonardo de Moura,&lt;br /&gt;
Soonho Kong and Sebastian Ullrich, &#039;&#039;Theorem Proving in Lean 4&#039;&#039;, lean-lang.org (version for&lt;br /&gt;
Lean 4.33.0), chapter 2, &amp;quot;Dependent Type Theory&amp;quot;.&lt;br /&gt;
https://lean-lang.org/theorem_proving_in_lean4/Dependent-Type-Theory/&amp;lt;/ref&amp;gt; When an expected&lt;br /&gt;
type and an inferred type disagree, elaboration fails:&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;
example : Bool := (3 : Nat)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean reports:&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;
  3&lt;br /&gt;
has type&lt;br /&gt;
  Nat&lt;br /&gt;
but is expected to have type&lt;br /&gt;
  Bool&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The message names both sides of the comparison: the type inferred for the term and the type&lt;br /&gt;
it was checked against.&lt;br /&gt;
&lt;br /&gt;
== What the judgment leaves out ==&lt;br /&gt;
&lt;br /&gt;
The core language has no implicit arguments, no type classes, no pattern matching, no&lt;br /&gt;
recursive definitions and no tactics. All of these are features of the elaborator, which&lt;br /&gt;
translates them into the terms above before the Lean kernel sees anything; a recursive function,&lt;br /&gt;
for instance, usually reaches the Lean kernel as an application of a recursor or of a well-founded&lt;br /&gt;
fixed-point combinator.&amp;lt;ref name=&amp;quot;refman-elab&amp;quot;&amp;gt;&#039;&#039;The Lean Language Reference&#039;&#039;, for Lean&lt;br /&gt;
4.34.0, lean-lang.org, 2026, sections 2.3, &amp;quot;The Kernel&amp;quot;, and 2.4, &amp;quot;Elaboration Results&amp;quot;.&lt;br /&gt;
https://lean-lang.org/doc/reference/4.34.0/Elaboration-and-Compilation/&amp;lt;/ref&amp;gt; The division&lt;br /&gt;
of labour is described on [[Lean theorem prover/System/Elaboration|Elaboration]] and&lt;br /&gt;
[[Lean theorem prover/System/The Lean kernel|The Lean kernel]].&lt;br /&gt;
&lt;br /&gt;
The rules also leave open how &amp;lt;math&amp;gt;\Gamma \vdash A \equiv B&amp;lt;/math&amp;gt; is decided. In Lean&#039;s full&lt;br /&gt;
theory that relation is undecidable, so the Lean kernel decides a slightly smaller relation;&lt;br /&gt;
[[Lean theorem prover/Foundations/Definitional equality|Definitional equality]] gives the&lt;br /&gt;
details and the sources.&amp;lt;ref name=&amp;quot;carneiro2019&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/Foundations/Dependent function types|Dependent function types]] takes&lt;br /&gt;
the three function rules above and shows what they give: implication, universal&lt;br /&gt;
quantification and polymorphism, all as one construction.&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>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/Explainers/Lean_and_physics&amp;diff=6773</id>
		<title>Lean theorem prover/Explainers/Lean and physics</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/Explainers/Lean_and_physics&amp;diff=6773"/>
		<updated>2026-10-15T19:34:45Z</updated>

		<summary type="html">&lt;p&gt;PMA Publisher: Published from the Principia Machina source&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Lean and physics}}&lt;br /&gt;
{{Lean theorem prover map}}&lt;br /&gt;
&lt;br /&gt;
A proof checker can do one thing for physics: check that a conclusion follows from&lt;br /&gt;
stated assumptions. It cannot check that the assumptions describe the world. This page says what that&lt;br /&gt;
division means in practice, how real numbers, units and approximations enter a formal statement,&lt;br /&gt;
and what has been done in Lean on physics so far. It closes with this wiki&#039;s own physics.&lt;br /&gt;
&lt;br /&gt;
== A derivation, as Lean sees it ==&lt;br /&gt;
&lt;br /&gt;
A derivation in physics starts from laws and assumptions and arrives at a result. In Lean the&lt;br /&gt;
laws and assumptions become hypotheses, the result becomes the statement, and the derivation&lt;br /&gt;
becomes the proof. Here a body is assumed to move at a constant speed &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt;, and the&lt;br /&gt;
theorem says how far it moves between two times:&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;
theorem displacement (x : Int → Int) (x₀ v : Int)&lt;br /&gt;
    (law : ∀ t, x t = x₀ + v * t) (t₁ t₂ : Int) :&lt;br /&gt;
    x t₂ - x t₁ = v * (t₂ - t₁) := by&lt;br /&gt;
  rw [law t₂, law t₁]&lt;br /&gt;
  grind&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean accepts it. What it has checked is a conditional: if the position &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt; follows&lt;br /&gt;
the law named &amp;lt;code&amp;gt;law&amp;lt;/code&amp;gt;, then the displacement is speed times elapsed time. It has not&lt;br /&gt;
checked that any body moves that way. Whether one does is a question for measurement, and no&lt;br /&gt;
proof can answer it. (The example uses whole numbers so that it runs in Lean without any library;&lt;br /&gt;
the same statement over the real numbers needs Mathlib.)&lt;br /&gt;
&lt;br /&gt;
The project this wiki records puts the point in one line: Lean proves the model, not the world&lt;br /&gt;
(see [[Principia Machina/Lean transition|the move to Lean]]).&lt;br /&gt;
&lt;br /&gt;
== What Lean can and cannot check ==&lt;br /&gt;
&lt;br /&gt;
Lean can check that every step of a derivation is valid, that no case is skipped, and that the&lt;br /&gt;
assumptions used are exactly the ones stated. An assumption that a written derivation uses without&lt;br /&gt;
saying so becomes, in Lean, a hypothesis that must be written down, or else the proof fails.&lt;br /&gt;
&lt;br /&gt;
Lean cannot check three things. It cannot check that the assumptions are true of nature; that is&lt;br /&gt;
what experiments are for. It cannot check that the symbols stand for the things they are meant to,&lt;br /&gt;
that &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt; really is a position measured from a chosen point; that link between the&lt;br /&gt;
mathematics and the world is made by people. And it cannot check that the statement proved is the&lt;br /&gt;
one that was wanted (see [[Lean theorem prover/Explainers/Stating the right thing|stating the right thing]]).&lt;br /&gt;
&lt;br /&gt;
== Real numbers ==&lt;br /&gt;
&lt;br /&gt;
Physics is written over the real numbers, and core Lean has none (see&lt;br /&gt;
[[Lean theorem prover/Explainers/A library of mathematics|a library of mathematics]]). Mathlib&lt;br /&gt;
defines them as classes of Cauchy sequences of rational numbers, sequences whose terms get and&lt;br /&gt;
stay arbitrarily close to one another.&amp;lt;ref name=&amp;quot;real&amp;quot;&amp;gt;Mathlib, source file &amp;lt;code&amp;gt;Mathlib/Basic/Real/Basic.lean&amp;lt;/code&amp;gt;, module documentation &amp;quot;Real numbers from Cauchy sequences&amp;quot;. [https://github.com/leanprover-community/mathlib4/blob/master/Mathlib/Basic/Real/Basic.lean github.com/leanprover-community/mathlib4], consulted 14 October 2026.&amp;lt;/ref&amp;gt;&lt;br /&gt;
These are the exact real numbers of mathematics, not the rounded numbers a computer calculates&lt;br /&gt;
with. A theorem about real numbers therefore says nothing by itself about the rounding errors of a&lt;br /&gt;
numerical simulation. Connecting the two takes a further statement, one that bounds the error.&lt;br /&gt;
&lt;br /&gt;
== Units ==&lt;br /&gt;
&lt;br /&gt;
On paper, units are checked by hand. In Lean they can be made part of the types, so that adding a&lt;br /&gt;
length to a time is refused before any proof begins. A small version:&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;
structure Metres where&lt;br /&gt;
  val : Int&lt;br /&gt;
&lt;br /&gt;
structure Seconds where&lt;br /&gt;
  val : Int&lt;br /&gt;
&lt;br /&gt;
instance : Add Metres := ⟨fun a b =&amp;gt; ⟨a.val + b.val⟩⟩&lt;br /&gt;
&lt;br /&gt;
def d : Metres := ⟨3⟩&lt;br /&gt;
def t : Seconds := ⟨2⟩&lt;br /&gt;
&lt;br /&gt;
#eval (d + d).val&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean prints &amp;lt;code&amp;gt;6&amp;lt;/code&amp;gt;: two lengths add. A length and a time do not:&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;
#eval (d + t).val&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean answers: failed to synthesize instance of type class, naming the missing addition of&lt;br /&gt;
&amp;lt;code&amp;gt;Metres&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Seconds&amp;lt;/code&amp;gt;. A fuller treatment exists. A 2025 preprint formalised&lt;br /&gt;
dimensional analysis in Lean: a dimension is a map from base dimensions to their exponents, dimensions&lt;br /&gt;
form a group under multiplication, physical quantities pair a value with a dimension, and the&lt;br /&gt;
framework covers SI units, fundamental constants and the Buckingham Pi theorem, with the&lt;br /&gt;
Lennard-Jones potential as a worked case.&amp;lt;ref name=&amp;quot;dims&amp;quot;&amp;gt;Maxwell P. Bobbin, Colin Jones, John Velkey and Tyler R. Josephson, &amp;quot;Formalizing dimensional analysis using the Lean theorem prover&amp;quot;, arXiv:2509.13142, 16 September 2025. [https://arxiv.org/abs/2509.13142 arxiv.org/abs/2509.13142]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Approximations ==&lt;br /&gt;
&lt;br /&gt;
Physics leans on approximations: small angles, weak fields, slow speeds. The sign &amp;quot;≈&amp;quot; means&lt;br /&gt;
nothing to Lean. An approximation has to be stated as an exact claim, usually an inequality with an&lt;br /&gt;
explicit bound on the error, or a statement about a limit. Writing it out that way shows what the&lt;br /&gt;
approximation actually assumes: how small the angle must be, and how large the error can then get.&lt;br /&gt;
That can be harder than the derivation it serves, and it is part of what formal proof adds.&lt;br /&gt;
&lt;br /&gt;
== Physics in Lean so far ==&lt;br /&gt;
&lt;br /&gt;
In 2024 Joseph Tooby-Smith introduced &#039;&#039;&#039;HepLean&#039;&#039;&#039;, a project to formalise high energy physics in&lt;br /&gt;
Lean 4, with first examples from flavour physics (CKM matrices), local anomaly cancellation and&lt;br /&gt;
Higgs physics. Its stated aims include making results easier to find, helping new results to be&lt;br /&gt;
found by artificial intelligence and automated methods, making the mathematical checking of papers easier, and new ways of&lt;br /&gt;
teaching.&amp;lt;ref name=&amp;quot;heplean&amp;quot;&amp;gt;Joseph Tooby-Smith, &amp;quot;HepLean: Digitalising high energy physics&amp;quot;, &#039;&#039;Computer Physics Communications&#039;&#039; 308 (2025), article 109457. [https://doi.org/10.1016/j.cpc.2024.109457 doi:10.1016/j.cpc.2024.109457]; preprint arXiv:2405.08863.&amp;lt;/ref&amp;gt;&lt;br /&gt;
HepLean was renamed PhysLean and later merged with Lean-QuantumInfo, a library for quantum&lt;br /&gt;
information, to form &#039;&#039;&#039;Physlib&#039;&#039;&#039;, an open-source community project under the Apache 2.0 licence&lt;br /&gt;
that depends on Mathlib. Its core library holds reviewed formalisations; a separate area with&lt;br /&gt;
lighter review accepts larger and faster contributions, including some generated by AI.&amp;lt;ref name=&amp;quot;physlib&amp;quot;&amp;gt;&#039;&#039;Physlib&#039;&#039; (README). [https://github.com/leanprover-community/physlib github.com/leanprover-community/physlib], consulted 14 October 2026; also [https://physlib.io physlib.io].&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Formalisation has also found a mistake. In 2026 Tooby-Smith formalised a widely cited paper of 2006,&lt;br /&gt;
by Maniatis, von Manteuffel, Nachtmann and Nagel, on the stability of the two-Higgs-doublet&lt;br /&gt;
potential, and found an error in its arguments that invalidates its main theorem on stability. He&lt;br /&gt;
suggests that this may be the first non-trivial error in a physics paper found through&lt;br /&gt;
formalisation.&amp;lt;ref name=&amp;quot;2hdm&amp;quot;&amp;gt;Joseph Tooby-Smith, &amp;quot;Formalizing the stability of the two Higgs doublet model potential into Lean: identifying an error in the literature&amp;quot;, arXiv:2603.08139, version 2, 20 April 2026. [https://arxiv.org/abs/2603.08139 arxiv.org/abs/2603.08139]&amp;lt;/ref&amp;gt;&lt;br /&gt;
[[Lean theorem prover/Applications/Physics in Lean|Physics in Lean]] describes this work further.&lt;br /&gt;
&lt;br /&gt;
== This wiki&#039;s physics ==&lt;br /&gt;
&lt;br /&gt;
The physics editions on this wiki, [[Hamilton&#039;s principle]], [[Noether&#039;s theorems]] and&lt;br /&gt;
[[On Physical Lines of Force]], are written in ordinary mathematics and prose, not in Lean.&lt;br /&gt;
The framework this wiki records is moving to Lean (see&lt;br /&gt;
[[Lean theorem prover/Applications/Principia Machina|Principia Machina]]). Its own account notes&lt;br /&gt;
that physics over the real numbers needs Mathlib, which it has not yet chosen to adopt&lt;br /&gt;
(see [[Principia Machina/Lean transition|the move to Lean]]).&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/Foundations/Terms, types and judgments|Terms, types and judgments]]&lt;br /&gt;
begins the technical pages, on the type theory that Lean checks.&lt;br /&gt;
[[Lean theorem prover/Applications/Physics in Lean|Physics in Lean]] describes the formal physics&lt;br /&gt;
done in Lean so far.&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>