<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://invarians.org/index.php?action=history&amp;feed=atom&amp;title=Lean_theorem_prover%2FSystem%2FMonads_and_do-notation</id>
	<title>Lean theorem prover/System/Monads and do-notation - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://invarians.org/index.php?action=history&amp;feed=atom&amp;title=Lean_theorem_prover%2FSystem%2FMonads_and_do-notation"/>
	<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/System/Monads_and_do-notation&amp;action=history"/>
	<updated>2026-10-21T08:23:23Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.46.2</generator>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/System/Monads_and_do-notation&amp;diff=6797&amp;oldid=prev</id>
		<title>PMA Publisher: Published from the Principia Machina source</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/System/Monads_and_do-notation&amp;diff=6797&amp;oldid=prev"/>
		<updated>2026-10-15T19:35:22Z</updated>

		<summary type="html">&lt;p&gt;Published from the Principia Machina source&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw-interface=&quot;&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 19:35, 15 October 2026&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l1&quot;&gt;Line 1:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;{{DISPLAYTITLE:Monads and do-notation}}&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;{{DISPLAYTITLE:Monads and do-notation}}&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;{{Plebeian|Lean theorem prover/Explainers/Programs and proofs in one language}}&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;{{Plebeian|Lean theorem prover/Explainers/Programs and proofs in one language}}&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;{{Lean theorem prover map}}&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Lean is a purely functional language: a function&amp;#039;s result depends only on its arguments,&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Lean is a purely functional language: a function&amp;#039;s result depends only on its arguments,&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;

&lt;!-- diff cache key pma_cutover_20261020t051351z-soft_:diff:1.41:old-6590:rev-6797:php=table --&gt;
&lt;/table&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=6590&amp;oldid=prev</id>
		<title>PMA Publisher: Published from the Principia Machina source</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/System/Monads_and_do-notation&amp;diff=6590&amp;oldid=prev"/>
		<updated>2026-10-14T18:01:10Z</updated>

		<summary type="html">&lt;p&gt;Published from the Principia Machina source&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{DISPLAYTITLE:Monads and do-notation}}&lt;br /&gt;
{{Plebeian|Lean theorem prover/Explainers/Programs and proofs in one language}}&lt;br /&gt;
&lt;br /&gt;
Lean is a purely functional language: a function&amp;#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 &amp;#039;&amp;#039;&amp;#039;effects&amp;#039;&amp;#039;&amp;#039; as values, using &amp;#039;&amp;#039;&amp;#039;monads&amp;#039;&amp;#039;&amp;#039;, and provides&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;do-notation&amp;#039;&amp;#039;&amp;#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 &amp;#039;&amp;#039;The Lean Language Reference&amp;#039;&amp;#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;, &amp;#039;&amp;#039;Proceedings of the ACM on Programming Languages&amp;#039;&amp;#039; 6 (ICFP), article 109, August 2022, 28 pp. doi:[https://doi.org/10.1145/3547640 10.1145/3547640]; author&amp;#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, &amp;#039;&amp;#039;Functional Programming in Lean&amp;#039;&amp;#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 &amp;#039;&amp;#039;&amp;#039;nested action&amp;#039;&amp;#039;&amp;#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&amp;#039;s&lt;br /&gt;
&amp;#039;&amp;#039;Functional Programming in Lean&amp;#039;&amp;#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, &amp;#039;&amp;#039;Functional Programming in Lean&amp;#039;&amp;#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&amp;#039;s do-notation provides sequencing and little more. Ullrich and de Moura&amp;#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&amp;#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&amp;#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&amp;#039;s own implementation differs in its details from the paper&amp;#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;, &amp;#039;&amp;#039;The Lean Language Reference&amp;#039;&amp;#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&amp;#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&amp;#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&amp;#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>
</feed>