<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Unformed Delta - programming-languages</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/programming-languages.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Sat, 09 May 2026 14:44:19 +0000</pubDate>
    <lastBuildDate>Sat, 09 May 2026 14:44:19 +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>
    
    <item>
      <title>programming language features (and optimizations)</title>
      <description>&lt;p&gt;My dream programming language would be able to express the syntax and semantics of every other programming language idiomatically. In this framing a good programming language would have few builtins&lt;sup id=&quot;fnref:builtins&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:builtins&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; but would still be able to manifest many more specific features as library definitions.&lt;/p&gt;

&lt;p&gt;I take a very general view of features. Optimizations are included in this list because in order practically exploit the fact that one programming can express the semantics of another, it must be able to match its performance&lt;sup id=&quot;fnref:why-match-performance&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:why-match-performance&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;. Thus optimizations are more or less “features” for a programming language; they help determine what the programming language can practically be used for.&lt;/p&gt;

&lt;p&gt;Maximizing which features are expressible as part of the standard library, maximizes what users are able to rewrite. If users don’t like the features the language provides in its standard library they can write their own. Such a language is maximally flexible for users.&lt;/p&gt;

&lt;p&gt;Of course, actually using custom built features comes at the expense of interoperability with the broader ecosystem. But I think it is better to give users the choice of what they need to interoperate with, rather than artificially restricting it to guarantee good interoperability&lt;sup id=&quot;fnref:go-lang&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:go-lang&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;With a sufficient floor of metaprogramming capabilities, any feature could be implemented as a builtin or as part of the standard library. I collect this list so that I can sort/consider which features are more primitive and which are the most useful to be able to reprogram. Each programming language features thus becomes both a test and an axiom for programming language expressivity.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Meta note: I went through and made a bunch of these notes public. There’s still a lot of links that aren’t public. A lot of the pages themselves are stubs and have highly varying levels of research/detail/revision put into them.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;meta-programming&quot;&gt;&lt;a href=&quot;/ncxpONlAUxwN/meta-programming&quot;&gt;meta programming&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Features enabling and enabled by metaprogramming. In some sense these are the most important because they’re what enables implementing features in terms of each other. I’m also interested in evaluating which of these features are the most irreducible.&lt;/p&gt;

&lt;p&gt;Features providing metaprogramming ability:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/NBcoqhpqPI7Q/homoiconicity&quot;&gt;homoiconicity&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/QKeZY0XKOiI6/get-runtime-string-of-compile-time-identifier&quot;&gt;get runtime string of compile-time identifier&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/xWpiR33ashZN/storing-morphological-data-with-identifiers&quot;&gt;storing morphological data with identifiers&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/8BHXL4aXonrC/compile-time-execution-of-code-assertion-baking-code&quot;&gt;compile time execution of code assertion / baking code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Features implementable by metaprogramming:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;embedded query languages, e.g. &lt;a href=&quot;/JJkIIMTFCOS2/linq&quot;&gt;LINQ&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;EDSLs in general get better as metaprogramming is better supported by a programming language&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Features kind of like metaprogramming in terms of the expressiveness they provide:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/Z1PKno9u7n88/overloadable-literals&quot;&gt;overloadable literals&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/xHw0NhTYpNsv/first-class-patterns&quot;&gt;first class patterns&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/iJCO4lkr7tNY/first-class-constructor-names&quot;&gt;first class constructor names&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/zgEZe8EylXt3/first-class-modules&quot;&gt;first class modules&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/6lzBYvOGzs77/self-types&quot;&gt;self types&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2glFqLPSCCmX/lambda-with-receiver&quot;&gt;Lambda with receiver&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/gSlE0WOhgelG/contextual-keywords&quot;&gt;contextual keywords&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/CPg3TGdClzgM/raw-identifiers&quot;&gt;raw identifiers&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/6lFX3b2wE4N9/functional-tactics-languages-for-proof-assistants&quot;&gt;functional tactics languages for proof assistants&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;working-with-generally-monadic-effects&quot;&gt;working with (generally monadic) effects&lt;/h2&gt;
&lt;p&gt;This category encapsulates language features that make working with effects easier:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;do notation&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/AfQULF8hGowN/monad-extraction&quot;&gt;monad extraction&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/aZQHyB6nrpSg/idiom-brackets&quot;&gt;idiom brackets&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;lifted versions of boolean operators&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/vwO1Erpqe9jg/dedicated-syntax-for-specific-effects&quot;&gt;dedicated syntax for specific effects&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/9prPQE3hGLjS/pattern-match-failures-are-an-effect-parsers-via-pattern-matching&quot;&gt;pattern match failures are an effect / parsers via pattern matching&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/NqZArcVKG3dy/the-runtime-system-should-be-deeply-tied-to-effect-system&quot;&gt;the runtime system should be deeply tied to effect system&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/kX1jiVaBymWv/implicit-conversions-between-effects&quot;&gt;Implicit Conversions Between Effects&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;See also: &lt;a href=&quot;/t1WnMS8gb0uo/effects&quot;&gt;Effects&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;working-with-coeffects&quot;&gt;working with coeffects&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/zOnT5C3LH1V2/method-with-notation&quot;&gt;method (/with) notation&lt;/a&gt;: relatively undeveloped, but interesting&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/0yMXYaW73qbq/coeffects-can-act-as-interpreters-for-effects&quot;&gt;coeffects can act as interpreters for effects&lt;/a&gt;: vague but interesting, method notation has some extra ideas for this&lt;/li&gt;
  &lt;li&gt;See also: &lt;a href=&quot;/mxPjuprza4i8/coeffects-consumer-effects&quot;&gt;coeffects / consumer effects&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;concurrency--distributed-programming&quot;&gt;concurrency / distributed programming&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/Nxtt5aJb3FnJ/structured-concurrency-nurseries&quot;&gt;structured concurrency / nurseries&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/lNKqn420Niw4/async-await&quot;&gt;async/await&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/yKIqGyLcKXQc/controlling-placement-of-logic-onto-specific-machines&quot;&gt;controlling placement of logic onto specific machines&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/dgmN2nnuWwRr/surfacing-semantic-information-about-distributed-behavior&quot;&gt;surfacing semantic information about distributed behavior&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/65rqGUe3XiKm/decomposing-transactional-systems&quot;&gt;decomposing transactional systems&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;working-with-data&quot;&gt;Working with data&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;/GQrJD6Vydss6/pattern-matching&quot;&gt;pattern matching&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/xHw0NhTYpNsv/first-class-patterns&quot;&gt;first class patterns&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/uDadVZnfjFD5/easily-checking-which-sum-case-is-used&quot;&gt;easily checking which sum case is used&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/iJCO4lkr7tNY/first-class-constructor-names&quot;&gt;first class constructor names&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Higher Kinded Data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Accessors / key paths / lenses:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;generic/uniform syntax for arbitrary n-functors/lenses&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;optimizations&quot;&gt;optimizations&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.ashermancinelli.com/csblog/2025-7-20-Ideal-Array-Language.html#why-does-this-matter&quot;&gt;someone’s ideal array programming language: ideas about non-uniform compute + SIMD + etc.&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/5JBEx6WCIHoE/stream-fusion&quot;&gt;stream fusion&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/mUFaDSi2Kni8/super-compilation&quot;&gt;super compilation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/zncYgtgbNa9x/equality-saturation-e-graphs&quot;&gt;equality saturation (e-graphs)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;evaluation-order&quot;&gt;evaluation order&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/2B407TlcHBup/lazy-evaluation-order-call-by-name&quot;&gt;lazy evaluation order / call by name&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/svrWWFkcUvTd/call-by-push-value&quot;&gt;call by push value&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;types&quot;&gt;types&lt;/h2&gt;
&lt;p&gt;Primitive types:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;basic types: &lt;a href=&quot;/48FOjJ7COOaX/closed-vs-open-types&quot;&gt;closed vs open types&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;/3dDEa8tnSN83/structs-record-types&quot;&gt;structs/record types&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;row types (i.e. extensible records)&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;/EdP0HQuZhLDD/coproducts-variants-enums&quot;&gt;coproducts / variants / enums&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;/XuvkOLlAiCEm/polymorphic-variants&quot;&gt;polymorphic variants&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;/EJjBX51KQ1Yy/recursive-µ-types&quot;&gt;recursive (µ) types&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;/qQ783yMXPPbQ/nominative-ν-types&quot;&gt;nominative (ν) types&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;/UeA8tt6iF5bq/algebraic-data-types&quot;&gt;algebraic data types&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;dependent types:
    &lt;ul&gt;
      &lt;li&gt;dependent product&lt;/li&gt;
      &lt;li&gt;dependent sum&lt;/li&gt;
      &lt;li&gt;interval / cubic type theory / univalence&lt;/li&gt;
      &lt;li&gt;cumulative universes&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;linear types&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Broader concepts:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/ZS3QCNHImVwZ/type-inference-list-of-methods-elaboration&quot;&gt;type inference (+ list of methods) / elaboration&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/6QbUR4dyX9Wd/completeness-checking&quot;&gt;completeness checking&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/E6doTkK2Znp0/subtypes-subtyping&quot;&gt;subtypes / subtyping&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/o8Dyaxi0ZKPK/structural-types&quot;&gt;structural types&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;gradual typing / migratory typing&lt;/li&gt;
  &lt;li&gt;pure functions, mutability
    &lt;ul&gt;
      &lt;li&gt;ST monad&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Weird/highly non-standard stuff:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/nrO5W22ORJzs/dual-type-operator&quot;&gt;dual type operator&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/6gtykpBojvhd/co-completeness-checking&quot;&gt;co-completeness checking&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/6lzBYvOGzs77/self-types&quot;&gt;self types&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2glFqLPSCCmX/lambda-with-receiver&quot;&gt;Lambda with receiver&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;probably not practical or interesting: &lt;a href=&quot;/Crx6jhw9TK7r/representing-types-as-just-namespaces&quot;&gt;representing types as just namespaces&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;typeclasses--traits&quot;&gt;&lt;a href=&quot;/iKz45KVyICwj/typeclasses-traits&quot;&gt;typeclasses / traits&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Typeclass features:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/MO8UYVyYLUgb/inserting-new-typeclasses-in-between-existing-ones&quot;&gt;inserting new typeclasses in-between existing ones&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/9cmxkzhW9IDE/override-typeclasses-or-implicits&quot;&gt;override typeclasses or implicits&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/3nJYq6q6JOEA/confluent-instance-resolution&quot;&gt;confluent instance resolution&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/TChq81fMCv9p/scoped-typeclasses-or-implicits&quot;&gt;scoped typeclasses or implicits&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/UnwAZzzngQLR/orphan-instances&quot;&gt;orphan instances&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/A2tVR0i9YcsB/givens-scala-3&quot;&gt;givens (Scala 3)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/ddgDTcVHs968/multiparameter-type-classes&quot;&gt;multiparameter type classes&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/I3MsqrihWOL9/auto-derived-type-classes&quot;&gt;auto derived type classes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;standard-library&quot;&gt;standard library&lt;/h2&gt;
&lt;p&gt;The main purpose of a standard library is to define the shared vocabulary that all programs can coordinate around. Because more primitive features are implemented as part of the “standard library”, it places an even larger burden on the design of its standard library.&lt;/p&gt;

&lt;p&gt;Properties the standard library should have:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;layers of primitiveness: that allow giving up progressive amounts of interoperability for the ability to redefine larger parts of the language&lt;/li&gt;
  &lt;li&gt;facilitate migrations between standard library types to make the decision to include/not-include various things as unimpactful as possible&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Must haves:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/9q45qzJgPaIz/type-safe-dates-times-durations&quot;&gt;type safe dates/times/durations&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;OSString type&lt;/li&gt;
  &lt;li&gt;theorem proving:
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;/ZMtfpDsFf117/explicitly-unordered-containers&quot;&gt;explicitly unordered containers&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Things to consider adding to a type class hierarchy beyond what Haskell has:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/RoZrSQ0VADCE/partial-equality-ordering&quot;&gt;Partial Equality / Ordering&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/qy3O2KrKgJYU/selective&quot;&gt;Selective&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/nlCzhqXrt5fN/discriminators-contravariant-functor-hierarchy-on-sorting&quot;&gt;Discriminators (contravariant functor hierarchy, O(n) sorting!)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;modules--scoping&quot;&gt;modules / scoping&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/zgEZe8EylXt3/first-class-modules&quot;&gt;first class modules&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/xWpiR33ashZN/storing-morphological-data-with-identifiers&quot;&gt;storing morphological data with identifiers&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/x7PUneHXkXAH/flexible-scope-resolution-with-article-like-functions-keywords&quot;&gt;flexible scope resolution with article like functions/keywords&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;limited / more local scopes:
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;/F4TTPLipKTSS/local-type-declarations&quot;&gt;local type declarations&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;/TChq81fMCv9p/scoped-typeclasses-or-implicits&quot;&gt;scoped typeclasses or implicits&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;/mpYtVwtsssAa/defining-functions-global-variables-over-a-limited-scope&quot;&gt;defining functions/global variables over a limited scope&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;lifetimes--scoping&quot;&gt;lifetimes / scoping&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/dRm9QXhhosuz/raii&quot;&gt;RAII&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/dn7y1F0E7gIR/defer-statement&quot;&gt;defer statement&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/0FSraZkV6OJ7/deconstructors-deinitializers&quot;&gt;deconstructors / deinitializers&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;lifetime annotations ala rust&lt;/li&gt;
  &lt;li&gt;borrow checker&lt;/li&gt;
  &lt;li&gt;move semantics (e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;consume&lt;/code&gt; in Swift)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;control-flow&quot;&gt;control flow&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/KI7CnXtB4sYS/implementing-control-flow-as-library-functions&quot;&gt;implementing control flow as library functions&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;loops:
    &lt;ul&gt;
      &lt;li&gt;for loops&lt;/li&gt;
      &lt;li&gt;foreach loops&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;/sSiTDOesjtyI/while-loop&quot;&gt;while loop&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;/n4l4TUphkC42/until-loop&quot;&gt;until loop&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;do while loop&lt;/li&gt;
      &lt;li&gt;unconditional forever loop&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;/4hDfrbOYfERt/do-while-with-block-loop&quot;&gt;do while with block loop&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/JwjtjzAsEbm9/if-statements&quot;&gt;if statements&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/Wdj1LjlC97rO/switch-case-analysis-statements&quot;&gt;switch / case analysis statements&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/T2LKKGgNsdGW/allowing-statements-to-be-used-as-expressions&quot;&gt;allowing statements to be used as expressions&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/dn7y1F0E7gIR/defer-statement&quot;&gt;defer statement&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;try { … } catch { … }&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dis-preferred:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/KAvQgJqAafP2/with-using-blocks&quot;&gt;with/using blocks&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/VeqfqfVzppXi/try-finally&quot;&gt;try { … } finally { … }&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;code-location--relocating-code&quot;&gt;code location / relocating code&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;removing indentation from nested code structures&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/DB3xJAOpe0Bf/unit-tests-can-be-co-located-with-code&quot;&gt;unit tests can be co-located with code&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;get calling function location&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/dn7y1F0E7gIR/defer-statement&quot;&gt;defer statement&lt;/a&gt; is useful for putting de-initialization next to initialization logic&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;testing&quot;&gt;testing&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/DB3xJAOpe0Bf/unit-tests-can-be-co-located-with-code&quot;&gt;unit tests can be co-located with code&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;inspection testing&lt;/li&gt;
  &lt;li&gt;unit tests can be discovered at compile time / in the IDE without necessarily running arbitrary code&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;see-also&quot;&gt;See also&lt;/h1&gt;
&lt;ul&gt;
  &lt;li&gt;programming language benchmarks for ways of testing what features are useful for programming tasks&lt;/li&gt;
  &lt;li&gt;my programming language for features that are core enough to warrant consideration as primitives for my programming language design project&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:builtins&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Features implemented with special support in the compiler. Also sometimes called intrinsics (e.g. by the rust compiler) &lt;a href=&quot;#fnref:builtins&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:why-match-performance&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Even though the lambda calculus is Turing complete and can technically implement arbitrary floating point arithmetic, no one is seriously trying to train neural networks using it. &lt;a href=&quot;#fnref:why-match-performance&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:go-lang&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;This is my largest problem with the philosophy behind the design of go-lang. While true that a simpler language leads to more uniform programming styles, it also makes it harder to build shared abstractions. &lt;a href=&quot;#fnref:go-lang&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
      <pubDate>Fri, 24 Apr 2026 00:12:00 +0000</pubDate>
      <link>https://unformeddelta.wiki/dCtl1IFIC8VF/programming-language-features-and-optimizations</link>
      <guid isPermaLink="true">https://unformeddelta.wiki/dCtl1IFIC8VF/programming-language-features-and-optimizations</guid>
      
      <category>inkhaven</category>
      
      <category>recommended</category>
      
      <category>programming-languages</category>
      
    </item>
    
    <item>
      <title>an expressive programming language</title>
      <description>&lt;p&gt;&lt;em&gt;Thanks to Alok Singh for the rough format and inspiration to write this post.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I tried naming as may programming languages as I could and came up with these before I got bored: C Rust Perl Bash Zsh Fish Zig C++ D Visual Basic Prolog Racket Elisp VimScript Lua Ruby Idris Agda Rocq C# F# F* Clojure Kotlin Scala Java ECMAScript TypeScript Raku Python OCaml Standard ML Jai Pony koka Cyclone Unison Swift Objective C Piet J APL Brainfuck Purescript Elm JIF (Java Information Flow) moss LLVM CUDA MLIR x86 ARM MIPS&lt;/p&gt;

&lt;p&gt;But Haskell is my favorite.&lt;/p&gt;

&lt;h2 id=&quot;why&quot;&gt;Why?&lt;/h2&gt;
&lt;p&gt;It’s expressive. Things that other languages must implement as builtin features, can and are implemented as libraries. This gives you the power to customize the language however you see fit.&lt;/p&gt;

&lt;p&gt;In most languages the and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;amp;&amp;amp;&lt;/code&gt; operator needs special compiler treatment to ensure that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false &amp;amp;&amp;amp; doSomethingExpensive()&lt;/code&gt; doesn’t evaluate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;doSomethingExpensive()&lt;/code&gt; unnecessarily. In Haskell laziness gives you this for free. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;amp;&amp;amp;&lt;/code&gt; operator can be defined in the standard library just like any other function without any special compiler treatment:&lt;/p&gt;
&lt;div class=&quot;language-haskell 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;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Bool&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Bool&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Bool&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;True&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;False&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you evaluate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;False &amp;amp;&amp;amp; someExpensiveComputation&lt;/code&gt;, laziness means that the second clause never evaluates &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;someExpensiveComputation&lt;/code&gt;, the computation only needs to see that the first argument is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;False&lt;/code&gt; to produce its result.&lt;/p&gt;

&lt;p&gt;But there’s a problem with laziness. It makes it hard to predict what order things will get evaluated in, because you need to look at the implementation of your function to know what order its arguments will be evaluated in. For IO like reading a file or printing to the console you need a way to guarantee the order things run in. Haskell adopted &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;do&lt;/code&gt; notation and monads for this purpose. But it turns out that it’s a very general abstraction that generalizes exception handling, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt;, generators (e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yield&lt;/code&gt;), and many other things.&lt;/p&gt;

&lt;p&gt;But so far we’ve only listed two language features: laziness and monads. By “avoiding success at all costs” Haskell has accumulated decades of experimental language features produced by programming languages research. This allows Haskell to absorb features and express patterns invented in pretty much any other programming language.&lt;/p&gt;

&lt;p&gt;RSpec is a Ruby library for writing unit tests. It lets you describe the behaviors of your program using near natural language syntax.&lt;/p&gt;
&lt;div class=&quot;language-ruby 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;no&quot;&gt;RSpec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Order&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;sums the prices of its line items&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;order&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Order&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add_entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LineItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:item&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:price&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Money&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:USD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add_entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LineItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:item&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:price&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Money&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;2.22&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:USD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:quantity&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Money&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;5.55&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:USD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Without even needing to resort to &lt;a href=&quot;https://wiki.haskell.org/Template_Haskell&quot;&gt;macros&lt;/a&gt; HSpec embeds a very similar syntax:&lt;/p&gt;
&lt;div class=&quot;language-haskell 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;n&quot;&gt;spec&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Spec&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;spec&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;sums the prices of its line items&quot;&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;kr&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;order&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderFromEntries&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;LineItem&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;price&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Money&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currency&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;USD&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;quantity&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;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;LineItem&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;price&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Money&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;2.22&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currency&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;USD&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;quantity&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;orderTotal&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;order&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shouldBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Money&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;5.55&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currency&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;USD&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There’s even database libraries like squeal that embed SQL syntax in a type safe way without needing macros:&lt;/p&gt;
&lt;div class=&quot;language-haskell 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;n&quot;&gt;getUsers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Statement&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;DB&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;User&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;getUsers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;query&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;select_&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;u&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;userName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:*&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;#&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;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;userEmail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;table&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;innerJoin&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;table&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;emails&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;u&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.==&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;#&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;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Personally that’s too many operators and too complicated types even for me, but I like the idea that it’s possible in the programming language I use. Maybe someday I’ll have a problem for which that complexity is worth it. The thing that I love the most about Haskell is that people do these things even if its not worth it.&lt;/p&gt;

&lt;p&gt;Through clever encodings, it’s even possible to do anything you can do in a dependently typed programming language/proof assistant like Lean and Rocq with &lt;a href=&quot;https://hackage.haskell.org/package/singletons&quot;&gt;a little bit extra boilerplate&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;the-languages-with-features-i-envy&quot;&gt;The languages with features I envy&lt;/h2&gt;
&lt;p&gt;When writing Haskell, there’s still some languages left with features that I envy:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Any programming language with fast compile times: I used to work at a company with a ~2 million lines of code Haskell codebase. It took 3-4 hours to compile from scratch.&lt;/li&gt;
  &lt;li&gt;True dependently typed programming languages (like Lean, Idris, Agda, Rocq) are way more ergonomic for any kind of advanced type level programming. Haskell’s &lt;a href=&quot;https://ghc.serokell.io/dh&quot;&gt;working on becoming Dependent Haskell&lt;/a&gt;, but it’s still a really long way off.&lt;/li&gt;
  &lt;li&gt;Languages with better macro systems, mostly Racket, who’s macro system is powerful enough to implement &lt;a href=&quot;https://lexi-lambda.github.io/hackett/&quot;&gt;Hackett&lt;/a&gt;, a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#lang&lt;/code&gt; pragma that more or less implements Haskell in Racket.&lt;/li&gt;
  &lt;li&gt;Rust: while Haskell has linear types, they are not nearly as mature as Rust’s uniqueness types for resource management.&lt;/li&gt;
  &lt;li&gt;Prolog: logic programming can be more declarative than laziness.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My dream is a programming language that can subsume all of these features.&lt;/p&gt;

&lt;h2 id=&quot;epilogue&quot;&gt;Epilogue&lt;/h2&gt;
&lt;p&gt;I’m not sure there is a perfect programming language, nor will there probably ever be. Perhaps someday there’ll be a programming language that combines all the features I like. &lt;a href=&quot;https://alok.github.io/lean-pages/perfectable-lean/&quot;&gt;Perhaps Lean will be perfected&lt;/a&gt;. But who knows, for now Haskell is still my favorite programming language.&lt;/p&gt;
</description>
      <pubDate>Wed, 08 Apr 2026 05:43:00 +0000</pubDate>
      <link>https://unformeddelta.wiki/GEbCU1EGqkQU/an-expressive-programming-language</link>
      <guid isPermaLink="true">https://unformeddelta.wiki/GEbCU1EGqkQU/an-expressive-programming-language</guid>
      
      <category>inkhaven</category>
      
      <category>haskell</category>
      
      <category>recommended</category>
      
      <category>programming-languages</category>
      
    </item>
    
  </channel>
</rss>
