<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Unformed Delta - lean</title>
    <description>A place to collect the things I learn, figure out, or find interesting.
</description>
    <link>https://unformeddelta.wiki/</link>
    <atom:link href="https://unformeddelta.wiki/feed/lean.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Tue, 28 Apr 2026 06:51:04 +0000</pubDate>
    <lastBuildDate>Tue, 28 Apr 2026 06:51:04 +0000</lastBuildDate>
    <generator>Jekyll v3.10.0</generator>
    
    <item>
      <title>First impressions of Lean</title>
      <description>&lt;p&gt;Since reading &lt;a href=&quot;https://alok.github.io/lean-pages/perfectable-lean/&quot;&gt;a perfectable programming language&lt;/a&gt; I started getting the itch to try actual dependently typed programming languages again.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/GEbCU1EGqkQU/an-expressive-programming-language&quot;&gt;Haskell is my favorite programming language&lt;/a&gt; because it provides one of the strongest type system but my most common frustrations in Haskell are from not having access to stronger types. &lt;a href=&quot;https://ghc.serokell.io/dh&quot;&gt;Dependent types in Haskell&lt;/a&gt; are an active research project, but still far away. So when I’ve wanted more power I’ve had to make do with Coq (now Roqc) plus a little bit of dabbling in Idris and Agda.&lt;/p&gt;

&lt;p&gt;In my usual fashion, I dove right in without reading the tutorial, hoping my experience with similar languages would take me far enough.&lt;/p&gt;

&lt;h2 id=&quot;first-steps&quot;&gt;First steps&lt;/h2&gt;
&lt;p&gt;I started out by just typing out some definitions.&lt;/p&gt;
&lt;div class=&quot;language-lean highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; : &lt;span class=&quot;n&quot;&gt;Int&lt;/span&gt; := &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; : &lt;span class=&quot;kt&quot;&gt;Type&lt;/span&gt; := &lt;span class=&quot;n&quot;&gt;Int&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;z&lt;/span&gt; : &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; := &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I was surprised that the last example failed to compile:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;▼ 2:14-2:15: error:
failed to synthesize instance of type class
  OfNat x 1
numerals are polymorphic in Lean, but the numeral &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt; cannot be used in a context where the expected type is
  x
due to the absence of the instance above&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This was fixable by using:&lt;/p&gt;
&lt;div class=&quot;language-lean highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; : &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; := (&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; : &lt;span class=&quot;n&quot;&gt;Int&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I had a bit of trouble figuring out that Eq.refl needed an argument, but nicely &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_&lt;/code&gt; allows inferring the type:&lt;/p&gt;
&lt;div class=&quot;language-lean highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; : &lt;span class=&quot;kt&quot;&gt;Type&lt;/span&gt; := &lt;span class=&quot;n&quot;&gt;Int&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; : &lt;span class=&quot;n&quot;&gt;Int&lt;/span&gt; := &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;z&lt;/span&gt; : &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Int&lt;/span&gt; := &lt;span class=&quot;n&quot;&gt;Eq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;refl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Of course, I later discovered that there’s a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rfl&lt;/code&gt; tactic that allows avoiding this boilerplate.&lt;/p&gt;

&lt;p&gt;I also ran into some other surprising sharp edges:&lt;/p&gt;
&lt;div class=&quot;language-lean highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;decrement&lt;/span&gt; : &lt;span class=&quot;n&quot;&gt;Nat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Nat&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Doesn’t compile but this does:&lt;/p&gt;
&lt;div class=&quot;language-lean highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;decrement&lt;/span&gt; : &lt;span class=&quot;n&quot;&gt;Nat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Nat&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It’s cool that it’s possible to pattern match on syntax like this, but it’s annoying that it’s a bit inconsistent.&lt;/p&gt;

&lt;h2 id=&quot;lambda-calculus-confluence&quot;&gt;Lambda Calculus Confluence&lt;/h2&gt;
&lt;p&gt;Basic syntax out of the way, I started implanting the simply typed lambda calculus.&lt;/p&gt;

&lt;p&gt;Debrujin indexes:&lt;/p&gt;
&lt;div class=&quot;language-lean highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;inductive&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Term&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt; : &lt;span class=&quot;n&quot;&gt;Nat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Term&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lam&lt;/span&gt; : &lt;span class=&quot;n&quot;&gt;Term&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Term&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;app&lt;/span&gt; : &lt;span class=&quot;n&quot;&gt;Term&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Term&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Term&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Of course, I can’t implement a full interpreter because I can’t solve the halting problem, so I implement single step semantics:&lt;/p&gt;
&lt;div class=&quot;language-lean highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;step_cbn&lt;/span&gt; (&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; : &lt;span class=&quot;n&quot;&gt;Term&lt;/span&gt;) : &lt;span class=&quot;n&quot;&gt;Maybe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Term&lt;/span&gt; :=
  &lt;span class=&quot;k&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Term&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lam&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Maybe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nothing&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Term&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Maybe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nothing&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Term&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;app&lt;/span&gt; (&lt;span class=&quot;n&quot;&gt;Term&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lam&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;body&lt;/span&gt;) &lt;span class=&quot;n&quot;&gt;t2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;Maybe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;just&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shift_down&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; (&lt;span class=&quot;n&quot;&gt;subst&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; (&lt;span class=&quot;n&quot;&gt;shift&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t2&lt;/span&gt;) &lt;span class=&quot;n&quot;&gt;body&lt;/span&gt;)
  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Term&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;app&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;step_cbn&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Maybe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;just&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Maybe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;just&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Term&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;app&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t2&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Maybe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nothing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;step_cbn&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Maybe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nothing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Maybe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nothing&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Maybe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;just&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Maybe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;just&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Term&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;app&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There’s several different evaluation orders for the simply typed lambda calculus. I recall that Church-Rosser theorem proves that when a term converges, it always converges to the same term regardless of evaluation order.&lt;/p&gt;

&lt;div class=&quot;language-lean highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;inductive&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ConvergesCBN&lt;/span&gt; : &lt;span class=&quot;n&quot;&gt;Term&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Term&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; : &lt;span class=&quot;n&quot;&gt;step_cbn&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Maybe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nothing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ConvergesCBN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;step&lt;/span&gt;  : &lt;span class=&quot;n&quot;&gt;step_cbn&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Maybe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;just&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ConvergesCBN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ConvergesCBN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;inductive&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ConvergesCBV&lt;/span&gt; : &lt;span class=&quot;n&quot;&gt;Term&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Term&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; : &lt;span class=&quot;n&quot;&gt;step_cbv&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Maybe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nothing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ConvergesCBV&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;step&lt;/span&gt; : &lt;span class=&quot;n&quot;&gt;step_cbv&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Maybe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;just&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ConvergesCBV&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ConvergesCBV&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;noncomputable&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cbv_implies_cbn_convergence&lt;/span&gt; :
  &lt;span class=&quot;n&quot;&gt;ConvergesCBV&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ConvergesCBN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; := &lt;span class=&quot;n&quot;&gt;sorry&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I didn’t end up making that much progress. I also tried big step semantics, but that ended up not being much easier, and after Codex and Claude found several holes in my definitions, that made the theorem unprovable as stated, I gave up.&lt;/p&gt;

&lt;h2 id=&quot;ecosystem&quot;&gt;Ecosystem&lt;/h2&gt;
&lt;p&gt;Lean’s ecosystem still feels fairly immature.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;parser libraries: I use megaparsec/attoparsec in Haskell
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;https://github.com/fgdorais/lean4-parser&quot;&gt;fgdorais/lean4-parser&lt;/a&gt;: this provides decent parser combinators, but none of the fancier recovery or error handling offered by megaparsec.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;C bindings are possible, but you’ll likely need to implement them yourself&lt;/li&gt;
  &lt;li&gt;effects: monad transformers are the default way of representing effects; usable, but a far cry from Haskell’s wide variety&lt;/li&gt;
  &lt;li&gt;tooling quite good, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lean --server&lt;/code&gt; provides top good tooling even in Neovim. I appreciated this compared with using&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;a-meetup&quot;&gt;A meetup&lt;/h2&gt;
&lt;p&gt;People writing Lean seem to be very dedicated to verifying things for verifications sake. I love that. I think this is the standard for what should be demanded of our libraries and tools.&lt;/p&gt;

&lt;p&gt;I’m curious to try diving into metaprogramming, which I hear is pretty good, but that’ll have to wait for another day.&lt;/p&gt;
</description>
      <pubDate>Tue, 28 Apr 2026 06:49:00 +0000</pubDate>
      <link>https://unformeddelta.wiki/Ayg9N1mAL7dd/first-impressions-of-lean</link>
      <guid isPermaLink="true">https://unformeddelta.wiki/Ayg9N1mAL7dd/first-impressions-of-lean</guid>
      
      <category>inkhaven</category>
      
      <category>lean</category>
      
      <category>programming-languages</category>
      
    </item>
    
  </channel>
</rss>
