<?xml version="1.0" encoding="utf-8" standalone="yes"?>

<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Thomas Letan's Blog</title>
    <link>https://soap.coffee/~lthms/posts/</link>
    <description>Blogposts in Thomas Letan's Website</description>
    <atom:link href="https://soap.coffee/~lthms/posts/index.xml" rel="self"
               type="application/rss+xml" />
    
    
    <item>
      <title>What happened in February 2026?</title>
      <link>https://soap.coffee/~lthms/posts/february-2026.html</link>
      <guid>https://soap.coffee/~lthms/posts/february-2026.html</guid>
      <pubDate>March 8, 2026</pubDate>
      <description>
        
        &lt;h1&gt;What happened in February 2026?&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/meta.html&quot; class=&quot;tag hover-sky&quot; marked=&quot;&quot;&gt;meta&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/vibecoding.html&quot; class=&quot;tag hover-peach&quot; marked=&quot;&quot;&gt;vibecoding&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;Time flies. February was a productive month, and I got many things done—with
the help of my &lt;a href=&quot;https://github.com/letan-assistant&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;coding assistant&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, that is. I haven’t joined the “I
haven’t written a single line of code for quite some time” flock just yet, but
I am close. At the same time, I feel like I’m still locked in beginner mode.
Like I have still to &lt;em&gt;really&lt;/em&gt; tap into what agentic tools like Claude Code have
to offer.&lt;/p&gt;
&lt;p&gt;For now, the tools may have changed, but the journeys feel somewhat the same as
they used to a few months back. It’s a strange feeling, and I am still trying
to wrap my head around it.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Yet Another Claude Code Wrapper&lt;/h2&gt;
&lt;p&gt;In my previous retrospective, I mentioned CeCe and Vee. The former is a plugin
for turning Anthropic’s model into a “modal” agent that I had vibe “prompted”
with Claude itself. The latter was a second take at the exact same concept.&lt;/p&gt;
&lt;p&gt;A month later, Vee has evolved quite a bit, to a point where the “modal”
aspect of the project lost the front seat. More precisely, Vee has become a
session multiplexer for Claude Code, with built-in support for spawning it in
ephemeral containers with &lt;code class=&quot;hljs&quot;&gt;--dangerously-skip-permissions&lt;/code&gt; enabled. It is also
a playground for me to experiment with the agent. For instance, I built a
feedback system where I can point it to the good and bad things it’s doing—my
feedbacks get saved in a SQLite database and appended in the system prompt
during the next sessions. I’ve also tried to set up a knowledge base with
embeddings. Both approaches have their benefits, but I don’t think I have clear
evidence that they can be a game changer.&lt;/p&gt;
&lt;p&gt;You may remember Vee started out of my frustration to losing control of CeCe’s
internals. Well, Claude Code took over Vee’s codebase quite quickly as well.
But this time, the output was a lot more satisfying. This time, I leaned into
playing the role of a Tech Lead and a QA tester. Seeing the project taking
shape and the tool I wanted becoming a reality that quickly has clear upsides.
I also find it interesting that I have both a fairly good understanding of how
the software works overall—I called most of the architectural choices—&lt;em&gt;and&lt;/em&gt;
very little insight on how the code itself is written. It reminds me of
&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$WORK&lt;/span&gt;&lt;/code&gt;, where I am involved in some projects without being a direct IC.&lt;/p&gt;
&lt;h2&gt;I Built Myself a Cloudlab&lt;/h2&gt;
&lt;p&gt;In the first half of the month, a colleague of mine was tasked with building
“staging environments &lt;em&gt;à la demande&lt;/em&gt;” for the engineers working on
&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$WORK&lt;/span&gt;&lt;/code&gt;’s Next Big Thing™. Their answer was a managed Kubernetes cluster
and a bunch of Helm charts—and a small CLI tool to deploy the latter onto the
former. A few hours later, I started building myself a &lt;a href=&quot;https://k3s.io&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;k3s&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; cluster. &lt;em&gt;It’ll be
a fun way to get familiar with the stack,&lt;/em&gt; I thought. What emerged almost
resembles a managed cluster of sorts. I called it &lt;a href=&quot;https://github.com/lthms/elsa&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;elsa&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, and it now
hosts &lt;a href=&quot;https://github.com/lthms/cloud-lab&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;this very website along with a few other self-hosted services I had
under my radar for a while&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;&lt;p class=&quot;markdown-alert-title&quot;&gt;&lt;svg class=&quot;octicon octicon-info mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;Note&lt;/p&gt;&lt;p&gt;Yes, GitHub Pages and the like remain a better, cheaper, superior even way to
host my website. But where is the fun in that? 😁&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;This may come as a surprise, considering &lt;a href=&quot;/~lthms/posts/i-cannot-ssh-into-my-server-anymore.html&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;I had migrated my website to a new
setup called &lt;code class=&quot;hljs&quot;&gt;tinkerbell&lt;/code&gt;&lt;/a&gt; barely &lt;em&gt;a month ago&lt;/em&gt;. Well, fret not. The
little VPS sure has been retired early, but its legacy has not been lost.
&lt;code class=&quot;hljs&quot;&gt;elsa&lt;/code&gt; was built upon the very same tools (Terraform, CoreOS, and Ignition) and
promise I got hooked on a month ago: that there is freedom in designing a
system whose &lt;em&gt;destruction&lt;/em&gt; is a non-event. If anything, working on &lt;code class=&quot;hljs&quot;&gt;elsa&lt;/code&gt; has
only &lt;em&gt;deepened&lt;/em&gt; my understanding—and my appreciation—of what Fedora has been
pushing for with CoreOS.&lt;/p&gt;
&lt;p&gt;I really, &lt;em&gt;really&lt;/em&gt; want to publish an article about &lt;code class=&quot;hljs&quot;&gt;elsa&lt;/code&gt;. I yet have to find
my angle, though. Funny story, the first couple of paragraphs of this section
were initially intended to be its introduction, until I grew dissatisfied with
them and decided to repurpose them. Which means I need to restart from scratch.
😆&lt;/p&gt;
&lt;p&gt;Anyway, as I was making good progress on &lt;code class=&quot;hljs&quot;&gt;elsa&lt;/code&gt;, I ran into some good
opportunities to contribute to some open source software. I opened two bugfix
PRs over the course of my journey: one for the &lt;a href=&quot;https://github.com/BetterStackHQ/terraform-provider-better-uptime/pull/178&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;official BetterStack’s
Terraform provider&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, and the other for &lt;a href=&quot;https://github.com/vultr/external-dns-vultr-webhook/pull/10&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;external-dns’ Vultr webhook
sidecar&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. That was pretty cool! I want to do that more often.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;We are almost a third into March already, and the month is clearly following
the trend set by its predecessor. As such, I expect to have plenty to write
about in a month’s time, meaning I should be able to keep up with publishing
these retrospective pieces for a while. At least, I hope so!&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>Teaching Firefox About slack:// URLs</title>
      <link>https://soap.coffee/~lthms/posts/teaching-firefox-about-slack.html</link>
      <guid>https://soap.coffee/~lthms/posts/teaching-firefox-about-slack.html</guid>
      <pubDate>February 19, 2026</pubDate>
      <description>
        
        &lt;h1&gt;Teaching Firefox About &lt;code class=&quot;hljs&quot;&gt;slack://&lt;/code&gt; URLs&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/releases.html&quot; class=&quot;tag hover-lemon&quot; marked=&quot;&quot;&gt;releases&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;I’ve been using Slack at &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$WORK&lt;/span&gt;&lt;/code&gt; for the past 5 (!) years. I don&apos;t know
why, but it looks like Firefox does not know what to do with the &lt;code class=&quot;hljs&quot;&gt;slack://&lt;/code&gt;
URLs out of the box&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Try logging in Slack when your browser does not let Slack know
authentication concluded successfully. The worst thing? Sometimes it works,
sometimes it doesn’t. &lt;/span&gt;
&lt;/span&gt;. It could be an issue on my side—wouldn’t be the
first time!—but in case you are suffering from the same issue, I have found
that I can provision my laptop with a so-called Firefox policy to fix this
annoyance.&lt;/p&gt;
&lt;div class=&quot;markdown-alert markdown-alert-caution&quot;&gt;&lt;p class=&quot;markdown-alert-title&quot;&gt;&lt;svg class=&quot;octicon octicon-stop mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;Caution&lt;/p&gt;&lt;p&gt;Firefox only supports a single &lt;code class=&quot;hljs&quot;&gt;policies.json&lt;/code&gt; file. If you happen to already
have one installed at &lt;code class=&quot;hljs&quot;&gt;/usr/lib/firefox/distribution/policies.json&lt;/code&gt;, you will
need to merge the policies manually.&lt;/p&gt;
&lt;/div&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-json&quot;&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;&quot;policies&quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;&quot;Handlers&quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;schemes&quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;hljs-attr&quot;&gt;&quot;slack&quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;hljs-attr&quot;&gt;&quot;action&quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;useHelperApp&quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;hljs-attr&quot;&gt;&quot;ask&quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;false&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;hljs-attr&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;/usr/lib/firefox-slack-policy/open-slack&quot;&lt;/span&gt;
        &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;hljs-punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will only work if you also install the companion script &lt;code class=&quot;hljs&quot;&gt;open-slack&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;#!/bin/sh&lt;/span&gt;
&lt;span class=&quot;hljs-built_in&quot;&gt;exec&lt;/span&gt; xdg-open &lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-variable&quot;&gt;$@&lt;/span&gt;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These two files together tell Firefox to use &lt;code class=&quot;hljs&quot;&gt;xdg-open&lt;/code&gt; in place of &lt;code class=&quot;hljs&quot;&gt;gio open&lt;/code&gt;.
If I understand correctly, the latter needs an explicit entry in the
&lt;code class=&quot;hljs&quot;&gt;mimeapps.list&lt;/code&gt; file to select an application to handle mimetypes it is not
familiar with (like &lt;code class=&quot;hljs&quot;&gt;x-scheme-handler/slack&lt;/code&gt;) even if you have a &lt;code class=&quot;hljs&quot;&gt;.desktop&lt;/code&gt;
file with the appropriate &lt;code class=&quot;hljs&quot;&gt;MimeType&lt;/code&gt; declaration. I have no idea why,
especially considering that &lt;code class=&quot;hljs&quot;&gt;mimeinfo.cache&lt;/code&gt; correctly resolves
&lt;code class=&quot;hljs&quot;&gt;x-scheme-handler/slack&lt;/code&gt; on my machine.&lt;/p&gt;
&lt;p&gt;Anyway, now at least I can log in Slack without issue. I made a small AUR
package of it, so if you are an ArchLinux user affected by this bug and without
a pre-existing Firefox entreprise policy, feel free to install
&lt;a href=&quot;https://aur.archlinux.org/packages/firefox-slack-policy&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;firefox-slack-policy&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;
and call it a day.&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>What Happened in January 2026?</title>
      <link>https://soap.coffee/~lthms/posts/january-2026.html</link>
      <guid>https://soap.coffee/~lthms/posts/january-2026.html</guid>
      <pubDate>January 30, 2026</pubDate>
      <description>
        
        &lt;h1&gt;What Happened in January 2026?&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/meta.html&quot; class=&quot;tag hover-sky&quot; marked=&quot;&quot;&gt;meta&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/vibecoding.html&quot; class=&quot;tag hover-lavender&quot; marked=&quot;&quot;&gt;vibecoding&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;This is my first retrospective in quite a while—I have yet to make writing
these logs a real habit of mine. That being the case, so much happened this
month that this article felt like the obvious thing to do.&lt;/p&gt;
&lt;h2&gt;&lt;code class=&quot;hljs&quot;&gt;tinkerbell&lt;/code&gt;’s First Month&lt;/h2&gt;
&lt;p&gt;On January 5th, I published &lt;a href=&quot;/~lthms/posts/i-cannot-ssh-into-my-server-anymore.html&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;my account of migrating my website to a completely
new setup&lt;/a&gt;. Not only am I very
proud of this article in and of itself, I am also quite happy that it has
sparked discussions in a few places such as &lt;a href=&quot;https://lobste.rs/s/e7lpyy/i_cannot_ssh_into_my_server_anymore_s_fine&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;lobste.rs&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; or the &lt;a href=&quot;https://news.ycombinator.com/item?id=46524390&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;orange
website&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. It has also been shared in other places like the &lt;a href=&quot;https://buttondown.com/devopsish/archive/devopsish-293/&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;DevOps’ish
newsletter&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I have also created a &lt;a href=&quot;https://github.com/lthms/tinkerbell&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;GitHub repository&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; to host &lt;code class=&quot;hljs&quot;&gt;tinkerbell&lt;/code&gt;
configuration, and it is quietly farming stars as we speak. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;I don’t write articles with the expectation that they reach a large audience,
but I will admit I had &lt;em&gt;some&lt;/em&gt; ambitions for this one. It’s very fulfilling to
know my experiment report of sorts has caught the attention of my peers, if
only a little.&lt;/p&gt;
&lt;p&gt;At first, I thought I would spend January experimenting with my new playground.
I have a handful of services I want to deploy. Little did I know I would be
sidetracked sharply before I had a chance to get to it.&lt;/p&gt;
&lt;h2&gt;Meeting with Claude Code&lt;/h2&gt;
&lt;p&gt;Somehow, I have managed to go through 2025 while staying afar from the code
agent hype. I gave “vibecoding” a try in May by &lt;a href=&quot;/~lthms/posts/PeerProgrammingWithLLMs.html&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;chatting with ChatGPT and
Gemini while yak shaving my way towards transcribing YouTube videos in
OCaml&lt;/a&gt;. Even I realized back then that the hype had already moved on from
chat UI towards agents.&lt;/p&gt;
&lt;p&gt;Then, the craziest thing happened. I went on holidays on December 23rd, 2025. Two
weeks later, as I was going back to &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$WORK&lt;/span&gt;&lt;/code&gt;, Claude Code and its ilk
suddenly felt inevitable. It looks like agentic workflows got very good in a
matter of a few weeks, up to a point where there is a real opportunity cost in
ignoring them altogether. And as I am about to take out a mortgage, it feels
like a bad time to take the risk of falling out of relevance.&lt;/p&gt;
&lt;p&gt;Looking back, I think it started with a simple, genuine suggestion—we were
discussing a fairly ambitious clean-up of our test-suite at &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$WORK&lt;/span&gt;&lt;/code&gt; when
someone mentioned Claude Code was quite relevant for this kind of tedious,
boilerplate-heavy task. This resonated with all the success stories I was
suddenly exposed to. Before I could realize what was happening, I was caught up
in &lt;a href=&quot;/~lthms/posts/how-i-want-to-use-llms-in-2026.html&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;an intense introspective journey&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Part of my answer to the angst of LLMs being on the verge of reshaping the way
I work is &lt;a href=&quot;https://lthms.github.io/cece/&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;CeCe&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;&lt;label for=&quot;fn2&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn2&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;CeCe being a nickname for Claude Code (CC). &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;CeCe is a Claude Code plugin &lt;s&gt;I have been working&lt;/s&gt; Claude Code and I have
been working on for the better part of the month, and it has become my sandbox
to experiment with and understand agentic workflows. Configuring Claude Code in
a very opinionated way felt only natural—that’s the only starting point I know.
I am glad I did that, it enabled me to get a better understanding of how Claude
Code actually works.&lt;/p&gt;
&lt;p&gt;Ironically, since CeCe has mostly been written by CeCe itself and because it
grew quite fast as a result, I do not really feel confident in modifying it
myself 😆. I am now trying to &lt;a href=&quot;https://github.com/lthms/vee&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;rewrite it&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; on my
own, with more structure and “intention.” We will see how it goes.&lt;/p&gt;
&lt;h2&gt;New RSS Feeds&lt;/h2&gt;
&lt;p&gt;On a final note, I am glad to say that this website now features some new RSS
feeds that you may be interested in&lt;label for=&quot;fn3&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn3&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;That’s actually the very first task I entrusted to Claude Code.
Suffice it to say, it didn&apos;t blink, and navigated through my quite unusual
setup like a champ. &lt;/span&gt;
&lt;/span&gt;: one per &lt;a href=&quot;/~lthms/tags&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;tags&lt;/a&gt;, and one per
&lt;a href=&quot;/~lthms/series&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;series&lt;/a&gt;. I have been meaning to implement them since I’ve added my website to
a certain aggregator that now advertises every article I publish that cites one
particular programming language.&lt;/p&gt;
&lt;p&gt;I am glad to know that camel aficionados learnt about my &lt;code class=&quot;hljs&quot;&gt;tinkerbell&lt;/code&gt; setup
simply because I drew a parallel between infrastructure as code and functional
programming. Maybe they don’t share my enthusiasm, though. With this change, I
am one PR away from limiting this aggregator’s scope to simply the articles
featuring the appropriate tag. I think they will find it useful. Maybe you will
too!&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>How I Want to Use LLMs in 2026</title>
      <link>https://soap.coffee/~lthms/posts/how-i-want-to-use-llms-in-2026.html</link>
      <guid>https://soap.coffee/~lthms/posts/how-i-want-to-use-llms-in-2026.html</guid>
      <pubDate>January 25, 2026</pubDate>
      <description>
        
        &lt;h1&gt;How I Want to Use LLMs in 2026&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/opinions.html&quot; class=&quot;tag hover-rose&quot; marked=&quot;&quot;&gt;opinions&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/vibecoding.html&quot; class=&quot;tag hover-lemon&quot; marked=&quot;&quot;&gt;vibecoding&lt;/a&gt; &lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I would like to thank Xavier Van de Woestyne for his feedback and careful
review.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Agentic tools are here, and they are here to stay. I don’t think it is an
overstatement to say that LLMs are completely reshaping our day-to-day life.
Even if mass adoption has yet to happen&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;We are seeing more and more public statements from key figures of
our industry like &lt;a href=&quot;https://www.tomshardware.com/tech-industry/artificial-intelligence/microsoft-ceo-says-ai-needs-to-have-a-wider-impact-or-else-it-risks-quickly-losing-social-permission-also-says-that-the-technology-should-benefit-more-people-to-avoid-a-bubble&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;Satya Nadella&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; or &lt;a href=&quot;https://www.businessinsider.com/nvidia-jensen-huang-ai-doomerism-damage-investments-2026-1&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;Jensen Huang&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; trying to shed
positive light on AI and pushing for more people to embrace it—probably
because they don’t see the increase in active users they were hoping for. &lt;/span&gt;
&lt;/span&gt;, the consequences are
already here. In the software engineering industry, I already witness how they
come with expectations whether we want to use them or not.&lt;/p&gt;
&lt;p&gt;In 2025, I stayed away from the agentic hype. This month, I was made acutely
aware of how transformative they can be. I don’t think there is a way back from
there.&lt;/p&gt;
&lt;p&gt;As we jump into 2026 headfirst, I consequently find myself at a crossroads. I
will integrate LLMs in my workflow so that I can get the most out of what they
can offer, but I want to do so consciously. Hence this article, whose tone and
underlying motivation are different from my other pieces. I want to set a bar,
to form a contract of sorts between me and my future self.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I want to be &lt;strong&gt;transparent&lt;/strong&gt; about who—or what—produced the work I am exposing
to others. I am an engineer;&amp;nbsp;I can expect to generate tons of code and
technical documentation using (meticulously prompted) agents. I am also
publishing content online, like on this very website. The last thing I want is
to trick people into thinking that I wrote something that was actually
generated by a tool. Or, even worse, that they end up convinced something I
genuinely wrote “the old way” has been generated.&lt;/p&gt;
&lt;p&gt;This does not mean generated content is without value. Nor do I think there is
a clear, objective line to draw between what are actually two ends of a
spectrum. After all, I’ve been using ChatGPT to polish my articles for a year
now, and I haven’t advertised it in the past. Still, agentic tools have become
good enough: I will be in a position to describe complex tasks, fully delegate
their implementation, and be confident enough to publish the result. I believe
it is fair for my fellow humans to be aware of that fact when they read or
review the result. Only then will they be able to calibrate their own
expectations in light of this information.&lt;/p&gt;
&lt;p&gt;As a concrete example, I have started to set up &lt;a href=&quot;https://github.com/cece-lthms&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;dedicated accounts for Claude
Code&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. I am trying to come up with a reliable way to let it take over the
execution of well-scoped tasks, up to responding to reviewers’ feedback on its
own. That’s not an end I want to pursue unless I can be transparent about it.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I want to be &lt;strong&gt;deliberate&lt;/strong&gt; about when I use or don’t use LLMs. And I have a
surprising number of reasons why.&lt;/p&gt;
&lt;p&gt;On a personal level, there are skills I don’t want to lose, craft I still wish
to improve. I’m fine with never having to write a bug report directly again,
but do I want to forgo authorship of my blog’s articles, for instance? Clearly
not.&lt;/p&gt;
&lt;p&gt;Besides, we are still grimly on track when it comes to climate change. Even
after accepting that individual behaviors have a much less impact than what
we’d like, is it really reasonable to have hours of back-and-forth with an
agent every day from now on? A lot has been said and written about the impact
of LLMs in that regard. I am under the impression that we recently read
stories that are tragically similar to what was published about Bitcoin a few
years back&lt;label for=&quot;fn2&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn2&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I had a risk management training once, and something the instructor
said stuck with me: when something becomes &lt;em&gt;safer&lt;/em&gt;, we humans tend to adapt
our behavior to take more risks. Are we doing the same thing with climate
change? When we manage to reduce our environmental impact, do we
collectively interpret that news as a blank check to find new ways to
consume more energy? &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;I think one answer to this is to refuse to make the LLM the default, obvious
choice. Using an agent should have weight to it. There will be times when an
agent will be an enabler—achieving something outside of my immediate
reach&lt;label for=&quot;fn3&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn3&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Because it would take me too much time, because it would be extremely
tedious and error-prone, or for an infinite number of valid reasons. &lt;/span&gt;
&lt;/span&gt;. And there will be times when I will want to use it to write a
trivial patch that I could come up with myself in a matter of minutes. I want
to cultivate the discipline to make the distinction between the former and the
latter, so that I avoid falling into wasteful habits.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I want to be &lt;strong&gt;respectful&lt;/strong&gt; of the people who will be confronted with my use of
LLMs. The matter is too complicated to approach any other way. What is
acceptable for some feels like an attack on others.&lt;/p&gt;
&lt;p&gt;Yes, agents can be powerful accelerators. No, adopting them is neither easy nor
the obvious, right thing to do. We are seeing too many people being hurt by the
behaviors enabled by agents’ capabilities: open-source maintainers closing
their projects from external contributions, junior engineers struggling like
never before to find jobs, artists witnessing in real time their art being
regurgitated by models trained on their portfolios. The list goes on.&lt;/p&gt;
&lt;p&gt;I cannot commit to never using generated art, or to close my eyes to what LLMs
can bring me. But I want to be &lt;em&gt;aware&lt;/em&gt;—and to &lt;em&gt;care&lt;/em&gt;—about the consequences of
my choices, as well as the broader context behind them. And sometimes, that
needs to mean renouncing the convenience that a technology can bring, even if
for just a moment.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Only time will tell how I end up using LLMs, and whether the principles I claim
today as my own in this article will stand the test of time. I am rather
curious to reread this piece in a year—I hope it will prompt (ah!) me to write
a retrospective.&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>I Cannot SSH Into My Server Anymore (And That’s Fine)</title>
      <link>https://soap.coffee/~lthms/posts/i-cannot-ssh-into-my-server-anymore.html</link>
      <guid>https://soap.coffee/~lthms/posts/i-cannot-ssh-into-my-server-anymore.html</guid>
      <pubDate>January 5, 2026</pubDate>
      <description>
        
        &lt;h1&gt;I Cannot SSH Into My Server Anymore (And That’s Fine)&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/coreos.html&quot; class=&quot;tag hover-coral&quot; marked=&quot;&quot;&gt;coreos&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/docker.html&quot; class=&quot;tag hover-lavender&quot; marked=&quot;&quot;&gt;docker&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/meta.html&quot; class=&quot;tag hover-mint&quot; marked=&quot;&quot;&gt;meta&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/self-hosting.html&quot; class=&quot;tag hover-lavender&quot; marked=&quot;&quot;&gt;self-hosting&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/terraform.html&quot; class=&quot;tag hover-lemon&quot; marked=&quot;&quot;&gt;terraform&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/vultr.html&quot; class=&quot;tag hover-sky&quot; marked=&quot;&quot;&gt;vultr&lt;/a&gt; &lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I would like to thank Yann Régis-Gianas, Sylvain Ribstein and Paul Laforgue
for their feedback and careful review.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To kick off 2026, I had clear objectives in mind: decommissioning &lt;code class=&quot;hljs&quot;&gt;moana&lt;/code&gt;, my
trusty $100+/month VPS, and setting up &lt;code class=&quot;hljs&quot;&gt;tinkerbell&lt;/code&gt;, its far less costly
successor.&lt;/p&gt;
&lt;p&gt;On the one hand, I have been using &lt;code class=&quot;hljs&quot;&gt;moana&lt;/code&gt; to self-host a number of services,
and it was very handy to know that I had always a go-to place to experiment
with whatever caught my interest. On the other hand, $100/month is obviously a
lot of money, and looking back at how I used it in 2025, it was not
particularly well spent. It was time to downsize.&lt;/p&gt;
&lt;p&gt;Now that &lt;code class=&quot;hljs&quot;&gt;tinkerbell&lt;/code&gt; is up and running, I cannot even SSH into it. In fact,
&lt;em&gt;nothing&lt;/em&gt; can.&lt;/p&gt;
&lt;p&gt;There is no need. To update one of the services it hosts, I push a new container
image to the appropriate registry with the correct tag. &lt;code class=&quot;hljs&quot;&gt;tinkerbell&lt;/code&gt; will fetch
and deploy it. All on its own.&lt;/p&gt;
&lt;p&gt;In this article, I walk through the journey that led me to the smoke and
mirrors behind this magic trick: &lt;a href=&quot;https://fedoraproject.org/coreos/&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;Fedora CoreOS&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, &lt;a href=&quot;https://coreos.github.io/ignition/&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;Ignition&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; and &lt;a href=&quot;https://docs.podman.io/en/latest/markdown/podman-quadlet.1.html&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;Podman
Quadlets&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; in the main roles, with &lt;a href=&quot;https://developer.hashicorp.com/terraform&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;Terraform&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; as an essential supporting
character. This stack checks all the boxes I care about.&lt;/p&gt;
&lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;&lt;p class=&quot;markdown-alert-title&quot;&gt;&lt;svg class=&quot;octicon octicon-info mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;Note&lt;/p&gt;&lt;p&gt;For interested readers, I have published &lt;code class=&quot;hljs&quot;&gt;tinkerbell&lt;/code&gt;’s &lt;a href=&quot;https://github.com/lthms/tinkerbell&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;full setup&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; on
GitHub. This article reads as an experiment log, and if you are only
interested in the final result, you should definitely have a look.&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Container-Centric, Declarative, and Low-Maintenance&lt;/h2&gt;
&lt;p&gt;Going into this, I knew I didn’t want to reproduce &lt;code class=&quot;hljs&quot;&gt;moana&lt;/code&gt;’s setup—it was fully
manual&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;In the end, I never took the time to publish a write-up about it, so
in a nutshell: everything relied on &lt;a href=&quot;https://github.com/lthms/nspawn&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;a small script&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; that enabled
me to create interconnected &lt;a href=&quot;https://man7.org/linux/man-pages/man5/systemd.nspawn.5.html&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;nspawn containers&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; on the spot. &lt;/span&gt;
&lt;/span&gt; and I no longer have the time or the motivation to fiddle with
the internals of a server. Instead, I wanted to embrace the principles my
DevOps colleagues had taught me over the past two years.&lt;/p&gt;
&lt;p&gt;My initial idea was to start with this very website, since it was the only
service deployed on &lt;code class=&quot;hljs&quot;&gt;moana&lt;/code&gt; that I really wanted to keep. Since &lt;a href=&quot;./DreamWebsite.html&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;I had written
a container image for this website&lt;/a&gt;, I just had to look
for the most straightforward and future-proof way to deploy it in production™—
something I could later extend to deploy more cool projects, if I ever wanted
to&lt;label for=&quot;fn2&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn2&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;If my goal was limited to host a static website, this whole setup
would arguably be both overengineered and counterproductive. &lt;code class=&quot;hljs&quot;&gt;tinkerbell&lt;/code&gt;
was to become my little foothold in the Internet, though. My “cloud
homelabs,” of sorts. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.docker.com/compose/&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;Docker Compose&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; alone wasn’t a good fit. I like compose files, but one needs
to provision and manage a VM to host them. Ansible can provision VMs, but that
road comes with its own set of struggles. Writing good playbooks has always
felt surprisingly difficult to me. In particular, a good playbook is supposed
to handle two very different scenarios—provisioning a brand new machine, and
updating a pre-existing deployment—and I have found it particularly challenging
to ensure that both paths reliably produce the same result.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://kubernetes.io/&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;Kubernetes&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; was &lt;em&gt;very&lt;/em&gt; appealing on paper. I have seen engineers turn compose
files into &lt;a href=&quot;https://helm.sh/docs/topics/charts/&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;Helm charts&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; and be done with it. If I could do the same thing,
wouldn’t that be bliss? Unfortunately, Kubernetes is a notoriously complex
stack, resulting from compromises made to address challenges I simply don’t
face. Managed clusters could make things easier, but they aren’t cheap. That
would defeat the initial motivation behind retiring &lt;code class=&quot;hljs&quot;&gt;moana&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://fedoraproject.org/coreos/&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;CoreOS&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, being an operating system specifically built to &lt;em&gt;run containers&lt;/em&gt;,
obviously stood out. That said, I had very little intuition on how it could
work in practice. So I started digging. I learned about Ignition first. Its
purpose is to provision a VM exactly once, at first boot. If you need to change
something afterwards, you throw away your VM and create a new one. This may
seem counter-intuitive, but since it eliminates the main reason I was looking
for an alternative to Ansible, I was hooked&lt;label for=&quot;fn3&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn3&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;CoreOS and Ignition enable me to think about virtual machines the same
way OCaml or Haskell trained me to think about data: as immutable values. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;I found out how to use systemd unit files to start containers via &lt;code class=&quot;hljs&quot;&gt;podman&lt;/code&gt; CLI
commands. That was way too cumbersome, so I pushed on for a way to orchestrate
containers &lt;em&gt;à la&lt;/em&gt; Docker Compose. That’s when I discovered Podman Quadlets and
&lt;a href=&quot;https://docs.podman.io/en/stable/markdown/podman-auto-update.1.html&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;auto-updates&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With that, everything clicked. I knew what I wanted to do, and I was very
excited about it.&lt;/p&gt;
&lt;h2&gt;Assembling &lt;code class=&quot;hljs&quot;&gt;tinkerbell&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;For more than a year now, my website has been &lt;a href=&quot;./DreamWebsite.html&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;served from RAM by a standalone,
static binary built in OCaml&lt;/a&gt;, with TLS termination handled by Nginx and
&lt;code class=&quot;hljs&quot;&gt;certbot&lt;/code&gt;’s certificates renewal performed by yours truly&lt;label for=&quot;fn4&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn4&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I didn’t lie when I said &lt;code class=&quot;hljs&quot;&gt;moana&lt;/code&gt;’s setup was indeed &lt;em&gt;manual&lt;/em&gt;. &lt;/span&gt;
&lt;/span&gt;. I didn’t
have any reason to fundamentally change this architecture. I was simply looking
for a way to automate their deployment.&lt;/p&gt;
&lt;h3&gt;Container-Centric, …&lt;/h3&gt;
&lt;p&gt;The logical thing to do was to have &lt;code class=&quot;hljs&quot;&gt;tinkerbell&lt;/code&gt; run two containers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The reverse proxy:&lt;/strong&gt; I had been firmly on Team Nginx for years now, but
when I heard &lt;a href=&quot;https://caddyserver.com/&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;Caddy&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; could “&lt;em&gt;automatically obtain&lt;/em&gt; and &lt;em&gt;renew&lt;/em&gt; TLS
certificates,” I was sold on giving it a try.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The website itself:&lt;/strong&gt; Static binaries can be wrapped inside a container
with close to zero overhead using the &lt;a href=&quot;https://hub.docker.com/_/scratch&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;scratch&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; base image, so I
did just that. I published it to a free-plan, public registry hosted on Vultr
that I created for the occasion&lt;label for=&quot;fn5&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn5&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Which means getting an offline copy of this website is now as
simple as calling &lt;code class=&quot;hljs&quot;&gt;docker pull ams.vultrcr.com/lthms/www/soap.coffee:live&lt;/code&gt;. &lt;/span&gt;
&lt;/span&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;https://mermaid.ink/img/pako:eNo9UMtOwzAQ_BVrTyCllZs4JPEBiYZjuQASEnUPTrxJLBK7ch1BafPvuC_2tDM7M7vaA9RWIXBoevtdd9J5snoVhoR6Wpe9RuM3ZDZ7PPKcEs5YciTLtYBSKrUnd--rt3sBm4t-N1atk9uOeG2-0FXY95fB8hZwJOX6A6ud9nj1oFEQQeu0Au7diBEM6AZ5gnA4SQT4DgcUwENrcPRO9gKEmYJtK82ntcPN6ezYdsAb2e8CGrdKenzWMtw0_LMuLERX2tF44AnLziHAD_ATIM3mMY3zlCZskRUPRQR74DGL58WCXrk8S6cIfs9b6TxlWZ4EcsFYkdOgR6W9dS-Xj9bWNLqF6Q97DWuS?type=png&quot;&gt;&lt;figcaption&gt;&lt;p&gt;Nothing beats a straightforward architecture&lt;/p&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Nothing fancy or unexpected here, which made it a good target for a first
deployment. It was time to open Neovim to write some YAML.&lt;/p&gt;
&lt;h3&gt;Declarative, …&lt;/h3&gt;
&lt;p&gt;At this point, the architecture was clear. The next step was to turn it into
something a machine could execute. To that end, I needed two things: first an
Ignition configuration, then a CoreOS VM to run it.&lt;/p&gt;
&lt;h4&gt;The Proof of Concept&lt;/h4&gt;
&lt;p&gt;Ignition configurations (&lt;code class=&quot;hljs&quot;&gt;.ign&lt;/code&gt;) are JSON files primarily intended to be
consumed by machines. They are produced from YAML files using a tool called
&lt;a href=&quot;https://coreos.github.io/butane/&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;Butane&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. For instance, here is the first Butane configuration file I ended up
writing. It provisions a CoreOS VM by creating a new user (&lt;code class=&quot;hljs&quot;&gt;lthms&lt;/code&gt;), along with
a &lt;code class=&quot;hljs&quot;&gt;.ssh/authorized_keys&lt;/code&gt; file allowing me to SSH into the VM&lt;label for=&quot;fn6&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn6&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I didn’t know at the time that I would &lt;em&gt;deliberately&lt;/em&gt; remove these
lines from the final Butane file. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;variant:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;fcos&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;version:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1.5&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;passwd:&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;users:&lt;/span&gt;
    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;lthms&lt;/span&gt;
      &lt;span class=&quot;hljs-attr&quot;&gt;ssh_authorized_keys:&lt;/span&gt;
        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ssh-ed25519&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;AAAAC3NzaC1lZDI1NTE5AAAAIKajIx3VWRjhqIrza4ZnVnnI1g2q6NfMfMOcnSciP1Ws&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;lthms@vanellope&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What’s important to keep in mind is that Ignition runs exactly once, at first
boot. Then it is never used again. This single fact has far-reaching
consequences, and is the reason why any meaningful change implies replacing the
machine, not modifying it.&lt;/p&gt;
&lt;p&gt;Before going any further, I wanted to understand how the actual deployment was
going to work. I generated the Ignition configuration file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;butane main.bu &amp;gt; main.ign
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, I decided to investigate how to define the Vultr VM in Terraform. The
resulting configuration is twofold. First, we need to configure Terraform to be
able to interact with the Vultr API, using the &lt;a href=&quot;https://registry.terraform.io/providers/vultr/vultr/latest/docs&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;Vultr provider&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. Second, I
needed to &lt;a href=&quot;https://registry.terraform.io/providers/vultr/vultr/latest/docs/resources/instance&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;create the VM&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;&lt;label for=&quot;fn7&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn7&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;For discovering what values to put in most fields, &lt;code class=&quot;hljs&quot;&gt;vultr-cli&lt;/code&gt; is
pretty convenient. Kudos to the Vultr team for making it in the first
place. &lt;/span&gt;
&lt;/span&gt; and feed it the Ignition
configuration.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-hcl&quot;&gt;resource &quot;vultr_instance&quot; &quot;tinkerbell&quot; {
  region = &quot;cdg&quot;
  plan = &quot;vc2-1c-1gb&quot;
  os_id = &quot;391&quot;

  label = &quot;tinkerbell&quot;
  hostname = &quot;tinkerbell&quot;

  user_data = file(&quot;main.ign&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that was it. I invoked &lt;code class=&quot;hljs&quot;&gt;terraform apply&lt;/code&gt;, waited for a little while, then
SSHed into the newly created VM with my &lt;code class=&quot;hljs&quot;&gt;lthms&lt;/code&gt; user. Sure enough, the
&lt;code class=&quot;hljs&quot;&gt;tinkerbell&lt;/code&gt; VM was now listed in the Vultr web interface. I explored for a
little while, then called &lt;code class=&quot;hljs&quot;&gt;terraform destroy&lt;/code&gt; and rejoiced when everything
worked as expected.&lt;/p&gt;
&lt;h4&gt;The MVP&lt;/h4&gt;
&lt;p&gt;At this point, I was basically done with Terraform, and I just needed to write
the Butane configuration that would bring my containers to life. As I mentioned
earlier, the first approach I tried was to define a systemd service responsible
for invoking &lt;code class=&quot;hljs&quot;&gt;podman&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;systemd:&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;units:&lt;/span&gt;
    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;soap.coffee.service&lt;/span&gt;
      &lt;span class=&quot;hljs-attr&quot;&gt;enabled:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;
      &lt;span class=&quot;hljs-attr&quot;&gt;contents:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|
        [Unit]
        Description=Web Service
        After=network-online.target
        Wants=network-online.target
&lt;/span&gt;
        [&lt;span class=&quot;hljs-string&quot;&gt;Service&lt;/span&gt;]
        &lt;span class=&quot;hljs-string&quot;&gt;ExecStart=/usr/bin/podman&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;\&lt;/span&gt;
          &lt;span class=&quot;hljs-string&quot;&gt;--name&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;soap.coffee&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;\&lt;/span&gt;
          &lt;span class=&quot;hljs-string&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8901&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;:8901&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;\&lt;/span&gt;
          &lt;span class=&quot;hljs-string&quot;&gt;--restart=always&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;\&lt;/span&gt;
          &lt;span class=&quot;hljs-string&quot;&gt;ams.vultrcr.com/lthms/www/soap.coffee:latest&lt;/span&gt;
        &lt;span class=&quot;hljs-string&quot;&gt;ExecStop=/usr/bin/podman&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;stop&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;soap.coffee&lt;/span&gt;

        [&lt;span class=&quot;hljs-string&quot;&gt;Install&lt;/span&gt;]
        &lt;span class=&quot;hljs-string&quot;&gt;WantedBy=multi-user.target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Adding this entry in my Butane configuration and redeploying &lt;code class=&quot;hljs&quot;&gt;tinkerbell&lt;/code&gt; got
me exactly what I wanted. My website was up and running. For the sake of
getting something working first, I added the necessary configuration for Caddy
(the container and the provisioning of its configuration file), redeployed
&lt;code class=&quot;hljs&quot;&gt;tinkerbell&lt;/code&gt; again, only to realize I also needed to create a network so that
the two containers could talk together. After half an hour or so, I got
everything working, but was left with a sour taste in my mouth.&lt;/p&gt;
&lt;p&gt;This would simply not do. I wasn’t defining anything, I was writing a shell
script in the most cumbersome way possible.&lt;/p&gt;
&lt;p&gt;Then, I remembered my initial train of thought and started to search for a way
to have Docker Compose work on CoreOS&lt;label for=&quot;fn8&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn8&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Well, Podman Compose, I guess. &lt;/span&gt;
&lt;/span&gt;. That is when I discovered
Quadlet, whose &lt;a href=&quot;https://github.com/containers/quadlet&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;initial repository does a good job justifying its
existence&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;&lt;label for=&quot;fn9&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn9&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;This repository is now archived, since Quadlet has got merged
upstream. &lt;/span&gt;
&lt;/span&gt;. In particular,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;With quadlet, you describe how to run a container in a format that is very
similar to regular systemd config files. From these actual systemd
configurations are automatically generated (using &lt;a href=&quot;https://github.com/containers/quadlet&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;systemd generators&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To give a concrete example, here is the &lt;code class=&quot;hljs&quot;&gt;.container&lt;/code&gt; file I wrote for my
website server.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ini&quot;&gt;&lt;span class=&quot;hljs-section&quot;&gt;[Container]&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;ContainerName&lt;/span&gt;=soap.c&lt;span class=&quot;hljs-literal&quot;&gt;off&lt;/span&gt;ee
&lt;span class=&quot;hljs-attr&quot;&gt;Image&lt;/span&gt;=ams.vultrcr.com/lthms/www/soap.c&lt;span class=&quot;hljs-literal&quot;&gt;off&lt;/span&gt;ee:live

&lt;span class=&quot;hljs-section&quot;&gt;[Service]&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;Restart&lt;/span&gt;=always

&lt;span class=&quot;hljs-section&quot;&gt;[Install]&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;WantedBy&lt;/span&gt;=multi-user.target
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I wasn’t wasting my time teaching systemd how to start containers anymore. I
was now declaring what should exist, so that systemd—repurposed for the
occasion as a container orchestrator—could take care of the rest.&lt;/p&gt;
&lt;div class=&quot;markdown-alert markdown-alert-tip&quot;&gt;&lt;p class=&quot;markdown-alert-title&quot;&gt;&lt;svg class=&quot;octicon octicon-light-bulb mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a8.456 8.456 0 0 0-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75ZM5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;Tip&lt;/p&gt;&lt;p&gt;If your containers are basically ignored by systemd, be smarter than me. Do
not try to blindly change your &lt;code class=&quot;hljs&quot;&gt;.container&lt;/code&gt; files and redeploy your VM in a
very painful and frustrating loop. Simply ask systemd for the generator logs.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;sudo journalctl -b | grep -i quadlet 
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;I excitedly turned &lt;code class=&quot;hljs&quot;&gt;caddy.service&lt;/code&gt; into &lt;code class=&quot;hljs&quot;&gt;caddy.container&lt;/code&gt;, redeployed
&lt;code class=&quot;hljs&quot;&gt;tinkerbell&lt;/code&gt;, ran into the exact same issue I had encountered before and
discovered the easiest way for two Quadlet-defined containers to talk to each
other was to introduce a &lt;a href=&quot;https://docs.podman.io/en/latest/_static/api.html?version=latest#tag/pods&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;&lt;em&gt;pod&lt;/em&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. Unlike Docker Compose which uses DNS
over a bridge network, a pod shares the network namespace, allowing containers
to communicate over &lt;em&gt;localhost&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;To define a pod, one needs to create a &lt;code class=&quot;hljs&quot;&gt;.pod&lt;/code&gt; file, and to reference it in
their &lt;code class=&quot;hljs&quot;&gt;.container&lt;/code&gt; files using the &lt;code class=&quot;hljs&quot;&gt;PodName=&lt;/code&gt; configuration option. A “few”
redeployments later, I got everything working again, and I was ready to call it
a day.&lt;/p&gt;
&lt;p&gt;And with that, &lt;code class=&quot;hljs&quot;&gt;tinkerbell&lt;/code&gt; was basically ready.&lt;/p&gt;
&lt;div class=&quot;markdown-alert markdown-alert-caution&quot;&gt;&lt;p class=&quot;markdown-alert-title&quot;&gt;&lt;svg class=&quot;octicon octicon-stop mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;Caution&lt;/p&gt;&lt;p&gt;I’ve later learned that restarting a container that is part of a pod will
have the (to me, unexpected) side-effect to restart all the other containers
of that pod.&lt;/p&gt;
&lt;/div&gt;
&lt;h3&gt;And Low-Maintenance&lt;/h3&gt;
&lt;p&gt;Now, the end of the previous section might have given you pause.&lt;/p&gt;
&lt;p&gt;Even a static website like this one isn’t completely “stateless.” Not only does
Caddy require a configuration file to do anything meaningful, but it is also a
stateful application as it manages TLS certificates over time. Besides, I &lt;em&gt;do&lt;/em&gt;
publish technical write-ups from time to time&lt;label for=&quot;fn10&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn10&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Two in 2025, that’s true. But 2026 is only starting, you never know
what might come! &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Was I really at peace with having to destroy and redeploy &lt;code class=&quot;hljs&quot;&gt;tinkerbell&lt;/code&gt; every
time I need to change anything on my website?&lt;/p&gt;
&lt;p&gt;On the one hand, &lt;em&gt;yes&lt;/em&gt;. I believe I could live with that. I modify my website
only a handful of times even in good months, I think my audience could survive
with a minute of downtime before being allowed to read my latest pieces. It may
be an unpopular opinion, but considering my actual use case, it &lt;em&gt;was&lt;/em&gt; good
enough. Even the fact that I do not store the TLS certificates obtained by
Caddy anywhere persistent should not be an issue. I mean, Let’s Encrypt has
fairly generous weekly issuance limits per domain &lt;label for=&quot;fn11&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn11&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;How do I know that? Well... I might have hit the limit while hacking my
way to a working setup. &lt;/span&gt;
&lt;/span&gt;. I should be fine.&lt;/p&gt;
&lt;p&gt;On the other hand, the setup was starting to grow on me, and I have &lt;em&gt;other&lt;/em&gt; use
cases in mind that could be a good fit for it. So I started researching again,
this time to understand how a deployment philosophy so focused on immutability
was managing what seemed to be conflicting requirements.&lt;/p&gt;
&lt;p&gt;I went down other rabbit holes, looking for answers. The discovery that stood
out the most to me—to the point where it became the hook of this article—was
Podman auto-updates.&lt;/p&gt;
&lt;p&gt;To deploy a new version of a containerized application, you pull the new image
and restart the container. When you commit to this pattern, why should you be
the one performing this action? Instead, your VM can regularly check registries
for new images, and &lt;em&gt;update the required containers when necessary&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In practice, Podman made this approach trivial to put in place. I just needed
to label my containers with &lt;code class=&quot;hljs&quot;&gt;io.containers.autoupdate&lt;/code&gt; set to &lt;code class=&quot;hljs&quot;&gt;registry&lt;/code&gt;,
enable the &lt;code class=&quot;hljs&quot;&gt;podman-auto-update&lt;/code&gt; timer&lt;label for=&quot;fn12&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn12&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;By default, the timer is triggered once a day, which felt
unnecessarily long, so I decided to make it hourly instead. &lt;/span&gt;
&lt;/span&gt;, and that was it. Now, every
time I update the tag &lt;code class=&quot;hljs&quot;&gt;www/soap.coffee:live&lt;/code&gt; to point to a newer version of my
image, my website is updated within the hour.&lt;/p&gt;
&lt;p&gt;And that is when the final piece clicked. At this point, publishing an image
becomes the only deployment step. I didn’t need SSH anymore.&lt;/p&gt;
&lt;h2&gt;The Road Ahead&lt;/h2&gt;
&lt;p&gt;&lt;code class=&quot;hljs&quot;&gt;tinkerbell&lt;/code&gt; has been running for a few days now, and I am quite pleased with
the system I have put in place. In retrospect, none of this is particularly
novel. It feels more like I am converging toward a set of practices the
industry has been gravitating toward for years.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/~lthms/img/iac-meme.jpg&quot;&gt;&lt;figcaption&gt;&lt;p&gt;A man looking at the “CoreOS &amp;amp; Quadlets” butterfly and wondering whether he’s looking at Infrastructure as Code. I’m not entirely sure of the answer.&lt;/p&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;The journey is far from being over, though. &lt;code class=&quot;hljs&quot;&gt;tinkerbell&lt;/code&gt; is up and running, and
it served you this HTML page just fine, but the moment I put SSH out of the
picture, it became a black box. Aside from some hardware metrics kindly
provided by the Vultr dashboard, I have no real visibility into what’s going on
inside. That is fine for now, but it is not a place I want to stay in forever.
I plan to spend a few more weekends building an observability stack&lt;label for=&quot;fn13&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn13&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Oh, and maybe I will move these TLS certificates in a block storage or
something. That could be a good idea. &lt;/span&gt;
&lt;/span&gt;.
That will come in handy when things go wrong—as they inevitably do. I would
rather have the means to understand failures than guess my way around them.&lt;/p&gt;
&lt;p&gt;Did I ever mention I am an enthusiastic Opentelemetry convert?&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>Peer-Programming in Modern OCaml with ChatGPT and Gemini</title>
      <link>https://soap.coffee/~lthms/posts/PeerProgrammingWithLLMs.html</link>
      <guid>https://soap.coffee/~lthms/posts/PeerProgrammingWithLLMs.html</guid>
      <pubDate>June 2, 2025</pubDate>
      <description>
        
        &lt;h1&gt;Peer-Programming in Modern OCaml with ChatGPT and Gemini&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/ocaml.html&quot; class=&quot;tag hover-lemon&quot; marked=&quot;&quot;&gt;ocaml&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/vibecoding.html&quot; class=&quot;tag hover-lavender&quot; marked=&quot;&quot;&gt;vibecoding&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;It is June 2025, and LLMs are everywhere and do everything now. I have never
been a diligent adopter of them myself. The past few months, I started to feel
a bit “left out,” though. Colleagues and friends are starting to integrate
LLM-powered tools into their personal toolkit, with notable successes.&lt;/p&gt;
&lt;p&gt;Early May, I decided to challenge myself to implement a simple tool to generate
a summary from YouTube videos using &lt;a href=&quot;https://alphacephei.com/vosk/&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;Vosk&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; for
speech recognition and &lt;a href=&quot;https://ollama.com/&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;Ollama&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; for generating summaries
using LLMs running locally. I could hit two birds with one stone—experimenting
with LLMs to write and power software.&lt;/p&gt;
&lt;p&gt;I decided to implement as much as possible in OCaml, for two main reasons.
Firstly, this is the main language I use at &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$WORK&lt;/span&gt;&lt;/code&gt;. I wanted to get a
sense of how LLMs could help with the software stack I used 7+ hours a day.
Secondly, it was a good opportunity to catch-up with the OCaml 5 ecosystem
(&lt;a href=&quot;https://github.com/ocaml-multicore/eio&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;Eio&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; in particular).&lt;/p&gt;
&lt;p&gt;This write-up is a sort of dev log of this exercise. Its main focus is not to
explain in depth the code I ended up writing, but rather to recollect on my
wins and losses in adding LLMs in my developer toolkit.&lt;/p&gt;
&lt;h2&gt;TL;DR&lt;/h2&gt;
&lt;p&gt;In this article, I am using “Tip” blocks to highlight my key findings and
lessons learned. That being said, for readers in a hurry, here’s how ChatGPT
summarizes these blocks.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Prompting is a skill that improves through trial and error—many failed
prompts help build intuition.&lt;/li&gt;
&lt;li&gt;LLMs may suggest non-existent functions; using LSP tools helps identify these
quickly.&lt;/li&gt;
&lt;li&gt;Standard formats like WAV lead to more accurate LLM outputs.&lt;/li&gt;
&lt;li&gt;LLMs without session memory tend to repeat mistakes; shared context is
important.&lt;/li&gt;
&lt;li&gt;Structuring commit message prompts (e.g., What / Why / How) produces
consistently good results.&lt;/li&gt;
&lt;li&gt;LLMs struggle with libraries like Eio, possibly due to name ambiguity or
unstable APIs.&lt;/li&gt;
&lt;li&gt;Providing project-specific context (e.g., via &lt;code class=&quot;hljs&quot;&gt;direnv&lt;/code&gt;) is likely to help
reduce repeated hallucinations.&lt;/li&gt;
&lt;li&gt;Prompting LLMs for MR descriptions or commits can eliminate empty submissions
and speed up review.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You should still definitely read the full piece, though. I don’t think my
prompt was particularly good 🤫.&lt;/p&gt;
&lt;h2&gt;Editor Integration&lt;/h2&gt;
&lt;p&gt;My first task was to grant myself the ability to leverage LLMs from my editor.
I had been using the web chat of ChatGPT for a while, but it now felt
antiquated since I had seen a freshly hired coworker get ChatGPT to generate
for themselves a dozen tests directly from VS Code.&lt;/p&gt;
&lt;p&gt;I have returned to &lt;a href=&quot;https://neovim.io&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;Neovim&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; for a few years, and I am not
ready to migrate to VS Code. I would have been surprised if the Vim/Neovim
communities wouldn’t have a viable plugin for me, though.&lt;/p&gt;
&lt;p&gt;I asked both ChatGPT and Gemini to find my candidates, but the plugins they
suggested seemed unmaintained, often outdated.&lt;/p&gt;
&lt;p&gt;In the end, I found &lt;a href=&quot;https://github.com/olimorris/codecompanion.nvim&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;CodeCompanion.nvim&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;
by myself, through a good old Google research. I asked ChatGPT why it hadn’t
suggested it to me, and it seems like my prompt were biased. By asking for
“a Neovim ChatGPT plugin” or “a plugin to integrate Gemini to Neovim,” I had
unnecessarily narrowed the LLM scope.&lt;/p&gt;
&lt;div class=&quot;markdown-alert markdown-alert-tip&quot;&gt;&lt;p class=&quot;markdown-alert-title&quot;&gt;&lt;svg class=&quot;octicon octicon-light-bulb mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a8.456 8.456 0 0 0-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75ZM5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;Tip&lt;/p&gt;&lt;p&gt;I guess one does not become a prompt engineer in a day. This is actually one
of the reasons I want to use LLMs more seriously. To build myself intuitions
of which prompts work and which don’t. After this project, I have mostly
uncovered a bunch of the latter category 😅.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/yurug&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;&lt;strong&gt;@yurug&lt;/strong&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; had told me he was impressed by Gemini
Pro, so I decided to make it the default adapter for the &lt;code class=&quot;hljs&quot;&gt;CodeCompanionChat&lt;/code&gt;
command. I tried to make Gemini Pro the default model for this adapter, it was
challenging and LLMs weren’t able to help. When I finally found the correct
&lt;code class=&quot;hljs&quot;&gt;setup&lt;/code&gt; option, it turns out I hadn’t generated a token allowing me to use Pro.&lt;/p&gt;
&lt;p&gt;Well. That gave me the opportunity to benchmark Gemini Flash, then.&lt;/p&gt;
&lt;h2&gt;Speech Recognition with Vosk&lt;/h2&gt;
&lt;p&gt;ChatGPT suggested Vosk as a way to get a transcript of an audio file, so it was
also a good opportunity to write bindings (something I had dodged for a long
time for no particular reason).&lt;/p&gt;
&lt;p&gt;As of June 2025, there is no OCaml bindings for the &lt;a href=&quot;https://github.com/alphacep/vosk-api/blob/master/src/vosk_api.h&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;Vosk
API&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, so my
first task was to write my own as part of a project soberly called
&lt;a href=&quot;https://github.com/lthms/ocaml-vosk&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;ocaml-vosk&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Gemini Flash was able to help me understand how &lt;code class=&quot;hljs&quot;&gt;ctypes&lt;/code&gt; and &lt;code class=&quot;hljs&quot;&gt;ctypes.foreign&lt;/code&gt;
works. This was my first experience interacting with an LLM from my Neovim
window, and it was pretty convincing. It gave me the opportunity to learn that
one can declare opaque types in OCaml (not just via mli files). It makes sense,
but it was news to me.&lt;/p&gt;
&lt;p&gt;Then, Gemini suggested me to use &lt;a href=&quot;https://ocaml-multicore.github.io/eio/eio/Eio/Switch/&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;EIO’s
&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Switch&lt;/span&gt;&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;
to deal with automatic memory management (in place of &lt;code class=&quot;hljs&quot;&gt;Gc.finalise&lt;/code&gt;). It was
the first time I heard about it, and the fact that I learned their existence
from the perspective of resource management (not fiber management) was a good
accident.&lt;/p&gt;
&lt;p&gt;The first point of friction came when I started build a high-level interface
for my Vosk bindings. More specifically, given a
&lt;a href=&quot;https://ocaml.org/p/cstruct/latest&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;Cstruct.t&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; value, how do I get a pointer
and a length? It turns out that while both ChatGPT and Gemini Pro know how to
do so, Gemini Flash hallucinates every step of the way.&lt;/p&gt;
&lt;p&gt;The solution is actually pretty straightforward.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; ptr =
  &lt;span class=&quot;hljs-type&quot;&gt;Ctypes&lt;/span&gt;.bigarray_start
    &lt;span class=&quot;hljs-type&quot;&gt;Ctypes&lt;/span&gt;.array1
    (&lt;span class=&quot;hljs-type&quot;&gt;Cstruct&lt;/span&gt;.to_bigarray buffer)
&lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; len = buffer.&lt;span class=&quot;hljs-type&quot;&gt;Cstruct&lt;/span&gt;.len &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Gemini Flash kept suggesting I use &lt;code class=&quot;hljs&quot;&gt;Ctypes.ptr_add&lt;/code&gt; instead, though. Don’t
search for it, it does not exist&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;While reviewing this article, ChatGPT gently hinted that while
&lt;code class=&quot;hljs&quot;&gt;ptr_add&lt;/code&gt; does not exist, &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Ctypes&lt;/span&gt;.(+@)&lt;/code&gt; does. &lt;/span&gt;
&lt;/span&gt;. When I suggested &lt;code class=&quot;hljs&quot;&gt;Cstruct.to_bigarray&lt;/code&gt;,
it warned me about the fact that this call would create a copy of the
underlying buffer. ChatGPT and Gemini Pro disagreed, and I could convince
myself that they were right by looking at the code. Interestingly, I was also
able to convince Gemini Flash it was wrong by copy/pasting the relevant code
snippet.&lt;/p&gt;
&lt;div class=&quot;markdown-alert markdown-alert-tip&quot;&gt;&lt;p class=&quot;markdown-alert-title&quot;&gt;&lt;svg class=&quot;octicon octicon-light-bulb mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a8.456 8.456 0 0 0-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75ZM5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;Tip&lt;/p&gt;&lt;p&gt;Having an LLM suggesting you to use a function which does not exist is &lt;em&gt;very&lt;/em&gt;
frustrating. Especially if it happens several times in a row—it recognizes
its mistake and proposes an alternative that is as nonexistant as the first
one.&amp;nbsp;At least, with LSP it is pretty straightforward to know when it happens.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Using Vosk is one thing, but then I couldn’t find any OCaml package to read
audio files compatible with Vosk expectations. Implementing what I needed in
OCaml gave me more opportunities to learn about EIO, but most importantly, it
showed how having a chat with an LLM directly from my editor was convenient. I
was able to learn about WAV files, RIFF header and subchunks and PCB 16-bit
mono audio data without leaving Neovim. And by giving Gemini access to my
buffer, I troubleshot most of my issues fairly quickly (except when they were
EIO-specific—more on that later).&lt;/p&gt;
&lt;div class=&quot;markdown-alert markdown-alert-tip&quot;&gt;&lt;p class=&quot;markdown-alert-title&quot;&gt;&lt;svg class=&quot;octicon octicon-light-bulb mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a8.456 8.456 0 0 0-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75ZM5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;Tip&lt;/p&gt;&lt;p&gt;For widespread encoding like WAV files, LLMs shine particularly bright.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;In the end, EIO-specific code put aside, this task was roughly solved by (1)
writing bindings for the few functions of the Vosk API I needed, and (2)
translating C examples provided by Gemini into good-looking OCaml&lt;label for=&quot;fn2&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn2&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;It’s a little out of scope for this article, but I discovered when
writing the high-level API for Vosk that &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Switch&lt;/span&gt;&lt;/code&gt;es are very easy
to misuse. It is as simple as (incorrectly) turning an eager function
consuming a buffer into a &lt;code class=&quot;hljs&quot;&gt;Seq&lt;/code&gt;-based alternative, while forgetting the use
of &lt;code class=&quot;hljs&quot;&gt;Switch.run&lt;/code&gt; on top of the function. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Witnessing my example program outputting the transcript of audio files as it
was processing them felt pretty good, and I was soon ready to tackle the second
part of this project: prompting a LLM to summarize it.&lt;/p&gt;
&lt;h2&gt;Prompting Local LLMs with Ollama&lt;/h2&gt;
&lt;p&gt;Similarly to Vosk, there is no on the shelf package available to use Ollama
from an OCaml program. As a consequence, I created a second repository
(&lt;a href=&quot;https://github.com/lthms/ocaml-ollama&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;ocaml-ollama&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; if you can believe it).&lt;/p&gt;
&lt;h3&gt;How It Started&lt;/h3&gt;
&lt;p&gt;Turns out, you don’t use Ollama the same way you use Vosk. The latter is a C
library that you can call from your binary, the former actually uses a
client/server architecture. I asked LLMs what was the best solution for
performing HTTP requests with Eio, and &lt;code class=&quot;hljs&quot;&gt;cohttp-eio&lt;/code&gt; came back as a good
candidate. I’m already familiar with &lt;code class=&quot;hljs&quot;&gt;cohttp&lt;/code&gt;, since we are using it at
&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$WORK&lt;/span&gt;&lt;/code&gt;, but it’s actually a transitive dependency (of a framework
called &lt;a href=&quot;https://ocaml.org/p/resto/latest&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;resto&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;I am actually a little frustrated with &lt;code class=&quot;hljs&quot;&gt;resto&lt;/code&gt;, so I welcomed the opportunity
to familiar myself a little more with &lt;code class=&quot;hljs&quot;&gt;cohttp&lt;/code&gt; directly. I quickly implemented
the helper fetching the list of models available from a given Ollama instance.&lt;/p&gt;
&lt;p&gt;Then, I got myself side tracked.&lt;/p&gt;
&lt;h3&gt;More LLMs Lies&lt;/h3&gt;
&lt;p&gt;Persistent HTTP connections are a pet peeve of mine. Establishing a TCP
connection, negotiating TLS encryption, all of that takes time—creating a new
socket for each request a daemon really frustrates me as a result.&lt;/p&gt;
&lt;p&gt;So I asked.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Does &lt;code class=&quot;hljs&quot;&gt;cohttp-eio&lt;/code&gt; reuses already established connections when performing two
requests on the same host?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;ChatGPT 4o. Gemini 2.5 Flash. Gemini 2.5 Pro. They all assured me it was the
case, as long as I was careful and reused the same
&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Cohttp_eio&lt;/span&gt;.&lt;span class=&quot;hljs-type&quot;&gt;Client&lt;/span&gt;.t&lt;/code&gt; instance. For instance, here is the first few
words of ChatGPT when prompted with this question.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As of current behavior in &lt;code class=&quot;hljs&quot;&gt;cohttp-eio-client&lt;/code&gt;, &lt;strong&gt;yes&lt;/strong&gt;, it does &lt;strong&gt;reuse
already established connections&lt;/strong&gt; when making multiple requests to the same
host, provided certain conditions are met.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It’s a lie. Don’t trust them. They don’t reuse existing HTTP connection.&lt;/p&gt;
&lt;p&gt;I was very doubtful, so I asked them how to check this. &lt;code class=&quot;hljs&quot;&gt;tcpdump&lt;/code&gt; was
mentioned&lt;label for=&quot;fn3&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn3&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I later discovered &lt;a href=&quot;https://github.com/ocaml-multicore/eio-trace&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;eio-trace&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;
and it would have been much more straightforward to use this tool to
inspect &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Cohttp_eio&lt;/span&gt;.&lt;span class=&quot;hljs-type&quot;&gt;Client&lt;/span&gt;&lt;/code&gt;’s default behavior. No LLM thought of
that, sadly. &lt;/span&gt;
&lt;/span&gt;. I got traces I couldn’t read at first glance, so I just
copy/pasted them to the LLMs… and sure enough, they confirmed what I suspected.
&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Cohttp_eio&lt;/span&gt;.&lt;span class=&quot;hljs-type&quot;&gt;Client&lt;/span&gt;&lt;/code&gt; does not share connections by default. It creates a
socket for each request.&lt;/p&gt;
&lt;p&gt;It’s actually pretty easy to convince yourself that it is the case by reading
the implementation of
&lt;a href=&quot;https://github.com/mirage/ocaml-cohttp/blob/main/cohttp-eio/src/client.ml#L83&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Cohttp_eio&lt;/span&gt;.&lt;span class=&quot;hljs-type&quot;&gt;Client&lt;/span&gt;&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; connection = &lt;span class=&quot;hljs-type&quot;&gt;Eio&lt;/span&gt;.&lt;span class=&quot;hljs-type&quot;&gt;Flow&lt;/span&gt;.two_way_ty r
&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; t = sw:&lt;span class=&quot;hljs-type&quot;&gt;Switch&lt;/span&gt;.t -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;Uri&lt;/span&gt;.t -&amp;gt; connection

&lt;span class=&quot;hljs-comment&quot;&gt;(* simplified version of [make], omitting the support for HTTPS *)&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; make &lt;span class=&quot;hljs-literal&quot;&gt;()&lt;/span&gt; net : t = &lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; ~sw uri -&amp;gt;
  (&lt;span class=&quot;hljs-type&quot;&gt;Eio&lt;/span&gt;.&lt;span class=&quot;hljs-type&quot;&gt;Net&lt;/span&gt;.connect ~sw net (unix_address uri) :&amp;gt; connection)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is &lt;em&gt;nothing&lt;/em&gt; here dealing with persistent connections. &lt;code class=&quot;hljs&quot;&gt;Eio.Net.connect&lt;/code&gt;
uses a switch for resource management, but does not perform any kind of
connection caching.&lt;/p&gt;
&lt;p&gt;That’s okay, though. Yak shaving is a real thing. I can stop working on my
Ollama client library for a while, just to &lt;em&gt;fix this&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;The Questionable Side Quest of Implementing a Connection Pool for &lt;code class=&quot;hljs&quot;&gt;cohttp-eio&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The bottom-line of this little adventure is: I should have updated my default
prompt to remind the LLMs that &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Cohttp_eio&lt;/span&gt;.&lt;span class=&quot;hljs-type&quot;&gt;Body&lt;/span&gt;.drain&lt;/code&gt; in &lt;em&gt;not&lt;/em&gt; a thing.&lt;/p&gt;
&lt;p&gt;But let’s start from the beginning. Over the course of a few days, I have
successfully implemented a wrapper on top of &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Cohttp_eio&lt;/span&gt;.&lt;span class=&quot;hljs-type&quot;&gt;Client&lt;/span&gt;&lt;/code&gt; to
deal with persistent connections. It’s not rocket science, but it’s still a
subtle endeavor, which necessitated a good understanding of Eio and &lt;code class=&quot;hljs&quot;&gt;cohttp&lt;/code&gt;. I
cannot say LLMs were instrumental for the task. They gave me good pointers to
start from, but they also misled me a bunch of times.&lt;/p&gt;
&lt;p&gt;Sometimes, the help came in surprising ways. One anecdote in particular
stuck with me. I decided I needed a &lt;code class=&quot;hljs language-ocaml&quot;&gt;get&lt;/code&gt; operation for
&lt;a href=&quot;https://ocaml-multicore.github.io/eio/eio/Eio/Pool/&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Eio&lt;/span&gt;.&lt;span class=&quot;hljs-type&quot;&gt;Pool&lt;/span&gt;&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;
pools, which sadly only proposes &lt;code class=&quot;hljs&quot;&gt;use&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;(* Provided by Eio.Pool *)&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; use : &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; t -&amp;gt; (&lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;b&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;b&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;(* Not provided *)&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; get : sw:&lt;span class=&quot;hljs-type&quot;&gt;Switch&lt;/span&gt;.t -&amp;gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; t -&amp;gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The key insight is that &lt;code class=&quot;hljs&quot;&gt;get&lt;/code&gt; allows callers to pick something from the pool,
and only put it back when the switch is released.&lt;/p&gt;
&lt;p&gt;My first implementation of &lt;code class=&quot;hljs&quot;&gt;get&lt;/code&gt; was roughly as follows&lt;label for=&quot;fn4&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn4&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I didn’t even consider asking an LLM to propose me an implementation,
now that I think about it. I really am no vibe coder yet. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;Eio&lt;/span&gt;.&lt;span class=&quot;hljs-type&quot;&gt;Std&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; get ~sw t =
  &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; x, rx = &lt;span class=&quot;hljs-type&quot;&gt;Promise&lt;/span&gt;.create &lt;span class=&quot;hljs-literal&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; never, _ = &lt;span class=&quot;hljs-type&quot;&gt;Promise&lt;/span&gt;.create &lt;span class=&quot;hljs-literal&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;
  &lt;span class=&quot;hljs-type&quot;&gt;Fiber&lt;/span&gt;.fork ~sw (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;()&lt;/span&gt; -&amp;gt;
      &lt;span class=&quot;hljs-type&quot;&gt;Eio&lt;/span&gt;.&lt;span class=&quot;hljs-type&quot;&gt;Pool&lt;/span&gt;.use t @@ &lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; conn -&amp;gt;
      &lt;span class=&quot;hljs-type&quot;&gt;Promise&lt;/span&gt;.resolve rx conn;
      &lt;span class=&quot;hljs-type&quot;&gt;Promise&lt;/span&gt;.await never);
  &lt;span class=&quot;hljs-type&quot;&gt;Promise&lt;/span&gt;.await x
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And it didn’t work. The resulting program was hanging, because of how
&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Fiber&lt;/span&gt;.fork ~sw&lt;/code&gt; works. Basically, the fiber created by &lt;code class=&quot;hljs&quot;&gt;fork&lt;/code&gt; becomes
part of the set of fibers the switch &lt;code class=&quot;hljs&quot;&gt;sw&lt;/code&gt; waits for. Since, in my case, said
fiber would never be resolved, I had created a deadlock.&lt;/p&gt;
&lt;p&gt;I asked Gemini Pro 2.5 for help, and out of curiosity, I looked at its
reasoning steps. Very early on, it mentioned &lt;code class=&quot;hljs&quot;&gt;Fiber.fork_daemon&lt;/code&gt;, but
surprisingly &lt;code class=&quot;hljs&quot;&gt;Fiber.fork_daemon&lt;/code&gt; was not mentioned in the final answer&lt;label for=&quot;fn5&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn5&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Once again, I had asked the wrong question. I asked for the &lt;code class=&quot;hljs&quot;&gt;Fiber&lt;/code&gt;
equivalent of &lt;code class=&quot;hljs&quot;&gt;Lwt.async&lt;/code&gt;. I had overlooked that &lt;code class=&quot;hljs&quot;&gt;Lwt.async&lt;/code&gt; had a very
particular behavior wrt. exceptions, that Gemini Pro tried very hard to
replicate. I didn’t care at all about the exceptions I could raise, here! &lt;/span&gt;
&lt;/span&gt;.
Have I not been curious at that time, I would have missed the correct
solution&lt;label for=&quot;fn6&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn6&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;&lt;a href=&quot;https://bsky.app/@welltypedwit.ch&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;@alice&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#bsky&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; provided me the answer a
few minutes later, so I’d have been fine in the end 😅. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;I think my experience overall was made a little more frustrating than it should
have been because I have never constructed a “context” that I could share
between coding sessions. I haven’t enabled the memory saving setting in
ChatGPT. Besides, everytime I opened Neovim, Gemini was starting from scratch.
I should try to change that, to prevent the LLMs from doing the same mistakes
again and again—typically, the &lt;code class=&quot;hljs&quot;&gt;Cohttp_eio.Body.drain&lt;/code&gt; function they kept
bringing up.&lt;/p&gt;
&lt;div class=&quot;markdown-alert markdown-alert-tip&quot;&gt;&lt;p class=&quot;markdown-alert-title&quot;&gt;&lt;svg class=&quot;octicon octicon-light-bulb mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a8.456 8.456 0 0 0-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75ZM5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;Tip&lt;/p&gt;&lt;p&gt;I need to investigate how I can specialize my default prompt for each
software project I am working on. I imagine I can rely on an environment
variable and &lt;a href=&quot;https://direnv.net/&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;direnv&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Finally, it’s when I worked on this library that I came up with a nice prompt
for Gemini to write my git commit messages for me.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code class=&quot;hljs&quot;&gt;@editor&lt;/code&gt; &lt;code class=&quot;hljs&quot;&gt;#buffer&lt;/code&gt; Add a git commit title and message. Structure the
description in three sections (What, Why, How). Wrap the sections at 72
columns. Don’t forget the git title, and always insert a new line between the
title and the description.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This prompt gives pretty cool result. It is still necessary to review it,
because in a few instances I caught false statement in the proposal. But
overall, it gives really meaningful output. Almost &lt;a href=&quot;https://github.com/lthms/cohttp-connpool-eio/commits/main/&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;all commits of the
library&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; have been
written with this prompt.&lt;/p&gt;
&lt;div class=&quot;markdown-alert markdown-alert-tip&quot;&gt;&lt;p class=&quot;markdown-alert-title&quot;&gt;&lt;svg class=&quot;octicon octicon-light-bulb mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a8.456 8.456 0 0 0-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75ZM5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;Tip&lt;/p&gt;&lt;p&gt;If anything, I don’t think I will never open a Merge Request with an empty
description ever again.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;And that, kids, is how I released
&lt;a href=&quot;https://github.com/lthms/cohttp-connpool-eio&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;cohttp-connpool-eio.0.1&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Wrapping-up a Minimal Ollama Chat&lt;/h3&gt;
&lt;p&gt;Integrating &lt;code class=&quot;hljs&quot;&gt;cohttp-connpool-eio&lt;/code&gt; in my &lt;code class=&quot;hljs&quot;&gt;ocaml-ollama&lt;/code&gt; project led me to find a
bug in the former. More specifically, the &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Cohttp_connpool_eio&lt;/span&gt;.warm&lt;/code&gt;
function that can be used to pre-populate a new pool was doing so by performing
a specified &lt;code class=&quot;hljs&quot;&gt;HEAD&lt;/code&gt; request to the host as many time as the pool size&lt;label for=&quot;fn7&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn7&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;In a later iteration of the library, &lt;code class=&quot;hljs&quot;&gt;warm&lt;/code&gt; only establishes
connections, and does not perform any unnecessary HTTP requests. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;It worked well against both &lt;code class=&quot;hljs&quot;&gt;https://www.google.com&lt;/code&gt; and
&lt;code class=&quot;hljs&quot;&gt;https://soap.coffee/~lthms&lt;/code&gt;, but when I tried with the Ollama server, it
decided to hang. Why?&lt;/p&gt;
&lt;p&gt;Well, I tried asking my new friends the LLMs, but didn’t get any answer I felt
confident with. At this point, my trust in their EIO expertise was rather low,
and I was more skimming through their answer to find a lead I would follow
myself than anything else. In the end, I completely dropped the LLMs here, and
went back to what I usually do: experimenting, and reading code.&lt;/p&gt;
&lt;p&gt;I reproduced the issue with &lt;code class=&quot;hljs&quot;&gt;curl&lt;/code&gt;: &lt;code class=&quot;hljs&quot;&gt;curl -X HEAD&lt;/code&gt; hangs as well with Ollama,
while &lt;code class=&quot;hljs&quot;&gt;curl --head&lt;/code&gt; does not. The former tries to read the response body, based
on the response headers (&lt;em&gt;e.g.&lt;/em&gt;, &lt;code class=&quot;hljs&quot;&gt;content-length&lt;/code&gt;). The latter doesn’t, because
it knows &lt;code class=&quot;hljs&quot;&gt;HEAD&lt;/code&gt; always omits the body. I am not sure &lt;em&gt;why&lt;/em&gt;  the hanging
behavior does not show for &lt;code class=&quot;hljs&quot;&gt;curl -X HEAD https://www.google.com&lt;/code&gt;, though.&lt;/p&gt;
&lt;p&gt;But anyway, once the bug was fixed, I could return to playing with Ollama.&lt;/p&gt;
&lt;p&gt;I then decided to implement a helper to call &lt;a href=&quot;https://github.com/ollama/ollama/blob/main/docs/api.md#generate-a-completion&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;POST /api/generate&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;.
It is the simplest way with Ollama to generate an LLM’s answer from a prompt.
Interestingly enough, it is a “streamed” RPC using the &lt;code class=&quot;hljs&quot;&gt;application/x-ndjson&lt;/code&gt;
content type. Instead of computing the answer &lt;em&gt;before&lt;/em&gt; sending it to the
client, the server instead sends JSON-encoded chunks (&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Transfer-Encoding#chunked&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;transfer-encoding: chunked&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;I tried to implement that with &lt;code class=&quot;hljs&quot;&gt;cohttp-eio&lt;/code&gt;, and it failed miserably with
obscure parsing error messages.&lt;/p&gt;
&lt;p&gt;After a bit of debugging, it became clear that &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Eio&lt;/span&gt;.&lt;span class=&quot;hljs-type&quot;&gt;Buf_read&lt;/span&gt;.parse&lt;/code&gt; was
not behaving as I thought it was, which made me feel paranoid about how
&lt;code class=&quot;hljs&quot;&gt;cohttp-connpool-eio&lt;/code&gt; handles connection releases. In the end, I had to unpack
how the &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Cohttp_eio&lt;/span&gt;.&lt;span class=&quot;hljs-type&quot;&gt;Body&lt;/span&gt;.t&lt;/code&gt; work under the hood wrt.
&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;End_of_file&lt;/span&gt;&lt;/code&gt; to move on. Once again, my LLM friends weren’t
particularly helpful: they were hallucinating &lt;code class=&quot;hljs&quot;&gt;Buf_read&lt;/code&gt; functions, and never
considered to mention that &lt;code class=&quot;hljs&quot;&gt;parse&lt;/code&gt; only works for complete response.&lt;/p&gt;
&lt;div class=&quot;markdown-alert markdown-alert-tip&quot;&gt;&lt;p class=&quot;markdown-alert-title&quot;&gt;&lt;svg class=&quot;octicon octicon-light-bulb mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a8.456 8.456 0 0 0-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75ZM5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;Tip&lt;/p&gt;&lt;p&gt;My personal conclusion is that ChatGPT and Gemini quickly show their limits
for non-trivial programming task involving Eio and its ecosystem.
I am really curious to understand why. Do they keep hallucinating functions
because Eio is a really generic name, and maybe they are mixing context from
the Python library with the OCaml one? Or is it because the API of Eio has
changed a lot over the years?&lt;/p&gt;
&lt;p&gt;I am also wondering how, as a the author of a library, I can fix a similar
situation. Assuming ChatGPT starts assuming false statements about
&lt;code class=&quot;hljs&quot;&gt;cohttp-connpool-eio&lt;/code&gt; for instance, how do I address this? I suspect being
“LLMs-friendly” will be increasingly important for a software library’s
success.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;In the end, ChatGPT and Gemini were just another source of inputs, not the main
driver of my development process.&lt;/p&gt;
&lt;h2&gt;Putting Everything Together&lt;/h2&gt;
&lt;p&gt;Turns out, you really need just one RPC to generate a summary for a text input,
so it wasn’t long before I could chain everything. I pulled
&lt;code class=&quot;hljs&quot;&gt;mistral:7b-instruct-v0.2-q4_K_M&lt;/code&gt; (over a suggestion by ChatGPT, if I remember
correctly), and got a summary from the video I had downloaded.&lt;/p&gt;
&lt;p&gt;Just kidding. Out of nowhere, I decided to pursue yet another side quest, and
gave a try to the fancy &lt;a href=&quot;https://dune.readthedocs.io/en/stable/tutorials/dune-package-management/dependencies.html&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;dune pkg lock&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;
command. &lt;em&gt;Then&lt;/em&gt; I was able to &lt;a href=&quot;/~lthms/files/RhinocerosSummary.html&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;generate my
summary&lt;/a&gt;, using the following prompt.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;Generate a summary of the raw transcript of a video provided after
this paragraph. The transcript may be in a language that is not
English, but the summary should always be in English. You should
adopt a neutral point of view (i.e., even if the transcript speaks
in the first person, you should always use the third person). Each
line is an utterance. Keep the summary short and engaging, your
goal is to provide a good overview of what was said.

----

{Vosk output}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And with this, it was time to wrap-up. And what better way to do so than to
write this little journal entry? So I did, and when I was half way through my
first draft, I fired a new chat buffer to ask for advice from my new friend
Gemini Flash.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;#buffer Here is a very preliminary, incomplete draft of a blogpost. Can you try to
anticipate if it will find an audience?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It wasn’t long before Gemini turned me down.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;My apologies, but I cannot anticipate whether this blog post will find an
audience. My capabilities are focused on programming-related tasks like code
explanation, review, generation, and tool execution within the Neovim
environment.&lt;/p&gt;
&lt;p&gt;Let me know if you have any questions about the code itself, or need
assistance with Neovim.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;🥲&lt;label for=&quot;fn8&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn8&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Fortunately, ChatGPT was less opinionated. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;h2&gt;Final Words&lt;/h2&gt;
&lt;p&gt;Although I had already used ChatGPT and other models in the past, this was the
first time I tried to make them a central part of my workflow. I learned a lot
during this experiment, and I now have an integrated setup I enjoy using.&lt;/p&gt;
&lt;p&gt;I need to keep digging. Try more models (there are a lot of those now). And get
better at writing good prompts which do not lead the LLMs astray. They are here
to stay, after all. I better learn how to take the most from them.&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>What Happened in 2024?</title>
      <link>https://soap.coffee/~lthms/posts/December2024.html</link>
      <guid>https://soap.coffee/~lthms/posts/December2024.html</guid>
      <pubDate>January 1, 2025</pubDate>
      <description>
        
        &lt;h1&gt;What Happened in 2024?&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/meta.html&quot; class=&quot;tag hover-periwinkle&quot; marked=&quot;&quot;&gt;meta&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;We are done with 2024, and now is a good time to reflect on what has happened
over the past 12 months. I was not planning to, but &lt;a href=&quot;https://www.paulox.net/2024/12/31/my-2024-in-review/&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;my feed convinced me to
give it a try&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. Plus, it is a good opportunity to revive my
“&lt;a href=&quot;series/Retrospectives.html&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;Retrospective&lt;/a&gt;” series.&lt;/p&gt;
&lt;h2&gt;Free and Open Source Software&lt;/h2&gt;
&lt;p&gt;I’ve been a “prolific contributor” at &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$WORK&lt;/span&gt;&lt;/code&gt;, but less so with my
personal projects.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lthms/spatial-shell&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;Spatial Shell&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; remains my most “popular” project&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;We should reach 100 stars on GitHub in 2025 😅. &lt;/span&gt;
&lt;/span&gt;, but
except for a very minor 7th release in January, I have not touched it. It’s
basically a done project, and I very much enjoy using it on a daily basis. My
main regret is that, contrary to what is stated in its README, Spatial Shell
does not work &lt;em&gt;at all&lt;/em&gt; with i3.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lthms/ezjsonm-encoding&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;ezjsonm-encoding&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; was initially written for Spatial Shell, but I
turned it into its own OCaml package in 2024. It is a JSON-only encoding
library heavily borrowing on &lt;a href=&quot;https://ocaml.org/p/data-encoding/latest&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;Data-encoding API&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, but with a
more flexible default behavior for object parsing. I enjoyed writing the
documentation, inspired by a tweet from &lt;a href=&quot;https://bsky.app/profile/chshersh.com&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;Dmitrii Kovanikov&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#bsky&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;&lt;label for=&quot;fn2&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn2&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Yes, cool kids moved to Bluesky in 2024, and Dmitrii is definitely a
cool kid. &lt;/span&gt;
&lt;/span&gt;.
That being said, I have never bothered to benchmark this package properly, so
if performances are important, it may not be a good fit for you.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lthms/jsonrpc2&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;jsonrpc2&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; is, as of January 1st, 2025, an experiment in
providing a general-purpose framework for servers and clients communicating
with the &lt;a href=&quot;https://www.jsonrpc.org/specification&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;JSON RPC 2.0&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; protocol. I quite like the API I’m proposing there,
and maybe I’ll try to polish and publish it in 2025.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lthms/bepo-tsrn.nvim&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;bepo-tsrn.nvim&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; is another thing I have done for myself, but
published as if it was a public good. Now, instead of having to copy/paste
the same Neovim configuration file on every computer I use, I can just type
&lt;code class=&quot;hljs&quot;&gt;yay -S neovim-bepo-tsrn-git&lt;/code&gt; and be done with it.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lthms/celtchar&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;celtchar&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; has seen its first commits since 2021, which is not nothing. As a
reminder, celtchar is a little tool I have written to generate ebooks and
static websites for the stories I write; and as I was doing the 2024 edition
of &lt;a href=&quot;https://nanowrimo.org&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;NaNoWriMo&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, I found myself in need to add a missing feature (supporting
books split in parts, not only chapters).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Overall, I’ve been defaulting to OCaml for the past two years or so, and I am
starting to think it is time to widen my perspective again. I will probably
start with relearning Go&lt;label for=&quot;fn3&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn3&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I don’t know why, but I have been mildly obsessed with this language
lately. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;h2&gt;Blog posts&lt;/h2&gt;
&lt;p&gt;2024 was not a very productive year when it comes to this website. I have
published 5 articles, which is half the number of publications of 2023. As a
logical consequence, not a lot of folks have visited my website this year.
Funnily enough, the &lt;a href=&quot;SpatialShell6.html&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;most read article&lt;/a&gt; (by far) in 2024 was published in
2023&lt;label for=&quot;fn4&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn4&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;To be fair, it was published on December 30, 2023. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/~lthms/img/2024.png&quot;&gt;&lt;figcaption&gt;&lt;p&gt;Yes, 2024 was a quiet year for this website&lt;/p&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;That being said, I am quite happy with the content published in 2024.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;GitMaintenanceSshEncryptedKeys.html&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;Using &lt;code class=&quot;hljs&quot;&gt;git maintenance&lt;/code&gt; with Encrypted SSH Keys&lt;/a&gt; is the first article I
published in 2024. It is a direct consequence of my trip to Brussels in
February to attend to &lt;a href=&quot;https://archive.fosdem.org/2024/&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;FOSDEM&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. If you haven’t already, you should watch
&lt;a href=&quot;https://www.youtube.com/watch?v=aolI_Rz0ZqY&amp;amp;pp=ygUZc28geW91IHRoaW5rIHlvdSBrbm93IGdpdA%3D%3D&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;Scott Chacon’s talk&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#youtube&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; about Git less known commands; it is the only
reason why I learned about &lt;code class=&quot;hljs&quot;&gt;git maintenance&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;LUKSEncryptedVPS.html&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;Installing a LUKS-Encrypted Arch Linux on a Vultr VPS&lt;/a&gt; is mostly a
gift I have made to Future Me. It is a very specific how-to that I can use to
quickly set up a new server with disk encryption. Funny story, I was planning
to publish a follow-up about &lt;a href=&quot;https://github.com/lthms/nspawn&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;how I use systemd-nspawn to run my web services
in containers&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, but no matter how many times I tried, I’ve never
quite found a good way to tell this story. As I plan to educate myself on
Kubernetes in 2025, it is not clear I will ever publish it now.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;BepoNvim.html&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;Introducing &lt;code class=&quot;hljs&quot;&gt;bepo-tsrn.nvim&lt;/code&gt;&lt;/a&gt; is probably the less useful article I
have published in 2024, considering I expect the userbase to &lt;code class=&quot;hljs&quot;&gt;bepo-tsrn.nvim&lt;/code&gt;
to stick to 1 until the very end&lt;label for=&quot;fn5&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn5&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;But who knows? Maybe one of you will prove me wrong! &lt;/span&gt;
&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;VestigialStructures.html&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;On Vestigial Structures&lt;/a&gt; hardly qualifies as a blog post, and is
mostly a joke. It is also the only content on my website that was mostly
generated by ChatGPT, and it is flagged as such. I don’t like using AI to
&lt;em&gt;write&lt;/em&gt;, but I do appreciate having a reviewer always at hand.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;DreamWebsite.html&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;Serving This Article from RAM for Fun and No Real Benefit&lt;/a&gt; was very
fun to write. This little experiment was stuck in my head for basically two
years, and it turned out basically exactly as I had pictured it. That being
said, I want to learn about CDNs now.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Overall, I still enjoy having my own little corner of the Internet, but if there is
one thing I’d like to improve in 2025, it is its reach. I’d like you folks to
run into my website, instead of having to promote it every time I write
something. 2025, the year of SEO?&lt;/p&gt;
&lt;h2&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$WORK&lt;/span&gt;&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;2024 started with my decision to go back to a Software Engineering position,
after giving an honest try at being an Engineering Manager in late 2023.&lt;/p&gt;
&lt;p&gt;I want to remember 2024 for two things.&lt;/p&gt;
&lt;p&gt;This year, more than ever, I have tried to appreciate my work beyond my
individual contributions. I am confident in my programming skills (although I
have so much to learn), but being an accomplished engineer is much more than
contributing code. Making sure every engineer in the team can work to the best
of their current ability, fostering a work environment favoring growth and
initiative, estimating as precisely as possible the amount of time needed to
deliver the next important thing, collaborating efficiently with non-technical
teams... I am becoming increasingly interested in these areas.&lt;/p&gt;
&lt;p&gt;Besides, this year was all about delivering and deploying in production. It’s
been a &lt;a href=&quot;https://medium.com/etherlink/post-mortem-etherlink-mainnet-beta-public-endpoint-denial-of-service-cfcaf1a7bb77&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;wild ride&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, and I loved it even if it was very demanding. After having
mostly contributed to R&amp;amp;D projects, the focus on UX, backward compatibility,
etc. was very refreshing. I learned so much through the year, and had many
opportunities to make significant impacts.&lt;/p&gt;
&lt;p&gt;In 2025, I want to keep learning about software engineering, and maybe start
sharing my thoughts on the subject on my website.&lt;/p&gt;
&lt;h2&gt;Talks&lt;/h2&gt;
&lt;p&gt;I gave only one talk in 2024, at a conference called &lt;a href=&quot;https://ethcc.io/&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;EthCC&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. It was actually a
follow-up to the talk I gave the year before. You can watch me deliver the talk
&lt;a href=&quot;https://ethcc.io/archives/being-a-stage-2-rollup-from-day-1-etherlinks-journey&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;here&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, but if you are more into written content, I have also published
a &lt;a href=&quot;BeingStage2Rollup.html&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;transcript&lt;/a&gt; on this very website. I actually loved writing it down, and plan
to systematically publish similar content for every recorded talk I will give
in the future.&lt;/p&gt;
&lt;p&gt;I also had the opportunity to participate in a &lt;a href=&quot;https://x.com/etherlink/status/1852378990712930664&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;Twitter Space&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#twitter&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This year, my public speaking opportunities were all &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$WORK&lt;/span&gt;&lt;/code&gt;-related. I
would like to change this in the future, because there are enough events out
there for me to start speaking about something other than work&lt;label for=&quot;fn6&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn6&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;It’s too late to apply to FOSDEM, but maybe I can find something to
say to an event later in the year! I think. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;h2&gt;Sport&lt;/h2&gt;
&lt;p&gt;This year was a bit of a disappointment, sport-wise. I tried several times to
get back to running regularly, and failed miserably. I went to Lyon for a 10km
run without proper training, and skipped the half-marathon I signed up for. I
should update my &lt;a href=&quot;/~lthms/running.html&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;Running Log&lt;/a&gt; nonetheless. I started swimming
regularly during the Summer, only to pierce my earlobes in September 😅.&lt;/p&gt;
&lt;p&gt;Let’s hope I do better in 2025! I am planning to register for the &lt;a href=&quot;https://triathlondeauville.com/&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;Triathlon de
Deauville&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; with my sister. That promises to be fun! And I
want to commit to the &lt;a href=&quot;https://vredestein.20kmparis.com/&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;20km de Paris&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; as well.&lt;/p&gt;
&lt;p&gt;On the bright side, I have started to use my bike again. I love riding around
Paris, especially at night.&lt;/p&gt;
&lt;h2&gt;Final Notes&lt;/h2&gt;
&lt;p&gt;Overall, I’ve devoted a large part of my time to &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$WORK&lt;/span&gt;&lt;/code&gt; in 2024.
Hopefully, I will find a better balance over the course of 2025, which should
give me more time to explore and experiment more things.&lt;/p&gt;
&lt;p&gt;Anyway, happy new year everyone! And happy Dry January!&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>Serving This Article from RAM for Fun and No Real Benefit</title>
      <link>https://soap.coffee/~lthms/posts/DreamWebsite.html</link>
      <guid>https://soap.coffee/~lthms/posts/DreamWebsite.html</guid>
      <pubDate>December 25, 2024</pubDate>
      <description>
        
        &lt;h1&gt;Serving This Article from RAM for Fun and No Real Benefit&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/docker.html&quot; class=&quot;tag hover-lavender&quot; marked=&quot;&quot;&gt;docker&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/meta.html&quot; class=&quot;tag hover-sky&quot; marked=&quot;&quot;&gt;meta&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/ocaml.html&quot; class=&quot;tag hover-peach&quot; marked=&quot;&quot;&gt;ocaml&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;In 2022, Xe Iaso published a &lt;a href=&quot;https://xeiaso.net/talks/how-my-website-works/&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;transcript of their talk on how their website was
working at the time&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. In a nutshell, their approach consisted of a
server preprocessing the website from its source at startup, then serving its
contents from memory. If you have not already, I can only encourage you to read
the article or watch the talk, as the story they tell is very interesting. For
me personally, it sparked a question: what if, instead of preprocessing the
website at startup, one decided to embed the already preprocessed website
within the program of the HTTP server tasked to serve it?&lt;/p&gt;
&lt;p&gt;Fast-forward today, and this question has finally been answered. The webpage
you are currently reading has been served to you by an ad hoc HTTP server built
with &lt;a href=&quot;https://aantron.github.io/dream/&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;Dream&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, whose binary is the only file I need to push to my server to
deploy the latest version of my website. I have actually deployed it, and it’s
been serving the contents of this website for more than a week now.&lt;/p&gt;
&lt;p&gt;What did I learn from this fun, little experiment? Basically, that this
approach changes nothing, as far as &lt;a href=&quot;https://chromewebstore.google.com/detail/lighthouse/blipmdconlkpinefehnmjammfjpmpbjk?pli=1&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;Lighthouse&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; and my monitoring is
concerned. I couldn’t find any meaningful differences between a static website
served by Nginx, a piece of software with thousands and thousands of
engineering work behind it, and my little toy web server pieced together in an
hour or so. Still. It was fun, so why not write about it?&lt;/p&gt;
&lt;p&gt;This article is a kind of experience report. I’ll dive into what I have done to
turn my website into a single, static binary. Not only does it mean writing
some OCaml, which is always fun, but it also requires understanding a little
some key HTTP headers, as well as using Docker to build easily deployable
binaries. All in all, I hope it will be an interesting read for the curious
minds.&lt;/p&gt;
&lt;h2&gt;Embedding My Website in a Binary&lt;/h2&gt;
&lt;p&gt;Not much had changed much since &lt;a href=&quot;August2022.html&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;I stopped using &lt;strong&gt;&lt;code class=&quot;hljs&quot;&gt;cleopatra&lt;/code&gt;&lt;/strong&gt; to generate
this website&lt;/a&gt;, and &lt;a href=&quot;Thanks2023.html&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;the article I published in 2023 still
stands&lt;/a&gt;. In a nutshell, I work in the &lt;code class=&quot;hljs&quot;&gt;site/&lt;/code&gt; directory, and &lt;a href=&quot;https://soupault.app&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;soupault&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;
generates my website in the &lt;code class=&quot;hljs&quot;&gt;out/~lthms&lt;/code&gt; directory, thanks to a collection of
built-in and ad hoc plugins&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;For instance, Markdown footnotes are turned into side notes with
a soupault plugin. &lt;/span&gt;
&lt;/span&gt;. To deploy the website, I was relying
on &lt;code class=&quot;hljs&quot;&gt;rsync&lt;/code&gt; to sync the contents of the &lt;code class=&quot;hljs&quot;&gt;out/~lthms&lt;/code&gt; directory with the
directory statically served by a Nginx instance on my personal server.&lt;/p&gt;
&lt;p&gt;The first step of my little toy project is to actually embed the output of
soupault into an OCaml program.&lt;/p&gt;
&lt;p&gt;That’s where &lt;a href=&quot;https://github.com/mirage/ocaml-crunch&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;ocaml-crunch&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; comes in handy. It is a &lt;a href=&quot;https://mirage.io/&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;MirageOS&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; project, whose
only job is to generate an OCaml module from a file system directory. It is
straightforward to use it from Dune.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-lisp&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;; file: out/dune&lt;/span&gt;
(&lt;span class=&quot;hljs-name&quot;&gt;rule&lt;/span&gt;
 (&lt;span class=&quot;hljs-name&quot;&gt;target&lt;/span&gt; website_content.ml)
 (&lt;span class=&quot;hljs-name&quot;&gt;deps&lt;/span&gt; (&lt;span class=&quot;hljs-name&quot;&gt;source_tree&lt;/span&gt; ~lthms))
 (&lt;span class=&quot;hljs-name&quot;&gt;action&lt;/span&gt;
  (&lt;span class=&quot;hljs-name&quot;&gt;run&lt;/span&gt; ocaml-crunch -m plain -o %{target} -s ~lthms)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This snippet generates the &lt;code class=&quot;hljs&quot;&gt;website_content.ml&lt;/code&gt; module, which we can then
expose through a library with the &lt;code class=&quot;hljs&quot;&gt;library&lt;/code&gt; stanza.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-lisp&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;; file: out/dune&lt;/span&gt;
(&lt;span class=&quot;hljs-name&quot;&gt;library&lt;/span&gt;
 (&lt;span class=&quot;hljs-name&quot;&gt;name&lt;/span&gt; website_content))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And we are basically done. Excluding an &lt;code class=&quot;hljs&quot;&gt;Internal&lt;/code&gt; module, the signature of
&lt;code class=&quot;hljs&quot;&gt;Website_content&lt;/code&gt; is pretty straightforward.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; file_list : &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; read : &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; option
&lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; hash : &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; option
&lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; size : &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; option
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Serving the content with Dream&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://aantron.github.io/dream/&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;Dream&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; is a cool project, and provides a straightforward API that we can
leverage to turn our list of in-memory files into an HTTP server.&lt;/p&gt;
&lt;h3&gt;Naive Approach&lt;/h3&gt;
&lt;p&gt;Our goal now is to create a &lt;code class=&quot;hljs&quot;&gt;Dream.handler&lt;/code&gt; for each item in
&lt;code class=&quot;hljs language-ocaml&quot;&gt;file_list&lt;/code&gt;. Done naively (as was my first attempt), it gives you
something of the form:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; make_handler ~content path =
  &lt;span class=&quot;hljs-type&quot;&gt;Dream&lt;/span&gt;.get path (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; req -&amp;gt;
    &lt;span class=&quot;hljs-type&quot;&gt;Lwt&lt;/span&gt;.return (&lt;span class=&quot;hljs-type&quot;&gt;Dream&lt;/span&gt;.response content)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which we can use to build the main route we will then pass to &lt;code class=&quot;hljs&quot;&gt;Dream.router&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; website_route =
  &lt;span class=&quot;hljs-type&quot;&gt;Dream&lt;/span&gt;.scope &lt;span class=&quot;hljs-string&quot;&gt;&quot;~lthms&quot;&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;[]&lt;/span&gt;
  @@ &lt;span class=&quot;hljs-type&quot;&gt;List&lt;/span&gt;.map
       (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; path -&amp;gt;
         &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; content = &lt;span class=&quot;hljs-type&quot;&gt;Option&lt;/span&gt;.get (&lt;span class=&quot;hljs-type&quot;&gt;Website_content&lt;/span&gt;.read path) &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;
         make_handler ~content path)
       &lt;span class=&quot;hljs-type&quot;&gt;Website_content&lt;/span&gt;.file_list
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this approach, we build our handlers once, and then the lookup is done by
Dream’s router. It could be an interesting experiment to see if doing the
lookup ourselves is more performant (since Dream’s router is very generic,
while in our case we don’t really need to parse anything). I remember Xe
routing is basically going through a linked list, which seems strange at first,
but works very well in practice because they have ordered said list with the
most recent articles up front, and everybody comes to their website to read the
latest article anyway.&lt;/p&gt;
&lt;p&gt;It does not take an extensive QA process to figure out that this approach
is far from being enough. To name a few things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;My website assumes &lt;code class=&quot;hljs&quot;&gt;http://path/index.html&lt;/code&gt; can be accessed with
&lt;code class=&quot;hljs&quot;&gt;http://path/&lt;/code&gt; or &lt;code class=&quot;hljs&quot;&gt;http://path&lt;/code&gt;. Our little snippet does not handle this.&lt;/li&gt;
&lt;li&gt;Browsers expect the &lt;code class=&quot;hljs&quot;&gt;Content-Type&lt;/code&gt; headers to be correctly set. To give an
example, they won&apos;t load a CSS file if the &lt;code class=&quot;hljs&quot;&gt;Content-Type&lt;/code&gt; header is not set
to &lt;code class=&quot;hljs&quot;&gt;text/css&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Browsers work best for websites that take the time to provide caching
directives. Our little snippet does not care to do so.&lt;/li&gt;
&lt;li&gt;Even if my website is rather lightweight&lt;label for=&quot;fn2&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn2&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;20MBytes at the time of writing the first version of this article. &lt;/span&gt;
&lt;/span&gt;, compressing the response
of our HTTP server for clients that support it is always a good idea.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is a gentle reminder of all the things Nginx can do for you with very
little configuration.&lt;/p&gt;
&lt;h3&gt;Handling &lt;code class=&quot;hljs&quot;&gt;index.html&lt;/code&gt; Synonyms&lt;/h3&gt;
&lt;p&gt;This one is rather simple. For files named &lt;code class=&quot;hljs&quot;&gt;index.html&lt;/code&gt;, we need 3 handers, not
just one. We can achieve this with an additional helper
&lt;code class=&quot;hljs&quot;&gt;make_handler_remove_suffix&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; make_handler_remove_suffix ~content path suffix
    =
  &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;String&lt;/span&gt;.ends_with ~suffix path &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; alt_path =
      &lt;span class=&quot;hljs-type&quot;&gt;String&lt;/span&gt;.sub path &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;String&lt;/span&gt;.length path - &lt;span class=&quot;hljs-type&quot;&gt;String&lt;/span&gt;.length suffix)
    &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;
    [ make_handler ~content alt_path ]
  &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Updating the &lt;code class=&quot;hljs&quot;&gt;website_route&lt;/code&gt; definition to use &lt;code class=&quot;hljs&quot;&gt;make_handler_remove_suffix&lt;/code&gt; is
quite easy as well.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-patch&quot;&gt; let website_route =
   Dream.scope &quot;~lthms&quot; []
&lt;span class=&quot;hljs-deletion&quot;&gt;-  @@ List.map&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+  @@ List.concat_map&lt;/span&gt;
        (fun path -&amp;gt;
          let content = Option.get (Website_content.read path) in
&lt;span class=&quot;hljs-deletion&quot;&gt;-         make_handler ~content path)&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+         if path = &quot;index.html&quot; then&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+           (* Special case to deal with &quot;index.html&quot; which needs to be&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+              recognized by the route &quot;/&quot; *)&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+           [&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+             make_handler ~content &quot;/&quot;;&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+             make_handler ~content &quot;&quot;;&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+             make_handler ~content &quot;index.html&quot;;&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+           ]&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+         else&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+           make_handler_remove_suffix ~content path&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+             &quot;/index.html&quot;&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+           @ make_handler_remove_suffix ~content&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+               path &quot;index.html&quot;&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+           @ [ make_handler ~content path ])&lt;/span&gt;
        Website_content.file_list
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that, &lt;code class=&quot;hljs&quot;&gt;https://soap.coffee/~lthms/posts/index.html&lt;/code&gt; returns the same pages
as &lt;code class=&quot;hljs&quot;&gt;https://soap.coffee/~lthms/posts&lt;/code&gt; or &lt;code class=&quot;hljs&quot;&gt;https://soap.coffee/~lthms/posts&lt;/code&gt;.
Check.&lt;/p&gt;
&lt;h3&gt;Supporting &lt;code class=&quot;hljs&quot;&gt;Content-Type&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;hljs&quot;&gt;Content-Type&lt;/code&gt; is an HTTP header which is used by the receiver of the HTTP
message (whether it is a request or a response) to interpret its content.&lt;/p&gt;
&lt;p&gt;For instance, when building a RPC API, &lt;code class=&quot;hljs&quot;&gt;Content-Type&lt;/code&gt; is used by the server to
know how to parse the request body (&lt;code class=&quot;hljs language-http&quot;&gt;&lt;span class=&quot;hljs-attribute&quot;&gt;Content-Type&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;: &lt;/span&gt;application/json&lt;/code&gt; or
&lt;code class=&quot;hljs language-http&quot;&gt;&lt;span class=&quot;hljs-attribute&quot;&gt;Content-Type&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;: &lt;/span&gt;application/octet-stream&lt;/code&gt; being two popular choices, for
JSON or binary encoding, respectively).&lt;/p&gt;
&lt;p&gt;In our case, the &lt;code class=&quot;hljs&quot;&gt;Content-Type&lt;/code&gt; header is used by the HTTP server to
communicate the nature of the content to browsers. For my website, I can just
use the file extensions to infer the correct header to set. First, we list the
extensions that are actually used.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; content_types =
  [
    (&lt;span class=&quot;hljs-string&quot;&gt;&quot;.html&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;text/html&quot;&lt;/span&gt;);
    (&lt;span class=&quot;hljs-string&quot;&gt;&quot;.css&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;text/css&quot;&lt;/span&gt;);
    (&lt;span class=&quot;hljs-string&quot;&gt;&quot;.xml&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;text/xml&quot;&lt;/span&gt;);
    (&lt;span class=&quot;hljs-string&quot;&gt;&quot;.png&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;image/png&quot;&lt;/span&gt;);
    (&lt;span class=&quot;hljs-string&quot;&gt;&quot;.svg&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;image/svg+xml&quot;&lt;/span&gt;);
    (&lt;span class=&quot;hljs-string&quot;&gt;&quot;.gz&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;application/gzip&quot;&lt;/span&gt;);
    (&lt;span class=&quot;hljs-string&quot;&gt;&quot;.pub&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;text/plain&quot;&lt;/span&gt;);
  ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A header in Dream is encoded as a &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; * &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;&lt;/code&gt; value, with the
first &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;&lt;/code&gt; being the header name and the second being the header
value.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; content_type_header path =
  &lt;span class=&quot;hljs-type&quot;&gt;List&lt;/span&gt;.filter_map
    (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; (ext, content_type) -&amp;gt;
      &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;String&lt;/span&gt;.ends_with ~suffix:ext path &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;
        &lt;span class=&quot;hljs-type&quot;&gt;Some&lt;/span&gt; (&lt;span class=&quot;hljs-string&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt;, content_type)
      &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;None&lt;/span&gt;)
    content_types
  |&amp;gt; assert_f
       ~error_msg:&lt;span class=&quot;hljs-type&quot;&gt;Format&lt;/span&gt;.(sprintf &lt;span class=&quot;hljs-string&quot;&gt;&quot;Unsupported file type %s&quot;&lt;/span&gt; path)
       (( &amp;lt;&amp;gt; ) &lt;span class=&quot;hljs-literal&quot;&gt;[]&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;with &lt;code class=&quot;hljs language-ocaml&quot;&gt;assert_f&lt;/code&gt; being defined as follows.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; assert_f ~error_msg f v =
  &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; f v &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt; v &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; failwith error_msg
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;assert_f&lt;/code&gt; is used to enforce that I don’t deploy a website which
contains route lacking a &lt;code class=&quot;hljs&quot;&gt;Content-Type&lt;/code&gt; header. For instance, if I remove the
&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-string&quot;&gt;&quot;html&quot;&lt;/span&gt;&lt;/code&gt; entry of the &lt;code class=&quot;hljs language-ocaml&quot;&gt;content_type&lt;/code&gt; list, I get this error
when I try to execute the server.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;Fatal error: exception Failure(&quot;Unsupported file type index.html&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is because the headers are only computed once, when each &lt;code class=&quot;hljs&quot;&gt;route&lt;/code&gt; are
defined. This is a key principle of this project: compute once, serve many
time&lt;label for=&quot;fn3&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn3&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I would love to get a compilation error instead (considering there
are no runtime values involved), but have not looked into this just yet. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-patch&quot;&gt; let website_route =
   Dream.scope &quot;~lthms&quot; []
   @@ List.concat_map
        (fun path -&amp;gt;
          let content = Option.get (Website_content.read path) in
&lt;span class=&quot;hljs-addition&quot;&gt;+         let headers = content_type_header path in&lt;/span&gt;
          if path = &quot;index.html&quot; then
            (* Special case to deal with &quot;index.html&quot; which needs to be
               recognized by the route &quot;/&quot; *)
            [
&lt;span class=&quot;hljs-deletion&quot;&gt;-             make_handler ~content &quot;/&quot;;&lt;/span&gt;
&lt;span class=&quot;hljs-deletion&quot;&gt;-             make_handler ~content &quot;&quot;;&lt;/span&gt;
&lt;span class=&quot;hljs-deletion&quot;&gt;-             make_handler ~content &quot;index.html&quot;;&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+             make_handler ~headers ~content &quot;/&quot;;&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+             make_handler ~headers ~content &quot;&quot;;&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+             make_handler ~headers ~content &quot;index.html&quot;;&lt;/span&gt;
            ]
          else
&lt;span class=&quot;hljs-deletion&quot;&gt;-           make_handler_remove_suffix ~content path&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+           make_handler_remove_suffix ~headers ~content path&lt;/span&gt;
              &quot;/index.html&quot;
&lt;span class=&quot;hljs-deletion&quot;&gt;-           @ make_handler_remove_suffix ~content&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+           @ make_handler_remove_suffix ~headers ~content&lt;/span&gt;
                path &quot;index.html&quot;
&lt;span class=&quot;hljs-deletion&quot;&gt;-           @ [ make_handler ~content path ])&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+           @ [ make_handler ~headers ~content path ])&lt;/span&gt;
        Website_content.file_list
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(The changes in &lt;code class=&quot;hljs&quot;&gt;make_handler&lt;/code&gt; and &lt;code class=&quot;hljs&quot;&gt;make_handler_remove_prefix&lt;/code&gt; are left as an
exercise to enthusiast readers)&lt;/p&gt;
&lt;h3&gt;Compressing if Requested&lt;/h3&gt;
&lt;p&gt;Nowadays, computations are cheap, while downloading data costs time (and
sometimes money). As a consequence, it is often a good idea for a server to
compress a large HTTP response, and browsers do ask them to do so, by setting
the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs language-http&quot;&gt;Accept-Encoding&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; header of their requests.&lt;/p&gt;
&lt;p&gt;The value of the &lt;code class=&quot;hljs language-http&quot;&gt;Accept-Encoding&lt;/code&gt; header is a comma-separated list of
supported compression algorithms, optionally ordered with a priority value &lt;code class=&quot;hljs&quot;&gt;q&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For instance, &lt;code class=&quot;hljs language-http&quot;&gt;&lt;span class=&quot;hljs-attribute&quot;&gt;Accept-Encoding&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;: &lt;/span&gt;gzip;q=0.5, deflate;q=0.3, identity&lt;/code&gt;
tells you that the browser supports three encoding methods: &lt;code class=&quot;hljs&quot;&gt;gzip&lt;/code&gt;, &lt;code class=&quot;hljs&quot;&gt;deflate&lt;/code&gt;
and &lt;code class=&quot;hljs&quot;&gt;identity&lt;/code&gt; (no compression), and the browser prefers &lt;code class=&quot;hljs&quot;&gt;gzip&lt;/code&gt; over &lt;code class=&quot;hljs&quot;&gt;deflate&lt;/code&gt;.
Besides, the request can provide several &lt;code class=&quot;hljs&quot;&gt;Accept-Encoding&lt;/code&gt; headers instead of
just one, so we can have&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-http&quot;&gt;&lt;span class=&quot;hljs-attribute&quot;&gt;Accept-Encoding&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;: &lt;/span&gt;gzip;q=0.5
&lt;span class=&quot;hljs-attribute&quot;&gt;Accept-Encoding&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;: &lt;/span&gt;deflate;q=0.3
&lt;span class=&quot;hljs-attribute&quot;&gt;Accept-Encoding&lt;/span&gt;&lt;span class=&quot;hljs-punctuation&quot;&gt;: &lt;/span&gt;identity
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code class=&quot;hljs&quot;&gt;String&lt;/code&gt; module provides everything we need to check if a browser
supports gzip as an encoding method&lt;label for=&quot;fn4&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn4&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Spoiler: they do. I was even wondering at some point if I could
just &lt;em&gt;always&lt;/em&gt; return GZIP-compressed values, ignoring the
&lt;code class=&quot;hljs language-http&quot;&gt;Accept-Encoding&lt;/code&gt; header altogether. If you do that, though, &lt;code class=&quot;hljs&quot;&gt;curl&lt;/code&gt;
becomes annoying to use (it does not uncompress the response automatically,
and instead complains about being about to write binary to the standard
output). &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;(* For [method(; q=val)?], returns [method], except if
   [q=0]. *)&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; to_directive str =
  &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;String&lt;/span&gt;.split_on_char &lt;span class=&quot;hljs-string&quot;&gt;&apos;;&apos;&lt;/span&gt; str |&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;List&lt;/span&gt;.map &lt;span class=&quot;hljs-type&quot;&gt;String&lt;/span&gt;.trim &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;
  | [ x ] -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;Some&lt;/span&gt; x
  | [ x; y ] -&amp;gt; (
      &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;String&lt;/span&gt;.split_on_char &lt;span class=&quot;hljs-string&quot;&gt;&apos;=&apos;&lt;/span&gt; y |&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;List&lt;/span&gt;.map &lt;span class=&quot;hljs-type&quot;&gt;String&lt;/span&gt;.trim &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;
      | [ &lt;span class=&quot;hljs-string&quot;&gt;&quot;q&quot;&lt;/span&gt;; &lt;span class=&quot;hljs-string&quot;&gt;&quot;0&quot;&lt;/span&gt; ] -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;None&lt;/span&gt;
      | [ &lt;span class=&quot;hljs-string&quot;&gt;&quot;q&quot;&lt;/span&gt;; _ ] -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;Some&lt;/span&gt; x
      | _ -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;None&lt;/span&gt;)
  | _ -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;None&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;(* [contains ~value:v header] returns [true] if [v] is a
   supported method listed in [header]. *)&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; contains ~&lt;span class=&quot;hljs-keyword&quot;&gt;value&lt;/span&gt; header =
  &lt;span class=&quot;hljs-type&quot;&gt;String&lt;/span&gt;.split_on_char &lt;span class=&quot;hljs-string&quot;&gt;&apos;,&apos;&lt;/span&gt; header
  |&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;List&lt;/span&gt;.to_seq |&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;Seq&lt;/span&gt;.map &lt;span class=&quot;hljs-type&quot;&gt;String&lt;/span&gt;.trim
  |&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;Seq&lt;/span&gt;.filter_map to_directive
  |&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;Seq&lt;/span&gt;.exists (( = ) &lt;span class=&quot;hljs-keyword&quot;&gt;value&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We use &lt;code class=&quot;hljs language-ocaml&quot;&gt;contains&lt;/code&gt; to tell us if we can return a compressed response,
which leaves us with one final question: how to compress said response?&lt;/p&gt;
&lt;p&gt;The OCaml ecosystem seems to have picked &lt;a href=&quot;https://ocaml.org/p/camlzip/latest&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;camlzip&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; library when GZIP is
involved&lt;label for=&quot;fn5&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn5&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;You know it is a legitimate OCaml library when one of the top-level
modules &lt;a href=&quot;https://ocaml.org/p/camlzip/latest/doc/Zlib/&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;is not documented at all&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. &lt;/span&gt;
&lt;/span&gt;. What is surprising with this library is that it does not
support in-memory compression: the functions expect channels, not
&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;bytes&lt;/span&gt;&lt;/code&gt;. That is quite annoying, because we are specifically doing this
&lt;strong&gt;not&lt;/strong&gt; to use files.&lt;/p&gt;
&lt;p&gt;The Internet is helpful here, and quickly suggests using pipes. It works when
you remember –or figure out– that pipes are a blocking mechanism: one does not
just write a buffer of arbitrary size in a pipe, because after something like
4KBytes, writing becomes blocking until a read happens to free some space.
That’s not a big problem: we can read and write concurrently to the pipe using
threads, and OCaml 5 makes it quite easy to do so with the &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Domain&lt;/span&gt;&lt;/code&gt;
module.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; gzip content =
  &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; inc, ouc = &lt;span class=&quot;hljs-type&quot;&gt;Unix&lt;/span&gt;.pipe &lt;span class=&quot;hljs-literal&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; ouc = &lt;span class=&quot;hljs-type&quot;&gt;Gzip&lt;/span&gt;.open_out_chan ~level:&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;Unix&lt;/span&gt;.(out_channel_of_descr ouc) &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; _writer =
    &lt;span class=&quot;hljs-type&quot;&gt;Domain&lt;/span&gt;.spawn (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;()&lt;/span&gt; -&amp;gt;
        &lt;span class=&quot;hljs-type&quot;&gt;Gzip&lt;/span&gt;.output_substring ouc content &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;String&lt;/span&gt;.(length content);
        &lt;span class=&quot;hljs-type&quot;&gt;Gzip&lt;/span&gt;.close_out ouc)
  &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; res = &lt;span class=&quot;hljs-type&quot;&gt;In_channel&lt;/span&gt;.input_all &lt;span class=&quot;hljs-type&quot;&gt;Unix&lt;/span&gt;.(in_channel_of_descr inc) &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;
  &lt;span class=&quot;hljs-type&quot;&gt;Unix&lt;/span&gt;.close inc;
  res
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;markdown-alert markdown-alert-caution&quot;&gt;&lt;p class=&quot;markdown-alert-title&quot;&gt;&lt;svg class=&quot;octicon octicon-stop mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;Caution&lt;/p&gt;&lt;p&gt;As rightfully &lt;a href=&quot;https://discuss.ocaml.org/t/serving-this-article-from-ram-with-dream-for-fun-and-no-real-benefit/15856/6?u=lthms&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;pointed out&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; by &lt;a href=&quot;https://erratique.ch/contact.en&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;Daniel Bünzli&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, the &lt;code class=&quot;hljs&quot;&gt;gzip&lt;/code&gt;
function presented in this article is full of shortcomings. To quote the
message, &lt;em&gt;the function can leak fds in case of errors and domains are not
meant to be used that way (it’s rather spawn one long running domain per CPU
you have). It’s not necessarily more complicated to correct it to use
Fun.protect invocations to make sure all your fds get closed even if the
function blows up and use Thread.create so that the netizens cut and paste
correct code.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In my opinion, this implementation is “good enough” for my use case, which is
compressing arbitrary strings before the HTTP server is even started. If it
were to be called in the handlers themselves, then definitely, it would not
be suitable.&lt;/p&gt;
&lt;p&gt;Keep that in mind if you want to borrow this code.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;We know how to decide whether to compress or not, and how to compress. The next
step is to modify &lt;code class=&quot;hljs&quot;&gt;make_handler&lt;/code&gt; accordingly.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-patch&quot;&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-let make_handler ~headers ~content path =&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+let make_handler ~headers ~gzip_content ~content path =&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+  let gzip_headers = (&quot;Content-Encoding&quot;, &quot;gzip&quot;) :: headers in&lt;/span&gt;
   Dream.get path (fun req -&amp;gt;
&lt;span class=&quot;hljs-deletion&quot;&gt;-    Lwt.return (Dream.response content)))&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+      match Dream.headers req &quot;Accept-Encoding&quot; with&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+      | accepted_encodings&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+        when List.exists (contains ~value:&quot;gzip&quot;) accepted_encodings -&amp;gt;&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+          Lwt.return @@ Dream.response ~headers:gzip_headers gzip_content&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+      | _ -&amp;gt; Lwt.return @@ Dream.response ~headers content)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code class=&quot;hljs&quot;&gt;gzip_content&lt;/code&gt; is computed only once (using our &lt;code class=&quot;hljs&quot;&gt;gzip&lt;/code&gt; function), and passed to
&lt;code class=&quot;hljs&quot;&gt;make_handler&lt;/code&gt;. This way, the only computation the handler needs to do is to
“parse” &lt;code class=&quot;hljs&quot;&gt;Accept-Encoding&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Caching&lt;/h3&gt;
&lt;p&gt;Compressing a page to reduce the number of bytes a browser needs to download is
fine. Letting the browser know it does not need to download anything because
it&apos;s previous version is still accurate is better.&lt;/p&gt;
&lt;p&gt;This is achieved through two complementary mechanisms: &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;entity tags&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;
(&lt;code class=&quot;hljs language-http&quot;&gt;ETag&lt;/code&gt;)&lt;label for=&quot;fn6&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn6&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;My first encounter with entity tags was around the time GDPR was a
hot topic, because you can use them as a cheap replacement for cookies to
&lt;a href=&quot;https://levelup.gitconnected.com/no-cookies-no-problem-using-etags-for-user-tracking-3e745544176b&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;track your users&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. I remained at the surface level at the time,
it was fun learning more about them through this little project. &lt;/span&gt;
&lt;/span&gt;, and &lt;a href=&quot;https://developer.mozilla.org/fr/docs/Web/HTTP/Headers/Cache-Control&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;cache policies&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; (&lt;code class=&quot;hljs language-http&quot;&gt;Cache-Control&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Entity tags are used to identify a resource, and are expected to change
every time the resource is updated. The general workflow goes like this: the
first time a browser requests &lt;code class=&quot;hljs&quot;&gt;https://soap.coffee/~lthms/index.html&lt;/code&gt;, it
caches the result along with the value of the &lt;code class=&quot;hljs language-http&quot;&gt;ETag&lt;/code&gt; header. The next
time it needs the page, it adds the header &lt;code class=&quot;hljs language-http&quot;&gt;If-None-Match&lt;/code&gt;, with the
ETag as its value. For such requests, the server is expected to return an empty
response with HTTP code 304 (&lt;em&gt;Not Modified&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;I decided to use the sha256 hash algorithm to compute the entity tag of each
resource of my website. The &lt;a href=&quot;https://ocaml.org/p/sha/latest&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;sha&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; OCaml library looked like a good enough
candidate.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;(* in `website_route` *)&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; etag = &lt;span class=&quot;hljs-type&quot;&gt;Sha256&lt;/span&gt;.(&lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; content |&amp;gt; to_hex) &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Interestingly, one question I had to answer was whether the entity tag of a
page needed to be different whether it was compressed or not. Internet almost
unanimously answered yes. So be it. We just need to keep in mind ETag values
are expected to be surrounded by quotes, and we are good to go. It is just a
matter of suffixing the ETag with &lt;code class=&quot;hljs&quot;&gt;+gzip&lt;/code&gt; in the compressed case.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-patch&quot;&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-let make_handler ~headers ~gzip_content ~content path =&lt;/span&gt;
&lt;span class=&quot;hljs-deletion&quot;&gt;-  let gzip_headers = (&quot;Content-Encoding&quot;, &quot;gzip&quot;) :: headers in&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+let make_handler ~headers ~etag ~gzip_content ~content path =&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+  let etag_gzip = Format.sprintf &quot;\&quot;%s+gzip\&quot;&quot; etag in&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+  let etag = Format.sprintf &quot;\&quot;%s\&quot;&quot; etag in&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+  let gzip_headers =&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+    (&quot;Content-Encoding&quot;, &quot;gzip&quot;) :: (&quot;ETag&quot;, etag_gzip) :: headers in&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+  let identity_headers = (&quot;ETag&quot;, etag) :: headers in&lt;/span&gt;
   Dream.get path (fun req -&amp;gt;
&lt;span class=&quot;hljs-deletion&quot;&gt;-      match Dream.headers req &quot;Accept-Encoding&quot; with&lt;/span&gt;
&lt;span class=&quot;hljs-deletion&quot;&gt;-      | accepted_encodings&lt;/span&gt;
&lt;span class=&quot;hljs-deletion&quot;&gt;-        when List.exists (contains ~value:&quot;gzip&quot;) accepted_encodings -&amp;gt;&lt;/span&gt;
&lt;span class=&quot;hljs-deletion&quot;&gt;-          Lwt.return @@ Dream.response ~headers:gzip_headers gzip_content&lt;/span&gt;
&lt;span class=&quot;hljs-deletion&quot;&gt;-      | _ -&amp;gt; Lwt.return @@ Dream.response ~headers content)&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+      match Dream.headers req &quot;If-None-Match&quot; with&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+      | [ previous_etag ] when previous_etag = etag || previous_etag = etag_gzip&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+        -&amp;gt;&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+          Lwt.return&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+          @@ Dream.response&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+               ~headers:((&quot;ETag&quot;, previous_etag) :: headers)&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+               ~code:304 &quot;&quot;&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+      | _ -&amp;gt; (&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+          match Dream.headers req &quot;Accept-Encoding&quot; with&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+          | accepted_encodings&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+            when List.exists (contains ~value:&quot;gzip&quot;) accepted_encodings -&amp;gt;&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+              Lwt.return @@ Dream.response ~headers:gzip_headers gzip_content&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+          | _ -&amp;gt; Lwt.return @@ Dream.response ~headers:identity_headers content))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Entity tags are useful, but you still need the browser to make an HTTP request
every single time you visit the website. By setting a cache policy, we can
remove even remove the need for this request most of the time. The
&lt;code class=&quot;hljs language-http&quot;&gt;Cache-Control&lt;/code&gt; header is used to set a number of parameters, including
the &lt;code class=&quot;hljs&quot;&gt;max-age&lt;/code&gt; value (in seconds).&lt;/p&gt;
&lt;p&gt;In my Nginx configuration, I had set &lt;code class=&quot;hljs&quot;&gt;max-age&lt;/code&gt; to a year for images. I did
the same thing here. Besides, I decided to set &lt;code class=&quot;hljs&quot;&gt;max-age&lt;/code&gt; for other resources
to 5 minutes. This seems like a good compromise: since my website does not
change very often, it is very unlikely that you happen to visit it when I
publish new content. Setting a 5-minute cache policy should let my readers
download each resource only once, yet get the freshest version at their next
visit&lt;label for=&quot;fn7&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn7&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Dealing with the &lt;code class=&quot;hljs language-http&quot;&gt;Cache-Control&lt;/code&gt; header is basically the same
exercise as setting the correct &lt;code class=&quot;hljs language-http&quot;&gt;Content-Type&lt;/code&gt; header, and this
article is already long enough, which is why there is no diff or snippet in
this section. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;And with this, we are done. We get a standalone library to server our website
in a browser-friendly manner, which I can theoretically use to replace my
current Nginx-powered setup. Although… is it &lt;em&gt;that&lt;/em&gt; simple?&lt;/p&gt;
&lt;h2&gt;Building and Deploying the Website&lt;/h2&gt;
&lt;p&gt;Files are quite easy to share and deploy. As I mentioned earlier in this
article, you just need to &lt;code class=&quot;hljs language-bash&quot;&gt;rsync&lt;/code&gt; them and be done with it. &lt;em&gt;Binaries&lt;/em&gt;,
on the other hand… One cannot just assume a binary build on a machine X will
work on another machine Y. Some additional works need to be done.&lt;/p&gt;
&lt;p&gt;The most straightforward solution I know is to rely on static binaries. &lt;a href=&quot;OCamlStaticBinaries.html&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;I have
already written about how to generate static binaries for OCaml
projects&lt;/a&gt;, so I had a pretty strong head start, but one drawback of the
approach I’ve described there (and that I have been using for &lt;a href=&quot;https://github.com/lthms/spatial-shell/releases&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;Spatial Shell’s
releases&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;&lt;label for=&quot;fn8&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn8&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Not that there were many of them lately. &lt;/span&gt;
&lt;/span&gt;) is that it is rather slow (I have a script creating
a new local switch each time) and requires static libraries to be installed
(which Arch Linux does not provide).&lt;/p&gt;
&lt;p&gt;And so, I figured, why not build the static binary in Docker? This allows me to
use Alpine to get a static version of my system dependencies, and can be quite
fast thanks to &lt;a href=&quot;https://docs.docker.com/build/cache/&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;Docker build cache&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. The Dockerfile is quite simple:
one stage for building the system and OCaml dependencies, and one stage for
building the static binary.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-dockerfile&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;FROM&lt;/span&gt; alpine:&lt;span class=&quot;hljs-number&quot;&gt;3.21&lt;/span&gt; AS build_environment

&lt;span class=&quot;hljs-comment&quot;&gt;# Use alpine /bin/ash and set shell options&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;# See https://docs.docker.com/build/building/best-practices/#using-pipes&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;SHELL&lt;/span&gt;&lt;span class=&quot;language-bash&quot;&gt; [&lt;span class=&quot;hljs-string&quot;&gt;&quot;/bin/ash&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;-euo&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;pipefail&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;-c&quot;&lt;/span&gt;]&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;USER&lt;/span&gt; root
&lt;span class=&quot;hljs-keyword&quot;&gt;WORKDIR&lt;/span&gt;&lt;span class=&quot;language-bash&quot;&gt; /root&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;RUN&lt;/span&gt;&lt;span class=&quot;language-bash&quot;&gt; apk add autoconf automake bash build-base ca-certificates opam gcc \ &lt;/span&gt;
  git rsync gmp-dev libev-dev openssl-libs-static pkgconf zlib-static \
  openssl-dev zlib-dev
&lt;span class=&quot;hljs-keyword&quot;&gt;RUN&lt;/span&gt;&lt;span class=&quot;language-bash&quot;&gt; opam init --bare --&lt;span class=&quot;hljs-built_in&quot;&gt;yes&lt;/span&gt; --disable-sandboxing&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;COPY&lt;/span&gt;&lt;span class=&quot;language-bash&quot;&gt; makefile dune-project .&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;RUN&lt;/span&gt;&lt;span class=&quot;language-bash&quot;&gt; make _opam/.init OCAML=&lt;span class=&quot;hljs-string&quot;&gt;&quot;ocaml-option-static,ocaml-option-no-compression,ocaml.5.2.1&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;RUN&lt;/span&gt;&lt;span class=&quot;language-bash&quot;&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;eval&lt;/span&gt; $(opam &lt;span class=&quot;hljs-built_in&quot;&gt;env&lt;/span&gt;) &amp;amp;&amp;amp; make server-deps&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;FROM&lt;/span&gt; build_environment AS builder

&lt;span class=&quot;hljs-keyword&quot;&gt;COPY&lt;/span&gt;&lt;span class=&quot;language-bash&quot;&gt; server ./server&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;COPY&lt;/span&gt;&lt;span class=&quot;language-bash&quot;&gt; out ./out&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;COPY&lt;/span&gt;&lt;span class=&quot;language-bash&quot;&gt; dune .&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;RUN&lt;/span&gt;&lt;span class=&quot;language-bash&quot;&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;eval&lt;/span&gt; $(opam &lt;span class=&quot;hljs-built_in&quot;&gt;env&lt;/span&gt;) &amp;amp;&amp;amp; dune build server/main.exe --profile=static&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;FROM&lt;/span&gt; alpine:&lt;span class=&quot;hljs-number&quot;&gt;3.21&lt;/span&gt; AS soap.coffee

&lt;span class=&quot;hljs-keyword&quot;&gt;COPY&lt;/span&gt;&lt;span class=&quot;language-bash&quot;&gt; --from=builder /root/_build/default/server/main.exe /bin/soap.coffee&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, building my static binary becomes as simple as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;docker build . -f ./build.Dockerfile \
  --target soap.coffee \
  -t soap.coffee:latest
docker create --name soap-coffee-build soap.coffee:latest
docker &lt;span class=&quot;hljs-built_in&quot;&gt;cp&lt;/span&gt; soap-coffee-build:/bin/soap.coffee .
docker &lt;span class=&quot;hljs-built_in&quot;&gt;rm&lt;/span&gt; -f soap-coffee-build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;docker &lt;span class=&quot;hljs-built_in&quot;&gt;cp&lt;/span&gt;&lt;/code&gt; does not work on an image, but on a container, so we need to
create one which can be destroyed shortly after.&lt;/p&gt;
&lt;p&gt;This little binary weights 38MBytes, which seems relatively reasonable to me,
considering my website weights 20MBytes. I guess it could be easy to reduce
this size by embedding the compressed version of my articles and images,
instead of the uncompressed one. But really, for my website, I’m not really
interested in investing the extra effort.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I would not recommend anyone to use this in production for anything remotely
important, but from my perspective, it was both fun and insightful. I was able
to refresh my memories about HTTP “internal,” among other things.&amp;nbsp;Again, as
far as I can tell, deploying my website this way did not bring me any benefit,
performance-wise; even worse, I am pretty sure the Dream server will not behave
as well as Nginx when it comes to handling the load (since it is limited to one
core, instead of several with Nginx).&lt;/p&gt;
&lt;p&gt;That being said, I am way too invested now… which is why, yes, you are
reading a blog post served to you directly from memory 🎉.&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>On Vestigial Structures</title>
      <link>https://soap.coffee/~lthms/posts/VestigialStructures.html</link>
      <guid>https://soap.coffee/~lthms/posts/VestigialStructures.html</guid>
      <pubDate>August 16, 2024</pubDate>
      <description>
        
        &lt;h1&gt;On Vestigial Structures&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/satire.html&quot; class=&quot;tag hover-periwinkle&quot; marked=&quot;&quot;&gt;satire&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/ocaml.html&quot; class=&quot;tag hover-peach&quot; marked=&quot;&quot;&gt;ocaml&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;Do you know what vestigial structures are?&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;This write-up is a slightly modified version of a commit description I have
written for &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$WORK&lt;/span&gt;&lt;/code&gt; with &lt;a href=&quot;https://chatgpt.com/share/f9c72991-7502-4048-9c10-0db5c93726be&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;some help from ChatGPT&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. &lt;/span&gt;
&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;In a nutshell, they are remnants of structures that were functional in an
ancestral species but have lost much or all of their original function in the
descendant species.&lt;/p&gt;
&lt;p&gt;For instance, some snakes, like pythons and boas, have tiny remnants of hind
leg bones, which are vestigial structures from when their ancestors had legs.
Birds like ostriches and emus have wings that are too small for flight. These
wings are vestigial structures as well, remnants of their flying ancestors.
Even humans have some, like those small muscles around their ears. These
muscles were once used by our ancestors to move their ears, similar to how many
animals can today.&lt;/p&gt;
&lt;p&gt;Sometimes, vestigial structures are not just useless, they can be harmful. Take
our wisdom teeth. They were handy to our ancestors, who had larger jaws and a
diet that required more chewing. Sadly, they have become problematic for many
modern humans.&lt;/p&gt;
&lt;p&gt;Anyway, &lt;code class=&quot;hljs&quot;&gt;ocaml-migrate-parsetree&lt;/code&gt; is a deprecated OCaml library in
&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$WORK&lt;/span&gt;&lt;/code&gt;’s dependency tree that will never be compatible with OCaml 5,
but it turns out &lt;a href=&quot;https://gitlab.com/tezos/tezos/-/commit/9973676470b5582eb08cb430551e030abba9d5aa&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;we do not need it anymore&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>Introducing bepo-tsrn.nvim</title>
      <link>https://soap.coffee/~lthms/posts/BepoNvim.html</link>
      <guid>https://soap.coffee/~lthms/posts/BepoNvim.html</guid>
      <pubDate>May 23, 2024</pubDate>
      <description>
        
        &lt;h1&gt;Introducing &lt;code class=&quot;hljs&quot;&gt;bepo-tsrn.nvim&lt;/code&gt;&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/neovim.html&quot; class=&quot;tag hover-mint&quot; marked=&quot;&quot;&gt;neovim&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/releases.html&quot; class=&quot;tag hover-coral&quot; marked=&quot;&quot;&gt;releases&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;It is not much, but I have recently &lt;a href=&quot;https://github.com/lthms/bepo-tsrn.nvim&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;published on
GitHub&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; what can be considered my very
first Neovim “plugin.”&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;hljs&quot;&gt;bepo-tsrn.nvim&lt;/code&gt; is a zero-configuration, global plugin for Neovim which remaps
default Neovim bindings for the &lt;a href=&quot;https://bepo.fr&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;Bépo&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; keyboard layout. It
started as a fork of &lt;a href=&quot;https://github.com/cljoly/bepo.nvim&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;bepo.nvim&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; with
two significant changes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;hljs&quot;&gt;hjkl&lt;/code&gt; are remapped to &lt;code class=&quot;hljs&quot;&gt;tsrn&lt;/code&gt; instead of &lt;code class=&quot;hljs&quot;&gt;ctsr&lt;/code&gt;. &lt;code class=&quot;hljs&quot;&gt;hjkl&lt;/code&gt; as motion keys always
had one great drawback in my opinion: they required me to shift my left hand
whenever I wanted to use them. Well, no more!&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;hljs&quot;&gt;bepo-tsrn.nvim&lt;/code&gt; is a global plugin, unconditionally loaded at startup
without the need to explicitely load it. As a consequence, it is a very
convenient way to get Bépo enabled in Neovim system-wide. Bonus point if you
are using Archlinux, since I have added it to the &lt;a href=&quot;https://aur.archlinux.org/packages/neovim-bepo-tsrn-git&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;Archlinux User
Repository&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; (AUR).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code class=&quot;hljs&quot;&gt;bepo-tsrn.nvim&lt;/code&gt; is released under the terms of the Apache-2.0 license
(inherited from &lt;a href=&quot;https://github.com/cljoly/bepo.nvim&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;bepo.nvim&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;). Granted,
this plugin targets a very small niche of users, but maybe you will find it as
useful as I do!&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>Installing a LUKS-Encrypted Arch Linux on a Vultr VPS</title>
      <link>https://soap.coffee/~lthms/posts/LUKSEncryptedVPS.html</link>
      <guid>https://soap.coffee/~lthms/posts/LUKSEncryptedVPS.html</guid>
      <pubDate>February 25, 2024</pubDate>
      <description>
        
        &lt;h1&gt;Installing a LUKS-Encrypted Arch Linux on a Vultr VPS&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/self-hosting.html&quot; class=&quot;tag hover-peach&quot; marked=&quot;&quot;&gt;self-hosting&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/vultr.html&quot; class=&quot;tag hover-coral&quot; marked=&quot;&quot;&gt;vultr&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;I’ve been a happy customer of &lt;a href=&quot;https://vultr.com&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;Vultr&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; for three years now. For one, this little
corner of the Internet is hosted on one of their VPS, along with other services
I have self-hosted. Recently, I have decided to migrate to a new
VPS with more disk space and more powerful vCPUs.&lt;/p&gt;
&lt;p&gt;In this article, I describe how I have set up the host (an Arch Linux system on
a LUKS-encrypted partition) of &lt;code class=&quot;hljs&quot;&gt;jasmine&lt;/code&gt;&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;jasmine&lt;/code&gt; being my shiny new server—I have taken the habit to name
my servers and personal computers after Disney princesses. &lt;/span&gt;
&lt;/span&gt;. I had done a similar thing
for &lt;code class=&quot;hljs&quot;&gt;mulan&lt;/code&gt;, &lt;code class=&quot;hljs&quot;&gt;jasmine&lt;/code&gt;’s predecessor. Unfortunately, I didn’t take the time to
document &lt;code class=&quot;hljs&quot;&gt;mulan&lt;/code&gt; installation steps three years ago. Needless to say, I had
plenty of opportunities to regret this oversight while I painfully redicovered
how to make this work.&lt;/p&gt;
&lt;p&gt;Hopefully, most of what is in this write-up will stand the test of time and
remain true three years from now, when I migrate again 😅.&lt;/p&gt;
&lt;h2&gt;Booting on the Installation ISO&lt;/h2&gt;
&lt;p&gt;It is no surprise that Vultr does not propose an out-of-the-box LUKS-encrypted
Arch Linux installation in their OSes library. As a consequence, I had to boot
my brand new VPS on the &lt;a href=&quot;https://geo.mirror.pkgbuild.com/iso/&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;Arch Linux ISO&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In the Vultr dashboard, I visited the “ISOs” page (in the “Orchestrations”
menu) to add the latest Arch Linux installation ISO.&lt;/li&gt;
&lt;li&gt;Then, I went to the management panel of &lt;code class=&quot;hljs&quot;&gt;jasmine&lt;/code&gt;, more precisely in the
“Settings” tab. I visited the “Custom ISO” page, and attached the Arch Linux
ISO. This prompted a reboot.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code class=&quot;hljs&quot;&gt;jasmine&lt;/code&gt; happily booted the image, but the resulting system was lacking a SSH
server to connect to. Instead, I used the “View Console” feature to get a shell
access to my VPS&lt;label for=&quot;fn2&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn2&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;It is noteworthy that I had to disable one of my Firefox extensions:
Vimium. Vimium provides me vim-like keystrokes in the browser, and the keys
I am using for motion (&lt;code class=&quot;hljs&quot;&gt;t&lt;/code&gt;, &lt;code class=&quot;hljs&quot;&gt;s&lt;/code&gt;, &lt;code class=&quot;hljs&quot;&gt;r&lt;/code&gt;, and &lt;code class=&quot;hljs&quot;&gt;n&lt;/code&gt;) were not forwarded to the
console. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;The Arch Linux installation ISO’s default keymap is qwerty, a keyboard layout I
am helpless with. The first command I always use in this situation is
&lt;code class=&quot;hljs&quot;&gt;loadkeys&lt;/code&gt;, which allows me to switch to the &lt;a href=&quot;https://bepo.fr&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;fr-bepo&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; layout.&lt;/p&gt;
&lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;&lt;p class=&quot;markdown-alert-title&quot;&gt;&lt;svg class=&quot;octicon octicon-info mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;Note&lt;/p&gt;&lt;p&gt;In this article, I am using &lt;code class=&quot;hljs&quot;&gt;;&lt;/code&gt; as the terminal prompt for &lt;a href=&quot;https://twitter.com/leostera/status/1740796853174596007&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;ease of
copy/pasting&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;; loadkeys fr-bepo
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Remote Access to &lt;code class=&quot;hljs&quot;&gt;jasmine&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The next step was to start a SSH server I could connect to using my terminal
emulator. A virtual console is nice enough, but when your muscle memory
commands you to hit &lt;code class=&quot;hljs&quot;&gt;Ctrl-W&lt;/code&gt; to delete the word before your cursor as soon as
you are connected to a shell, you don’t want to stay in a browser tab for
obvious reasons.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I set up a password for the &lt;code class=&quot;hljs&quot;&gt;root&lt;/code&gt; user using &lt;code class=&quot;hljs&quot;&gt;passwd&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;I modified the &lt;code class=&quot;hljs&quot;&gt;/etc/ssh/sshd_config&lt;/code&gt; file to let me connect with the &lt;code class=&quot;hljs&quot;&gt;root&lt;/code&gt;
user using a password (&lt;code class=&quot;hljs&quot;&gt;PermitRootLogin yes&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;I started the SSH server using &lt;code class=&quot;hljs&quot;&gt;systemctl start sshd&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;From there, I could connect &lt;code class=&quot;hljs&quot;&gt;jasmine&lt;/code&gt; from my terminal emulator.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# after modifying /etc/hosts to add `jasmine` IP there&lt;/span&gt;
; ssh root@jasmine
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Disk Partitions&lt;/h2&gt;
&lt;p&gt;Now that I was enjoying the comfort of my terminal emulator of choice
(&lt;a href=&quot;https://sw.kovidgoyal.net/kitty/&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;kitty&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;), the serious business could start. Moving forward, my next task was
to set up the disk layout and the filesystems.&lt;/p&gt;
&lt;div class=&quot;markdown-alert markdown-alert-warning&quot;&gt;&lt;p class=&quot;markdown-alert-title&quot;&gt;&lt;svg class=&quot;octicon octicon-alert mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;Warning&lt;/p&gt;&lt;p&gt;Did you know that Vultr VPS are using legacy boot and &lt;em&gt;not&lt;/em&gt; UEFI? I surely
did, three years ago, but sadly I had forgotten. So I did a first
installation setup with a EFI partition layout (GPT, &lt;code class=&quot;hljs&quot;&gt;/boot&lt;/code&gt; formatted with
VFAT, etc.), only to discover that my shiny system could not boot.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;To create an MBR partition system, &lt;code class=&quot;hljs&quot;&gt;fdisk&lt;/code&gt; is a nice enough tool. The disk is
exposed to the VPS under the name &lt;code class=&quot;hljs&quot;&gt;/dev/vda&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;; fdisk /dev/vda
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Firstly, I created a new MBR.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;Command (m for help): o
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, I created the &lt;code class=&quot;hljs&quot;&gt;/boot&lt;/code&gt; partition. To be sure I would not run out of space,
I allocated 3GBytes for it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;Command (m for help): n
Partition number (1-128, default 1): 
First sector (34-268435422, default = 2048) or {+-}size{KMGTP}: 
Last sector (2048-268435422, default = 268433407) or {+-}size{KMGTP}: +3G
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The root partition was to take the remaining space.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;Command (m for help): n
Partition number (2-128, default 2): 
First sector (34-268435422, default = 6293504) or {+-}size{KMGTP}: 
Last sector (6293504-268435422, default = 268433407) or {+-}size{KMGTP}: 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I reviewed the resulting partition layout.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;
Command (m for help): p

Disk /dev/vda: 128 GiB, 137438953472 bytes, 268435456 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xdbc3620d

Device     Boot   Start       End   Sectors  Size Id Type
/dev/vda1          2048   6293503   6291456    3G 83 Linux
/dev/vda2       6293504 268435455 262141952  125G 83 Linux
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;LGTM!&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;Command (? for help): w
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Filesystems&lt;/h2&gt;
&lt;h3&gt;&lt;code class=&quot;hljs&quot;&gt;/boot&lt;/code&gt; Partition&lt;/h3&gt;
&lt;p&gt;No need to be particularly fancy here. I formatted &lt;code class=&quot;hljs&quot;&gt;/boot&lt;/code&gt; with the &lt;code class=&quot;hljs&quot;&gt;ext3&lt;/code&gt;
filesystem. As far as I know, this is a reasonable default choice for this
partition.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;; mkfs.ext3 /dev/vda1
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;LUKS-Encrypted Root Partition&lt;/h2&gt;
&lt;p&gt;I mostly followed the &lt;a href=&quot;https://wiki.archlinux.org/title/Dm-crypt/Encrypting_an_entire_system#LUKS_on_a_partition&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;Arch Linux Wiki&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; for this. Generally speaking, the Arch
Linux Wiki is a wonderful source of information for anything related to Linux.&lt;/p&gt;
&lt;p&gt;I formatted &lt;code class=&quot;hljs&quot;&gt;/dev/vda2&lt;/code&gt; with &lt;code class=&quot;hljs&quot;&gt;cryptsetup&lt;/code&gt; to initialize the encryption scheme.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;; cryptsetup -y -v luksFormat /dev/vda2
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;markdown-alert markdown-alert-important&quot;&gt;&lt;p class=&quot;markdown-alert-title&quot;&gt;&lt;svg class=&quot;octicon octicon-report mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v9.5A1.75 1.75 0 0 1 14.25 13H8.06l-2.573 2.573A1.458 1.458 0 0 1 3 14.543V13H1.75A1.75 1.75 0 0 1 0 11.25Zm1.75-.25a.25.25 0 0 0-.25.25v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25Zm7 2.25v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 9a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;Important&lt;/p&gt;&lt;p&gt;Be sure to save your LUKS passphrase somewhere, otherwise you are likely to
run in trouble at some point. I’ve personally added it to my Bitwarden.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;As-is, the partition cannot be used; it needs to be “open” with &lt;code class=&quot;hljs&quot;&gt;cryptsetup&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;; cryptsetup open /dev/vda2 root
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code class=&quot;hljs&quot;&gt;root&lt;/code&gt; here is the name given to the usable partition. More precisely,  after
this command the partition can be manipulated through the &lt;code class=&quot;hljs&quot;&gt;/dev/mapper/root&lt;/code&gt;
logical volume.&lt;/p&gt;
&lt;p&gt;Before, I had always used &lt;code class=&quot;hljs&quot;&gt;ext4&lt;/code&gt; for my root partition, but for a while I’ve
had an interest for alternative filesystems. And so, I decided out of the blue
to format &lt;code class=&quot;hljs&quot;&gt;/dev/mapper/root&lt;/code&gt; with &lt;code class=&quot;hljs&quot;&gt;btrfs&lt;/code&gt;&lt;label for=&quot;fn3&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn3&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Time will tell if this was a mistake… The Internet seems to suggest
it might be one 😅. &lt;/span&gt;
&lt;/span&gt;. I like the idea of a
filesystem compressing its contents by default.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;; mkfs.btrfs -d single -m single /dev/mapper/root
; mount -t btrfs -o defaults,noatime,compress=zstd /dev/mapper/root /mnt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, I could mount the two formatted partitions in &lt;code class=&quot;hljs&quot;&gt;/mnt&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;; &lt;span class=&quot;hljs-built_in&quot;&gt;mkdir&lt;/span&gt; /mnt/boot
; mount /dev/vda1 /mnt/boot
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Installing Arch Linux&lt;/h2&gt;
&lt;p&gt;I have installed the bare minimum with &lt;code class=&quot;hljs&quot;&gt;pacstrap&lt;/code&gt;. I personally prefer entering
in the chroot as soon as possible.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;; pacstrap -K /mnt base linux
; genfstab -U /mnt &amp;gt;&amp;gt; /mnt/etc/fstab
; arch-chroot /mnt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the rest of the article, I focus on the details that are directly related to
our main subject. That is, being able to boot a LUKS-encrypted Arch Linux VPS.
To that end, I have chosen to reproduce the exact setup I did three years ago
for &lt;code class=&quot;hljs&quot;&gt;mulan&lt;/code&gt;. It consists in configuring the initramfs to spawn an SSH server
(&lt;a href=&quot;https://tinyssh.org/&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;tinyssh&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;) which let me enter the LUKS passphrase of &lt;code class=&quot;hljs&quot;&gt;/dev/vda2&lt;/code&gt; remotely.&lt;/p&gt;
&lt;h2&gt;&lt;code class=&quot;hljs&quot;&gt;sshd&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Before configuring the boot process, it had to take a small detour and
configure the SSH server (&lt;code class=&quot;hljs&quot;&gt;sshd&lt;/code&gt; from OpenSSH) &lt;code class=&quot;hljs&quot;&gt;jasmine&lt;/code&gt; will start once it has
booted. The main reason is quite simple: I wanted tinyssh and &lt;code class=&quot;hljs&quot;&gt;sshd&lt;/code&gt; to use the
same host key.&lt;/p&gt;
&lt;p&gt;tinyssh is limited in terms of the key types it supports, but I personally
always default to Ed25519 so I’m fine with that.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;ssh-keygen -f /etc/ssh/ssh_host_ed25519_key -N &lt;span class=&quot;hljs-string&quot;&gt;&apos;&apos;&lt;/span&gt; -t ed25519
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I then modified &lt;code class=&quot;hljs&quot;&gt;/etc/ssh/sshd_config&lt;/code&gt; to ensure &lt;code class=&quot;hljs&quot;&gt;sshd&lt;/code&gt; would default to it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# in /etc/ssh/sshd_config, uncomment&lt;/span&gt;
HostKey /etc/ssh/ssh_host_ed25519_key
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I used this opportunity to also (temporarily) allow login as root using a
password. Eventually, I will definitely remove this line from &lt;code class=&quot;hljs&quot;&gt;sshd&lt;/code&gt; config,
but while I’m configuring everything, it’s too convenient to bother with
another approach.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# in /etc/ssh/sshd_config, add&lt;/span&gt;
PermitRootLogin &lt;span class=&quot;hljs-built_in&quot;&gt;yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This line is only useful if &lt;code class=&quot;hljs&quot;&gt;root&lt;/code&gt; has a password, so I initialized one.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;; passwd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I also enabled the &lt;code class=&quot;hljs&quot;&gt;sshd&lt;/code&gt; service, to let systemd start &lt;code class=&quot;hljs&quot;&gt;sshd&lt;/code&gt; automatically at
boot time.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;; systemctl &lt;span class=&quot;hljs-built_in&quot;&gt;enable&lt;/span&gt; sshd
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;TinySSH&lt;/h2&gt;
&lt;p&gt;At this point, I knew I had only dealt with the easy bits. The hard part is
to be able the damn thing.&lt;/p&gt;
&lt;p&gt;I have always used Busybox-based initial ramdisk. While rereading the Arch
Linux Wiki, I discovered it was also possible to use systemd, which… well,
nobody is surprised by this, I guess. I am a happy adopter of systemd multiple
features in general, but for the particular setup I am targeting, using systemd
means &lt;a href=&quot;https://wiki.archlinux.org/title/Dm-crypt/Specialties#systemd_based_initramfs_(built_with_mkinitcpio)&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;installing an AUR package&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. So I decided to stick with Busybox.&lt;/p&gt;
&lt;p&gt;I gathered and installed the packages I needed for this to work.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;; pacman -S tinyssh mkinitcpio-tinyssh mkinitcpio-netconf mkinitcpio-utils python3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And I modified &lt;code class=&quot;hljs&quot;&gt;/etc/mkinitcpio.conf&lt;/code&gt; to modify the &lt;code class=&quot;hljs&quot;&gt;HOOKS&lt;/code&gt; array.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-diff&quot;&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-HOOKS=(base udev autodetect modconf kms keyboard keymap consolefont block filesystems fsck)&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+HOOKS=(base udev autodetect modconf block netconf tinyssh encryptssh filesystems keyboard keymap fsck)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I tried to keep it minimal (hence the removal of &lt;code class=&quot;hljs&quot;&gt;kms&lt;/code&gt; for instance, which does
not seem very useful for a remote server considering its about setting display
resolution), and I borrowed from the &lt;code class=&quot;hljs&quot;&gt;/etc/mkinitcpio.conf&lt;/code&gt; file of &lt;code class=&quot;hljs&quot;&gt;mulan&lt;/code&gt; for
&lt;code class=&quot;hljs&quot;&gt;netconf&lt;/code&gt;, &lt;code class=&quot;hljs&quot;&gt;tinyssh&lt;/code&gt; and &lt;code class=&quot;hljs&quot;&gt;encryptssh&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Turns out &lt;code class=&quot;hljs&quot;&gt;mkinitcpio-tinyssh&lt;/code&gt; is affected by &lt;a href=&quot;https://github.com/grazzolini/mkinitcpio-tinyssh/issues/10&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;a long standing bug&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, but
fortunately the patch to &lt;code class=&quot;hljs&quot;&gt;/usr/lib/initcpio/install/tinyssh&lt;/code&gt; worked like a
charm.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-diff&quot;&gt;   local return_code=1
 
   if [ ! -d $destdir -a -x /usr/bin/tinyssh-convert ]; then
&lt;span class=&quot;hljs-deletion&quot;&gt;-      mkdir $destdir&lt;/span&gt;
&lt;span class=&quot;hljs-deletion&quot;&gt;-  fi&lt;/span&gt;
&lt;span class=&quot;hljs-deletion&quot;&gt;-  &lt;/span&gt;
&lt;span class=&quot;hljs-deletion&quot;&gt;-  if [ -s &quot;$osshed25519&quot; -a ! -s $destdir/.ed25519.sk -a ! -s $destdir/ed25519.pk -a -x /usr/bin/tinyssh-convert ]; then&lt;/span&gt;
&lt;span class=&quot;hljs-deletion&quot;&gt;-      tinyssh-convert -f $osshed25519 -d $destdir&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+      tinyssh-convert $destdir &amp;lt; $osshed25519&lt;/span&gt;
       if [ $? -eq 0 ]; then
           return_code=0
       fi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On my local machine, I generated a brand new SSH key using the Ed25519 key
type.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;; ssh-keygen -t ed25519 -f jasmine
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I copy/pasteed the content of &lt;code class=&quot;hljs&quot;&gt;jasmine.pub&lt;/code&gt; in &lt;code class=&quot;hljs&quot;&gt;/etc/tinyssh/root_key&lt;/code&gt; on
&lt;code class=&quot;hljs&quot;&gt;jasmine&lt;/code&gt;. It was also a good idea to delete the &lt;code class=&quot;hljs&quot;&gt;etc/tinyssh/sshkeydir&lt;/code&gt;
directory, before running the command to generate the initial ramkdisk.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;; mkinitcpio -p linux
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Grub&lt;/h2&gt;
&lt;p&gt;This is your periodic reminder that Vultr does not support UEFI and still
requires to the legacy MBR to boot. This means &lt;code class=&quot;hljs&quot;&gt;systemd-boot&lt;/code&gt; is out of the
picture. I always feel overwhelmed when i have to configure Grub. However,
three years ago I managed to make it work, so I decided to stick to this again.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;; pacman -S grub
; grub-install --target=i386-pc /dev/vda
; grub-mkconfig -o /boot/grub/grub.cfg
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code class=&quot;hljs&quot;&gt;/boot/grub/grub.cfg&lt;/code&gt; contains a lot of things. I looked for the line&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;### BEGIN /etc/grub.d/10_linux ###
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the first &lt;code class=&quot;hljs&quot;&gt;menuentry&lt;/code&gt; after it, I modified one line&lt;label for=&quot;fn4&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn4&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;My initial thought was to install the &lt;code class=&quot;hljs&quot;&gt;intel-ucode&lt;/code&gt; package, and to
configure Grub to load Intel’s microcode upgrades at boot time. However,
since &lt;code class=&quot;hljs&quot;&gt;jasmine&lt;/code&gt; is a VPS, it does not directly access the physical CPU it
is running onto. As a consequence, this step is not necessary. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;First, the &lt;code class=&quot;hljs&quot;&gt;linux&lt;/code&gt; line.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;        linux   /vmlinuz-linux root=/dev/mapper/root rw cryptdevice=UUID=7e58f868-529
a-4d70-bdfd-31317017c30b:root ip=&amp;lt;server ip&amp;gt;::&amp;lt;server gateway&amp;gt;:&amp;lt;server netmask&amp;gt;::eth0:none logle
vel=3 quiet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The one is the most tricky.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;hljs&quot;&gt;root=/ev/mapper/root rw&lt;/code&gt; is the most straightforward. It means the root
filesystem in located in &lt;code class=&quot;hljs&quot;&gt;/dev/mapper/root&lt;/code&gt;, that is a logical volume.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;hljs&quot;&gt;cryptdevice=UUID=7e58f868-529a-4d70-bdfd-31317017c30b:root&lt;/code&gt; tells the kernel
that the &lt;code class=&quot;hljs&quot;&gt;root&lt;/code&gt; logical volume is inside the encrypted (&lt;code class=&quot;hljs&quot;&gt;cryptdevice&lt;/code&gt;)
&lt;code class=&quot;hljs&quot;&gt;/dev/vda2&lt;/code&gt; partition. To get the &lt;code class=&quot;hljs&quot;&gt;UUID&lt;/code&gt; of &lt;code class=&quot;hljs&quot;&gt;/dev/vda2&lt;/code&gt;, I used &lt;code class=&quot;hljs&quot;&gt;blkid&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;; blkid | grep UUID
/dev/mapper/root: UUID=&lt;span class=&quot;hljs-string&quot;&gt;&quot;0a44e4c7-10b7-4e85-8228-7663cf16a631&quot;&lt;/span&gt; UUID_SUB=&lt;span class=&quot;hljs-string&quot;&gt;&quot;0c9edc1c-31c0-417d-93e2-6f035c68b7cb&quot;&lt;/span&gt; BLOCK_SIZE=&lt;span class=&quot;hljs-string&quot;&gt;&quot;4096&quot;&lt;/span&gt; TYPE=&lt;span class=&quot;hljs-string&quot;&gt;&quot;btrfs&quot;&lt;/span&gt;
/dev/vda2: UUID=&lt;span class=&quot;hljs-string&quot;&gt;&quot;e9695de0-403c-4a6c-b8a2-9891dca2a60a&quot;&lt;/span&gt; TYPE=&lt;span class=&quot;hljs-string&quot;&gt;&quot;crypto_LUKS&quot;&lt;/span&gt; PARTUUID=&lt;span class=&quot;hljs-string&quot;&gt;&quot;dbc3620d-02&quot;&lt;/span&gt;
/dev/vda1: UUID=&lt;span class=&quot;hljs-string&quot;&gt;&quot;fa7a24d2-fc76-4af2-b26c-58548650253f&quot;&lt;/span&gt; BLOCK_SIZE=&lt;span class=&quot;hljs-string&quot;&gt;&quot;4096&quot;&lt;/span&gt; TYPE=&lt;span class=&quot;hljs-string&quot;&gt;&quot;ext3&quot;&lt;/span&gt; PARTUUID=&lt;span class=&quot;hljs-string&quot;&gt;&quot;dbc3620d-01&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;hljs&quot;&gt;ip=&amp;lt;server ip&amp;gt;::&amp;lt;server gateway&amp;gt;:&amp;lt;server netmask&amp;gt;::eth0:none&lt;/code&gt; tells the
kernel enough information for tinyssh to be accessible from the Internet.
These three IPS can be found in the “Settings” tab of &lt;code class=&quot;hljs&quot;&gt;jasmine&lt;/code&gt; management
panel in the Vultr dashboard.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Networking&lt;/h2&gt;
&lt;p&gt;There was only one step remaining before rebooting &lt;code class=&quot;hljs&quot;&gt;jasmine&lt;/code&gt; without the
installation ISO attached: configuring the system to ensure remote access. In
practice, it means enabling DHCP for the Ethernet interface (named &lt;code class=&quot;hljs&quot;&gt;ens3&lt;/code&gt; in
&lt;code class=&quot;hljs&quot;&gt;jasmine&lt;/code&gt;’s case).&lt;/p&gt;
&lt;p&gt;I did that by defining a &lt;code class=&quot;hljs&quot;&gt;.network&lt;/code&gt; unit in &lt;code class=&quot;hljs&quot;&gt;/etc/systemd/networkd&lt;/code&gt; to enable
DHCP so that &lt;code class=&quot;hljs&quot;&gt;jasmine&lt;/code&gt; can get its ip from Vultr DHCP server.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;# /etc/systemd/network/50-ens3.network
[Match]
Name=ens3

[Network]
DHCP=yes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As a last touch, I enabled both &lt;code class=&quot;hljs&quot;&gt;systemd-networkd&lt;/code&gt; and &lt;code class=&quot;hljs&quot;&gt;systemd-resolved&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;; systemctl &lt;span class=&quot;hljs-built_in&quot;&gt;enable&lt;/span&gt; systemd-networkd
; systemctl &lt;span class=&quot;hljs-built_in&quot;&gt;enable&lt;/span&gt; systemd-resolved
; &lt;span class=&quot;hljs-built_in&quot;&gt;ln&lt;/span&gt; -sf ../run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And I was good to go!&lt;/p&gt;
&lt;p&gt;I exited the chroot, came back to Vultr dashboard to detach the custom ISO from
&lt;code class=&quot;hljs&quot;&gt;jasmine&lt;/code&gt;, which prompted a reboot of the VPS. A look a the virtual console was
enough to confirm tinyssh had started and was waiting for incoming connection.
I edited my &lt;code class=&quot;hljs&quot;&gt;~/.ssh/known_hosts&lt;/code&gt; to remove &lt;code class=&quot;hljs&quot;&gt;jasmine&lt;/code&gt; now out-dated line, and
tried to connect to &lt;code class=&quot;hljs&quot;&gt;jasmine&lt;/code&gt;. tinyssh asked me kindly the passphrase for
&lt;code class=&quot;hljs&quot;&gt;/dev/vda1&lt;/code&gt;, before closing the connection.&lt;/p&gt;
&lt;p&gt;A new attempt at connection to &lt;code class=&quot;hljs&quot;&gt;jasmin&lt;/code&gt; using SSH led me to the expected
system. Hourray!&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Needless to say, while this article is meant to propose a linear story to its
readers, my personal journey was everything but. I had to reboot many times
into the installation ISO, to mount my root partition and tweak the
configuration until it finally worked.&lt;/p&gt;
&lt;p&gt;Hopefully, this article lists the various pitfalls I ran into, and how I fixed
them. It’ll be helpful for Future Me, and maybe to you before that.&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>Using git maintenance with Encrypted SSH Keys</title>
      <link>https://soap.coffee/~lthms/posts/GitMaintenanceSshEncryptedKeys.html</link>
      <guid>https://soap.coffee/~lthms/posts/GitMaintenanceSshEncryptedKeys.html</guid>
      <pubDate>February 18, 2024</pubDate>
      <description>
        
        &lt;h1&gt;Using &lt;code class=&quot;hljs&quot;&gt;git maintenance&lt;/code&gt; with Encrypted SSH Keys&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/workflow.html&quot; class=&quot;tag hover-peach&quot; marked=&quot;&quot;&gt;workflow&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/git.html&quot; class=&quot;tag hover-mint&quot; marked=&quot;&quot;&gt;git&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;This year, I went to &lt;a href=&quot;https://fosdem.org/2024&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;FOSDEM 2024&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. It was nice and
&lt;s&gt;cosy&lt;/s&gt; crowded, and I really enjoyed my time there. The very last talk I
could attend to before having to leave for the train station was “&lt;a href=&quot;https://www.youtube.com/watch?v=aolI_Rz0ZqY&amp;amp;pp=ygUZc28geW91IHRoaW5rIHlvdSBrbm93IGdpdA%3D%3D&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;So You Think
You Know
Git&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#youtube&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;”
by &lt;a href=&quot;https://twitter.com/chacon&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;Scott Chacon&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. If you haven’t already, go and
watch it. It is a very good and educational presentation. You will learn what
&lt;code class=&quot;hljs&quot;&gt;git blame -C -C -C&lt;/code&gt; does and never be the same.&lt;/p&gt;
&lt;p&gt;Another takeaway for me was &lt;code class=&quot;hljs&quot;&gt;git maintenance&lt;/code&gt;. &lt;code class=&quot;hljs&quot;&gt;git maintenance&lt;/code&gt; allows running
in the background a set of tasks which optimize commands like &lt;code class=&quot;hljs&quot;&gt;git add&lt;/code&gt; and
&lt;code class=&quot;hljs&quot;&gt;git fetch&lt;/code&gt; for a responsive user experience. I mean, count me in! Our git
repository at &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$WORK&lt;/span&gt;&lt;/code&gt; has become fairly big over the years&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Not &lt;a href=&quot;https://youtu.be/aolI_Rz0ZqY?si=-ielyNVXwREJqupo&amp;amp;t=1430&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;&lt;em&gt;mono-repo&lt;/em&gt;
big&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; yet, but
still big enough to make &lt;code class=&quot;hljs&quot;&gt;git fetch --all --prune&lt;/code&gt; feels… well,
unresponsive. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;So, when I came back to work the next day, I run the magic command the speaker
had mentioned&lt;label for=&quot;fn2&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn2&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Following &lt;a href=&quot;https://twitter.com/leostera/status/1740796853174596007&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;a petition from the
Internet&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, my
terminal prompt is &lt;code class=&quot;hljs&quot;&gt;;&lt;/code&gt;. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;; git maintenance start
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This created a bunch of user systemd services and timers which I decided to run
immediately to test that everything was working correctly, starting with the
hourly service responsible for prefetching remote branches.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;; systemctl --user start git-maintenance@hourly.service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unfortunately, this did not work out, and for predictable reasons.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;; systemctl --user status git-maintenance@hourly.service
(...)
systemd[1706]: Starting Optimize Git repositories data...
git[76228]: git@gitlab.com: Permission denied (publickey).
git[76226]: error: failed to prefetch remotes
git[76226]: error: task &lt;span class=&quot;hljs-string&quot;&gt;&apos;prefetch&apos;&lt;/span&gt; failed
systemd[1706]: git-maintenance@hourly.service: Main process exited, code=exited, status=&amp;gt;
systemd[1706]: git-maintenance@hourly.service: Failed with result &lt;span class=&quot;hljs-string&quot;&gt;&apos;exit-code&apos;&lt;/span&gt;.
systemd[1706]: Failed to start Optimize Git repositories data.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The culprit here is the fact I am using an encrypted SSH key to connect to
Gitlab where our repository is hosted and out of the box the scripts run by
&lt;code class=&quot;hljs&quot;&gt;git-maintenance&lt;/code&gt; have now way to use them. This is because &lt;code class=&quot;hljs&quot;&gt;git-maintenance&lt;/code&gt;
is not aware of the existence of the SSH agent running on my laptop.&lt;/p&gt;
&lt;p&gt;The solution can be read in the Man page of &lt;code class=&quot;hljs&quot;&gt;git-maintenance&lt;/code&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;(…) any customization should be done by creating a drop-in file, &lt;em&gt;i.e.&lt;/em&gt; a
&lt;code class=&quot;hljs&quot;&gt;.conf&lt;/code&gt; suffixed file in the
&lt;code class=&quot;hljs&quot;&gt;~/.config/systemd/user/git-maintenance@.service.d&lt;/code&gt; directory.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I didn’t know this general purpose trick which should work for any systemd
service running on a Linux machine! Thanks, anonymous technical writer who took
the time to contribute to this Man page.&lt;/p&gt;
&lt;p&gt;And indeed, creating a file named &lt;code class=&quot;hljs&quot;&gt;10-ssh.conf&lt;/code&gt;&lt;label for=&quot;fn3&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn3&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;The prefix number is as important as the &lt;code class=&quot;hljs&quot;&gt;.conf&lt;/code&gt; suffix mentioned in
the &lt;code class=&quot;hljs&quot;&gt;git-maintenance&lt;/code&gt; Man page for systemd to load the drop-in file. &lt;/span&gt;
&lt;/span&gt; in
&lt;code class=&quot;hljs&quot;&gt;${HOME}/.config/systemd/user/git-maintenance@.service.d/&lt;/code&gt; to set the
&lt;code class=&quot;hljs&quot;&gt;SSH_AUTH_SOCK&lt;/code&gt; environment variable solved my issue. Its value depends on your
personal setup. In my case, I am using the systemd &lt;code class=&quot;hljs&quot;&gt;ssh-agent.service&lt;/code&gt; user
unit.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;; systemctl --user show ssh-agent.service | grep Environment=SSH_AUTH_SOCK
Environment=SSH_AUTH_SOCK=/run/user/1000/ssh-agent.socket
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We replicate this in our &lt;code class=&quot;hljs&quot;&gt;10-ssh.conf&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-systemd&quot;&gt;[Service]
Environment=SSH_AUTH_SOCK=/run/user/1000/ssh-agent.socket
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And we are done! This time, executing the service manually will work (assuming
the necessary encrypted key has been &lt;code class=&quot;hljs&quot;&gt;ssh-add&lt;/code&gt; to the agent).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;; systemctl --user daemon-reload
; systemctl --user start git-maintenance@hourly.service
; systemctl --user status git-maintenance@hourly.service
(...)
systemd[1706]: Starting Optimize Git repositories data...
systemd[1706]: Finished Optimize Git repositories data.
&lt;/code&gt;&lt;/pre&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>Building Static Binaries for OCaml Projects</title>
      <link>https://soap.coffee/~lthms/posts/OCamlStaticBinaries.html</link>
      <guid>https://soap.coffee/~lthms/posts/OCamlStaticBinaries.html</guid>
      <pubDate>December 31, 2023</pubDate>
      <description>
        
        &lt;h1&gt;Building Static Binaries for OCaml Projects&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/ocaml.html&quot; class=&quot;tag hover-sky&quot; marked=&quot;&quot;&gt;ocaml&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;Building static binaries can come in handy. Most notably, when the time comes
to distribute executables. I should know, because I spend a bit of time
recently preparing for &lt;a href=&quot;./SpatialShell6.html&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;the 6th release of Spatial
Shell&lt;/a&gt;, and part of that time was ensuring that folks on
Linux unwilling to build an OCaml project from source could still give my
project a shot.&lt;/p&gt;
&lt;p&gt;Turns out, it can be achieved pretty easily, when you know what you are doing.
This is not the first article published on the Internet which explains how to
build static binaries, but (1) the ones I have found were a bit verbose and
hard to follow, and (2) the most recent versions of OCaml bring a new challenge
to tackle.&lt;/p&gt;
&lt;h2&gt;Setting-Up a Dedicated &lt;code class=&quot;hljs&quot;&gt;dune&lt;/code&gt; Profile&lt;/h2&gt;
&lt;p&gt;At the root of your repository, create a &lt;code class=&quot;hljs&quot;&gt;dune&lt;/code&gt; file containing the following
stanza:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-lisp&quot;&gt;(&lt;span class=&quot;hljs-name&quot;&gt;env&lt;/span&gt;
 (&lt;span class=&quot;hljs-name&quot;&gt;static&lt;/span&gt;
  (&lt;span class=&quot;hljs-name&quot;&gt;flags&lt;/span&gt;
   (&lt;span class=&quot;hljs-symbol&quot;&gt;:standard&lt;/span&gt; -cclib -static))))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This tells &lt;code class=&quot;hljs&quot;&gt;dune&lt;/code&gt; to passes specific arguments to the OCaml compiler when
called with the &lt;code class=&quot;hljs&quot;&gt;--profile=static&lt;/code&gt; command-line argument.&lt;/p&gt;
&lt;p&gt;At this point, calling &lt;code class=&quot;hljs&quot;&gt;dune build --profile=static&lt;/code&gt; is likely to fail with
linking related errors. For instance, I got this one.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;/sbin/ld: /usr/lib/gcc/x86_64-pc-linux-gnu/13.2.1/crt
beginT.o: relocation R_X86_64_32 against hidden symbol `__TMC_END__&apos; can not be used when making a shared object
/sbin/ld: failed to set dynamic section sizes: bad value
collect2: error: ld returned 1 exit status
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With OCaml 5.1.0 and OCaml 5.1.1, you are also likely to hit an error related
to &lt;code class=&quot;hljs&quot;&gt;zstd&lt;/code&gt;, which is a new runtime dependency for OCaml programs&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;It looks like a temporary issue. If I understood correctly, the OCaml
core developers are planning to remove said dependency in future versions
of the compiler. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;/sbin/ld: cannot find -lzstd: No such file or directory
collect2: error: ld returned 1 exit status
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The solution for these two problems is the same.&lt;/p&gt;
&lt;h2&gt;Setting Up a Specific Opam Switch&lt;/h2&gt;
&lt;p&gt;The OCaml compiler has a lot of so-called variants. The most famous is probably
&lt;a href=&quot;https://v2.ocaml.org/manual/flambda.html&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;flambda&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, which enables a series
of optimisations for native compilation.&lt;/p&gt;
&lt;p&gt;Nowadays, enabling the specific features of a given variant is achieved by
installing the related &lt;code class=&quot;hljs&quot;&gt;option&lt;/code&gt; package when choosing your compiler version. In
our case, we have to install:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;hljs&quot;&gt;ocaml-option-static&lt;/code&gt; (which will also enables &lt;code class=&quot;hljs&quot;&gt;ocaml-option-musl&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;hljs&quot;&gt;ocaml-option-no-compression&lt;/code&gt; (for OCaml 5.1.0 and 5.1.1)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The minimal Opam invocation to create such a switch is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;opam switch create . --packages &lt;span class=&quot;hljs-string&quot;&gt;&quot;ocaml-option-static,ocaml-option-no-compression,ocaml.5.1.1&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This particular configuration will produce static binaries using
&lt;a href=&quot;https://musl.libc.org&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;&lt;em&gt;musl&lt;/em&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, a lightweight libc implementation that is way
more suited than the glibc when it comes to static binaries. This means you
will have to install &lt;em&gt;musl&lt;/em&gt; on your system (it is more than likely that it is
packaged by your favorite distribution).&lt;/p&gt;
&lt;p&gt;Additionally, you will have to provide the static versions (&lt;code class=&quot;hljs&quot;&gt;.a&lt;/code&gt;) of the system
libraries your project relies on. This part might be tricky to address, and is
very dependent on the particular system you are using. For instance, Debian
makes this a &lt;em&gt;lot&lt;/em&gt; easier than Archlinux. This was typically what was happening
with &lt;code class=&quot;hljs&quot;&gt;zstd&lt;/code&gt;: Archlinux only distributed dynamic libraries, so no &lt;code class=&quot;hljs&quot;&gt;.a&lt;/code&gt; where
available on my laptop. Another example: if your project depends on
&lt;a href=&quot;https://github.com/ocaml/Zarith&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;Zarith&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, then you have a dependency to &lt;code class=&quot;hljs&quot;&gt;gmp&lt;/code&gt;.
You need to go and find the static library for it before moving to the next
section&lt;label for=&quot;fn2&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn2&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Of course, it is also possible that you are working on a pure OCaml
project whose only real dependency is to the libc. Lucky you. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;h2&gt;Verifying the Resulting Binaries&lt;/h2&gt;
&lt;p&gt;Now is the time to call Dune again, with the &lt;code class=&quot;hljs&quot;&gt;--profile=static&lt;/code&gt; command-line
argument. Checking the result of your effort is as simple as calling &lt;code class=&quot;hljs&quot;&gt;ldd&lt;/code&gt; on
the binary compiled by Dune.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;    not a dynamic executable
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If &lt;code class=&quot;hljs&quot;&gt;ldd&lt;/code&gt; outputs something of this form, then you are good to go!&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This is, in a nutshell, the approach I am using to produce static binaries for
Spatial Shell releases. You can find the resulting script in &lt;a href=&quot;https://github.com/lthms/spatial-shell/blob/cc026c67a4645a01bf6cc6600e9e6baa87441fa8/scripts/prepare-release-artifacts.sh&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;the project
repository&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;
if you are interested.&lt;/p&gt;
&lt;p&gt;If you have spotted an error in this article, or if you think the solution
proposed here can be improved, do not hesitate to reach out to me (ideally
though my &lt;a href=&quot;mailto:~lthms/public-inbox@lists.sr.ht&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;public inbox&lt;/a&gt;). Or, even
better, open an issue on &lt;a href=&quot;https://github.com/lthms/spatial-shell/issues&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;Spatial Shell
tracker&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;! Afterall, these are
the very steps I’m relying on in order to provide static binaries, so I’d like
to know if I am doing something wrong 😅.&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>Spatial Shell 6th Release Might Be the Charm</title>
      <link>https://soap.coffee/~lthms/posts/SpatialShell6.html</link>
      <guid>https://soap.coffee/~lthms/posts/SpatialShell6.html</guid>
      <pubDate>December 30, 2023</pubDate>
      <description>
        
        &lt;h1&gt;Spatial Shell 6th Release Might Be the Charm&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/spatial-shell.html&quot; class=&quot;tag hover-lavender&quot; marked=&quot;&quot;&gt;spatial-shell&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/releases.html&quot; class=&quot;tag hover-periwinkle&quot; marked=&quot;&quot;&gt;releases&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;After a first &lt;a href=&quot;/~lthms/posts/CFTSpatialShell.html&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;call for testers&lt;/a&gt; that &lt;a href=&quot;https://github.com/lthms/spatial-shell/issues/2#issuecomment-1527193430&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;could have
been more effective if only the building instructions listed in the README were
correct&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;,
I am quite happy to announce the 6th release for Spatial Shell that, I believe,
is pretty usable for someone who &lt;em&gt;isn’t me&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;What’s Spatial Shell Already?&lt;/h2&gt;
&lt;p&gt;In a nutshell, Spatial Shell implements a &lt;em&gt;spatial model&lt;/em&gt; inspired by &lt;a href=&quot;https://material-shell.com&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;Material
Shell&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; for i3 and sway. Windows are organized in a
grid whose rows are your workspace, and you can navigate this grid (by focusing
neighbors windows), move the focused window around, decide how many window you
want to see at most in every workspace, etc.&lt;/p&gt;
&lt;p&gt;When I first discovered Material Shell in August 2022, I was pretty excited,
but the fact that it is a GNOME extension prevented me from switching
completely (besides, it was pretty unstable on my laptop for reasons. So when I
discovered that Sway (my personal favorite window manager) could be controlled
by &lt;a href=&quot;https://man.archlinux.org/man/sway-ipc.7.en&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;a third-party program through a Unix
socket&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, I started experimenting.
&lt;a href=&quot;https://twitter.com/_lthms_/status/1561034295501897730&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;It didn’t take long before I had a working prototype that fit most of my
need&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, but it took a
significant amount of time to turn this prototype into something really usable
by anyone who isn’t me.&lt;/p&gt;
&lt;p&gt;Here is a clunky showcase of what Spatial Shell can do&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Yes, &lt;em&gt;Scott Pilgrim Takes Off&lt;/em&gt; is an awesome show that you definitely
need to watch. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;video controls=&quot;&quot;&gt;&lt;source src=&quot;https://spatial-shell.app/demo.mp4&quot;&gt;&lt;/video&gt;
&lt;p&gt;For the interested viewers, I am using a forked version of sway called
&lt;a href=&quot;https://github.com/WillPower3309/swayfx&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;SwayFX&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; to get these rounded corners
and the dim effects on unfocused windows. The status bar is Waybar with &lt;a href=&quot;https://github.com/lthms/spatial-shell/tree/main/contrib/waybar&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;a
config you can try yourself if you are
interested&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;!
There is also &lt;a href=&quot;https://github.com/lthms/spatial-shell/tree/main/contrib/i3blocks&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;a minimal &lt;code class=&quot;hljs&quot;&gt;i3blocks&lt;/code&gt;
config&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;
available if you cannot use Waybar&lt;label for=&quot;fn2&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn2&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I fully intend to provide an example config as visually pleasing as the
one for Waybar, but compatible with i3. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;To be clear, the UI part of Spatial Shell remains lacking to this day. My
Waybar configuration works, but is pretty verbose and statically limited. For
instance, it will only display the 8th first windows of a workspace. This is
because Waybar does not allow one widget to generate multiple blocks. The same
goes for the &lt;code class=&quot;hljs&quot;&gt;i3blocks&lt;/code&gt; configuration example. Also, they assume the
availability of a font with icons&lt;label for=&quot;fn3&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn3&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;On that matter, I love the &lt;a href=&quot;https://www.nerdfonts.com/&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;Nerd
Fonts&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; project. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;h2&gt;Try It Yourself!&lt;/h2&gt;
&lt;p&gt;As of today, you can install Spatial Shell using the following methods:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;By fetching the official binary builds for Linux x86_64 from the &lt;a href=&quot;https://github.com/lthms/spatial-shell/releases&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;GitHub
releases page&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;By installing the &lt;a href=&quot;https://aur.archlinux.org/packages/spatial-shell&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;AUR package for
Archlinux&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;By building directly from source&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/lthms/spatial-shell#spatial-shell&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;README&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; should be
a good starting point. If it is lacking key pieces of information, do not
hesitate to open an issue. At this point, I am willing to deal with
documentation issue as bugs.&lt;/p&gt;
&lt;p&gt;Besides its &lt;code class=&quot;hljs&quot;&gt;README&lt;/code&gt;, Spatial Shell is documented via manpages. For a list of
available manpages, you can refer to &lt;code class=&quot;hljs&quot;&gt;man -k spatial&lt;/code&gt;. Spatial Shell definitely
works with sway, and should work with i3 since the former is basically a
drop-in replacement for the latter.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The journey from the initial idea up to this moment has definitely been an
interesting one. At this point, Spatial Shell provides every feature I need.
That being said, it does not mean there is nothing more to tell! I certainly
hope this project will catch the eyes of some of you, and soon be used on
computers I do not own by folks who are not me.&lt;/p&gt;
&lt;p&gt;Contributions are obviously welcome! Typically, if you happen to piece together
a neat status bar configuration, I am &lt;em&gt;very&lt;/em&gt; interested.&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>The Free and Open Source Software Projects This Website is Built Upon in June 2023</title>
      <link>https://soap.coffee/~lthms/posts/Thanks2023.html</link>
      <guid>https://soap.coffee/~lthms/posts/Thanks2023.html</guid>
      <pubDate>June 23, 2023</pubDate>
      <description>
        
        &lt;h1&gt;The Free and Open Source Software Projects This Website is Built Upon in June 2023&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/meta.html&quot; class=&quot;tag hover-rose&quot; marked=&quot;&quot;&gt;meta&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;In the past, I had a page called “Thanks!” dedicated to listing the free and
open source software projects I was relying on to create this website. Sadly,
this page was dropped during my latest overhaul, which is a shame because I do
think it is important to acknowledge these fantastic projects without which
this website would not exist.&lt;/p&gt;
&lt;p&gt;That being said, I do want to approach this exercise differently this time.
Instead of keeping one page up to date with the latest software stack I am
using, I plan to publish a new article every now and then&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I really like the idea of keeping track of all the wonderful
tools I was lucky enough to find out and use over the years. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;h2&gt;Authoring Contents&lt;/h2&gt;
&lt;p&gt;As mentioned in &lt;a href=&quot;/~lthms/posts/May2023.html&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;my latest retrospective&lt;/a&gt;, I have
simplified how I write my contents. Nowadays, all my write-ups
are written in Markdown, and I use
&lt;a href=&quot;https://github.com/markdown-it/markdown-it&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;markdown-it&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; to parse them and
generate nice and fancy HTML documents.&lt;/p&gt;
&lt;p&gt;In addition to the base parser that markdown-it is, I am relying on an
ever-growing collection of plugins:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/markdown-it-footnote&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;markdown-it-footnote&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/markdown-it-figure&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;markdown-it-figure&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/markdown-it-highlightjs&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;markdown-it-highlightjs&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/markdown-it-meta&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;markdown-it-meta&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/markdown-it-custom-block&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;markdown-it-custom-block&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/markdown-it-mermaid&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;markdown-it-mermaid&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/@ryanxcharles/markdown-it-katex&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;markdown-it-katex from &lt;em&gt;@ryanxcharles&lt;/em&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As a consequence, this website also benefits from two very nice projects:
&lt;a href=&quot;https://highlightjs.org/&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;highlight.js&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; for syntax highlighting, and
&lt;a href=&quot;https://katex.org/&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mtext&gt;KaTeX&lt;/mtext&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\KaTeX&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8988em;vertical-align:-0.2155em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord text&quot;&gt;&lt;span class=&quot;mord textrm&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:-0.17em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;span style=&quot;top:-2.905em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord textrm mtight sizing reset-size6 size3&quot;&gt;A&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord text&quot;&gt;&lt;span class=&quot;mord textrm&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:-0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.4678em;&quot;&gt;&lt;span style=&quot;top:-2.7845em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord textrm&quot;&gt;E&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2155em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:-0.125em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord textrm&quot;&gt;X&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; for displaying mathematics equations.&lt;/p&gt;
&lt;h2&gt;Frontend&lt;/h2&gt;
&lt;p&gt;In addition to &lt;a href=&quot;https://www.npmjs.com/package/normalize.css&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;normalize.css&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; to
“reset” the CSS defaults of various browsers, this website could not exist as it
is now without the awesome &lt;a href=&quot;https://edwardtufte.github.io/tufte-css/&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;Tufte
CSS&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; project. The sidenotes of this
website could not have existed without it.&lt;/p&gt;
&lt;h2&gt;HTML Generation&lt;/h2&gt;
&lt;p&gt;While markdown-it is doing the heavy lifting of turning my Markdown contents
in HTML pages, &lt;a href=&quot;https://soupault.app&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;soupault&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; is the goldsmith which pieces
these pages together into a coherent whole.&lt;/p&gt;
&lt;p&gt;I really enjoy using soupault for my website. In a nutshell, this tool enables
me to customize the pages of my website with an API very similar to what
Javascript offers, but instead of the computation happening on the client side
every time the page is loaded, it is done on my laptop once, just before I
push the new pages. Just an example: for my sidenote pages, I was able to reuse
the markdown-it-footnote with zero modification, and I just had to write a
simple Lua plugin to customize its output to my (humble) needs.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;/~lthms/running.html&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;running log&lt;/a&gt; is also another good example of an ad hoc page
I can generate using a simple Lua script.&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>Extensible Records in OCaml Using dmap</title>
      <link>https://soap.coffee/~lthms/posts/ExtensibleRecordsInOCaml.html</link>
      <guid>https://soap.coffee/~lthms/posts/ExtensibleRecordsInOCaml.html</guid>
      <pubDate>June 20, 2023</pubDate>
      <description>
        
        &lt;h1&gt;Extensible Records in OCaml Using &lt;code class=&quot;hljs&quot;&gt;dmap&lt;/code&gt;&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/ocaml.html&quot; class=&quot;tag hover-coral&quot; marked=&quot;&quot;&gt;ocaml&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://ocaml.org/p/dmap/latest/&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;dmap&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; is a library to create and
manipulate heterogeneous maps. It features a very straightforward API which
leverages the common trick of tagging the type of the keys with a parameter
specifying the types of the associated values&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;This article assumes readers are familiar with GADTs. &lt;/span&gt;
&lt;/span&gt;. That is, given &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; key&lt;/code&gt; the type of keys of a heterogeneous map &lt;code class=&quot;hljs language-ocaml&quot;&gt;t&lt;/code&gt;, then the
value associated to a key &lt;code class=&quot;hljs language-ocaml&quot;&gt;k&lt;/code&gt; of type &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;bool&lt;/span&gt; key&lt;/code&gt; is expected to
be of type &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;bool&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In this write-up, we show how it is possible to use &lt;code class=&quot;hljs&quot;&gt;dmap&lt;/code&gt; to implement
extensible records (that is, records which can be extended with new fields
after they have been defined) in OCaml. I have also published on GitHub &lt;a href=&quot;https://github.com/lthms/extensible-records-minimal&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;a
repository containing the implementation presented in this
article&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. While &lt;code class=&quot;hljs&quot;&gt;dmap&lt;/code&gt; is
far from being the only available solution for this use case&lt;label for=&quot;fn2&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn2&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;For heterogeneous maps, &lt;a href=&quot;https://ocaml.org/p/gmap/latest&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;gmap&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; is
apparently a popular alternative, and so is
&lt;a href=&quot;https://ocaml.org/p/hmap/latest&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;hmap&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. For extensible records,
&lt;a href=&quot;https://ocaml.org/p/orec/latest&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;orec&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; looks like a very interesting
library I should probably take a long look at. &lt;/span&gt;
&lt;/span&gt;, it is the
one I happened to use for implementing a “plugin system” in a library where
each plugin can manipulate a shared state in a type-safe way.&lt;/p&gt;
&lt;h2&gt;Encoding Extensible Records&lt;/h2&gt;
&lt;p&gt;The (simplified) module type of a heterogeneous map built using &lt;code class=&quot;hljs&quot;&gt;dmap&lt;/code&gt; is as
follows.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;S&lt;/span&gt; = &lt;span class=&quot;hljs-keyword&quot;&gt;sig&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; t
  
  &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; key

  &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; binding = &lt;span class=&quot;hljs-type&quot;&gt;Binding&lt;/span&gt; : &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; key * &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; -&amp;gt; binding

  &lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; empty : t

  &lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; add : &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; key -&amp;gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; -&amp;gt; t -&amp;gt; t

  &lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; find_opt : &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; key -&amp;gt; t -&amp;gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; option

  &lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; fold_left : (&lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; -&amp;gt; binding -&amp;gt; a) -&amp;gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; -&amp;gt; t -&amp;gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The use case for heterogeneous maps I’ve been interested in recently is
encoding records. More precisely, constructors of keys encode fields containing
collections of values. In such approach, a constructor &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Foo&lt;/span&gt; : &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; key&lt;/code&gt;
encodes a field of type &lt;code class=&quot;hljs&quot;&gt;int option&lt;/code&gt;, while a constructor &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Bar&lt;/span&gt; : &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;bool&lt;/span&gt; key&lt;/code&gt; encodes a field of type &lt;code class=&quot;hljs&quot;&gt;bool StringMap.t&lt;/code&gt;. That is, the
heterogeneous map &lt;code class=&quot;hljs&quot;&gt;HMap.t&lt;/code&gt;, such as&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; _ key = &lt;span class=&quot;hljs-type&quot;&gt;Foo&lt;/span&gt; : &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; key | &lt;span class=&quot;hljs-type&quot;&gt;Bar&lt;/span&gt; : &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;bool&lt;/span&gt; key

&lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;HMap&lt;/span&gt; : &lt;span class=&quot;hljs-type&quot;&gt;S&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; key  = &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; key
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;can be used to encode values of a record type&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; t = {
  foo : &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; option;
  bar : &lt;span class=&quot;hljs-built_in&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;StringMap&lt;/span&gt;.t;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;as the following conversion functions demonstrates.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; of_record {foo; bar} =
  &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; res = &lt;span class=&quot;hljs-type&quot;&gt;HMap&lt;/span&gt;.empty &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; res = &lt;span class=&quot;hljs-type&quot;&gt;HMap&lt;/span&gt;.add &lt;span class=&quot;hljs-type&quot;&gt;Foo&lt;/span&gt; foo res &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;
  &lt;span class=&quot;hljs-type&quot;&gt;StringMap&lt;/span&gt;.fold_left
    (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; res (key, &lt;span class=&quot;hljs-keyword&quot;&gt;value&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;HMap&lt;/span&gt;.add (&lt;span class=&quot;hljs-type&quot;&gt;Bar&lt;/span&gt; key) &lt;span class=&quot;hljs-keyword&quot;&gt;value&lt;/span&gt; res)
    res
    bar

&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; of_hmap map =
  {
    foo = &lt;span class=&quot;hljs-type&quot;&gt;HMap&lt;/span&gt;.find_opt &lt;span class=&quot;hljs-type&quot;&gt;Foo&lt;/span&gt; map;
    bar = &lt;span class=&quot;hljs-type&quot;&gt;HMap&lt;/span&gt;.fold_left
            (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; smap (&lt;span class=&quot;hljs-type&quot;&gt;Binding&lt;/span&gt; binding) -&amp;gt;
               &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; binding &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;
               | (&lt;span class=&quot;hljs-type&quot;&gt;Bar&lt;/span&gt; k, v) -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;StringMap&lt;/span&gt;.add k v smap
               | _ -&amp;gt; smap)
            &lt;span class=&quot;hljs-type&quot;&gt;StringMap&lt;/span&gt;.empty
            map;
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As a consequence, to construct a heterogeneous map whose type of keys is
extensible is a way to get extensible records in OCaml.&lt;/p&gt;
&lt;p&gt;To that end, &lt;code class=&quot;hljs&quot;&gt;dmap&lt;/code&gt; only asks for a function to compare two arbitrary keys.
More precisely, given the type&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; _ key = ..
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;the challenge is to write the function &lt;code class=&quot;hljs&quot;&gt;compare&lt;/code&gt; of type&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; compare : &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; key -&amp;gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;b&lt;/span&gt; key -&amp;gt; (&lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt;, &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;b&lt;/span&gt;) &lt;span class=&quot;hljs-type&quot;&gt;Dmap&lt;/span&gt;.cmp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;with &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Dmap&lt;/span&gt;.cmp&lt;/code&gt; being defined&lt;label for=&quot;fn3&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn3&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;This definition of &lt;code class=&quot;hljs language-ocaml&quot;&gt;cmp&lt;/code&gt; enforces that two keys can only be
equal if and only if the values associated to them are of the same type. &lt;/span&gt;
&lt;/span&gt; as&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; (_, _) cmp =
  | &lt;span class=&quot;hljs-type&quot;&gt;Lt&lt;/span&gt; : (&lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt;, &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;b&lt;/span&gt;) cmp
  | &lt;span class=&quot;hljs-type&quot;&gt;Eq&lt;/span&gt;  : (&lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt;, &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt;) cmp
  | &lt;span class=&quot;hljs-type&quot;&gt;Gt&lt;/span&gt; : (&lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt;, &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;b&lt;/span&gt;) cmp
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;The Solution&lt;/h2&gt;
&lt;p&gt;To use extensible types in this kind of setting, the trick I am aware of is to
use a registration mechanism&lt;label for=&quot;fn4&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn4&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;For instance, this is what the &lt;code class=&quot;hljs&quot;&gt;tezos-error-monad&lt;/code&gt; package is
using for being able to &lt;a href=&quot;https://ocaml.org/p/tezos-error-monad/13.0/doc/Tezos_error_monad/Error_monad/index.html#val-register_error_kind&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;print the values of its extensible error
type&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;hljs language-ocaml&quot;&gt;compare&lt;/code&gt; function will work as follows.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We assign an integer to each constructor of the type &lt;code class=&quot;hljs language-ocaml&quot;&gt;key&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We compare these integers when the arguments of &lt;code class=&quot;hljs&quot;&gt;compare&lt;/code&gt; are constructed
from different constructors.&lt;/li&gt;
&lt;li&gt;We implement one comparison function per constructors, to be called when the
two arguments of &lt;code class=&quot;hljs&quot;&gt;compare&lt;/code&gt; are the same.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The exercise is being made a bit more complicated than what the previous
paragraph suggests due to the fact that both &lt;code class=&quot;hljs&quot;&gt;key&lt;/code&gt; and &lt;code class=&quot;hljs&quot;&gt;cmp&lt;/code&gt; are GADTs. As a
consequence, the rest of the article will proceed as follows. First, we will
implement the overall logic of the &lt;code class=&quot;hljs language-ocaml&quot;&gt;compare&lt;/code&gt; function implemented with
a registration mechanism, and only then will we tackle the OCaml compiler
errors GADTs so often bring.&lt;/p&gt;
&lt;h3&gt;Step 1: Forget About GADTs&lt;/h3&gt;
&lt;p&gt;To implement our registration mechanism, we rely on a good old reference to a
list&lt;label for=&quot;fn5&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn5&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;It is a good idea to hide this implementation “details”
behind a nice API, using a &lt;code class=&quot;hljs&quot;&gt;mli&lt;/code&gt; file. &lt;/span&gt;
&lt;/span&gt;. The position of a registered object within the list will
determine the integer attributed to it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; registered_keys = &lt;span class=&quot;hljs-built_in&quot;&gt;ref&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;[]&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; register_key key =
  registered_keys := key :: !registered_keys
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this list, we store a collection of first-class modules which provide
us everything we need to compare two &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; key&lt;/code&gt; values obtained from the
same constructors.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;KEY&lt;/span&gt; = &lt;span class=&quot;hljs-keyword&quot;&gt;sig&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; t

  &lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; proj : &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; key -&amp;gt; t option
  &lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; compare : t -&amp;gt; t -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The type &lt;code class=&quot;hljs language-ocaml&quot;&gt;t&lt;/code&gt; of the module type &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;KEY&lt;/span&gt;&lt;/code&gt; is the type of one
constructor’s arguments. The simplest definition of &lt;code class=&quot;hljs language-ocaml&quot;&gt;t&lt;/code&gt; is
&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;unit&lt;/span&gt;&lt;/code&gt;, which means the field encoded with the related constructor
points to a singleton value (as &lt;code class=&quot;hljs language-ocaml&quot;&gt;foo&lt;/code&gt; did in the previous section).&lt;/p&gt;
&lt;p&gt;However, it is also possible to have keys’ constructors taking arguments, which
would translate into a field pointing to collections of value. This was the case
for &lt;code class=&quot;hljs&quot;&gt;bar&lt;/code&gt;, which was pointing to a mapping of strings to booleans.&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;hljs&quot;&gt;compare&lt;/code&gt; function will consist in iterating over the first-class modules
registered in &lt;code class=&quot;hljs&quot;&gt;registered_keys&lt;/code&gt;, in order to determine to which ones the two
arguments belong to.&lt;/p&gt;
&lt;p&gt;This means that considering a call &lt;code class=&quot;hljs&quot;&gt;compare left right&lt;/code&gt;, for each first-class module
of &lt;code class=&quot;hljs&quot;&gt;registered_keys&lt;/code&gt;, either&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;both &lt;code class=&quot;hljs&quot;&gt;left&lt;/code&gt; and &lt;code class=&quot;hljs&quot;&gt;right&lt;/code&gt; have not yet been associated to a first-class module,&lt;/li&gt;
&lt;li&gt;or &lt;code class=&quot;hljs&quot;&gt;left&lt;/code&gt; has, but `right hasn’t&lt;/li&gt;
&lt;li&gt;or &lt;code class=&quot;hljs&quot;&gt;right&lt;/code&gt; has, but &lt;code class=&quot;hljs&quot;&gt;left&lt;/code&gt; hasn’t&lt;/li&gt;
&lt;li&gt;or both &lt;code class=&quot;hljs&quot;&gt;left&lt;/code&gt; and `right have been associated to a first-class module.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Only when the fourth stage has been reached can we provide the expected result
of &lt;code class=&quot;hljs&quot;&gt;compare&lt;/code&gt;, whose type we have simplified in this section to return a &lt;code class=&quot;hljs&quot;&gt;int&lt;/code&gt;
instead of the GADT &lt;code class=&quot;hljs&quot;&gt;Dmap.cmp&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To encode these stages, we introduce a dedicated accumulator type.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; (&lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt;, &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;b&lt;/span&gt;) acc =
  | &lt;span class=&quot;hljs-type&quot;&gt;Init&lt;/span&gt; : &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; key * &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;b&lt;/span&gt; key -&amp;gt; (&lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt;, &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;b&lt;/span&gt;) acc
  | &lt;span class=&quot;hljs-type&quot;&gt;Compare_left_with&lt;/span&gt; : &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; key * &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; -&amp;gt; (&lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt;, &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;b&lt;/span&gt;) acc
  | &lt;span class=&quot;hljs-type&quot;&gt;Compare_right_with&lt;/span&gt; : &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; * &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;b&lt;/span&gt; key -&amp;gt; (&lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt;, &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;b&lt;/span&gt;) acc
  | &lt;span class=&quot;hljs-type&quot;&gt;Res&lt;/span&gt; : &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; -&amp;gt; (&lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt;, &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;b&lt;/span&gt;) acc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This allows us to implement &lt;code class=&quot;hljs&quot;&gt;compare&lt;/code&gt;&lt;label for=&quot;fn6&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn6&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Note the use of the &lt;code class=&quot;hljs&quot;&gt;Seq&lt;/code&gt; module here. It is motivated by the fact that
&lt;code class=&quot;hljs&quot;&gt;List.fold_lefti&lt;/code&gt; does not exist.&lt;/span&gt;
&lt;span class=&quot;footnote-p&quot;&gt;We need to know the position of the current first-class module we are
testing the keys against, hence the need for a &lt;code class=&quot;hljs&quot;&gt;fold_lefti&lt;/code&gt;. Of course, we
could have added the current position to the &lt;code class=&quot;hljs&quot;&gt;acc&lt;/code&gt; type, but the function
is already cumbersome enough, and using &lt;code class=&quot;hljs&quot;&gt;Seq.t&lt;/code&gt; is mostly free. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; compare : &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; a b. a key -&amp;gt; b key -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; =
 &lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; left right -&amp;gt;
  &lt;span class=&quot;hljs-type&quot;&gt;List&lt;/span&gt;.to_seq !registered_keys
  |&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;Seq&lt;/span&gt;.fold_lefti
       (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; (acc : (a, b) acc) i (&lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;K&lt;/span&gt; : &lt;span class=&quot;hljs-type&quot;&gt;KEY&lt;/span&gt;) -&amp;gt;
         &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; acc &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;
         | &lt;span class=&quot;hljs-type&quot;&gt;Init&lt;/span&gt; (left, right) -&amp;gt; (
             &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;K&lt;/span&gt;.proj left, &lt;span class=&quot;hljs-type&quot;&gt;K&lt;/span&gt;.proj right) &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;
             | &lt;span class=&quot;hljs-type&quot;&gt;Some&lt;/span&gt; left, &lt;span class=&quot;hljs-type&quot;&gt;Some&lt;/span&gt; right -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;Res&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;K&lt;/span&gt;.compare left right)
             | &lt;span class=&quot;hljs-type&quot;&gt;Some&lt;/span&gt; _, &lt;span class=&quot;hljs-type&quot;&gt;None&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;Compare_right_with&lt;/span&gt; (i, right)
             | &lt;span class=&quot;hljs-type&quot;&gt;None&lt;/span&gt;, &lt;span class=&quot;hljs-type&quot;&gt;Some&lt;/span&gt; _ -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;Compare_left_with&lt;/span&gt; (left, i)
             | &lt;span class=&quot;hljs-type&quot;&gt;None&lt;/span&gt;, &lt;span class=&quot;hljs-type&quot;&gt;None&lt;/span&gt; -&amp;gt; acc)
         | &lt;span class=&quot;hljs-type&quot;&gt;Compare_right_with&lt;/span&gt; (j, right) -&amp;gt; (
             &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;K&lt;/span&gt;.proj right &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;
             | &lt;span class=&quot;hljs-type&quot;&gt;Some&lt;/span&gt; _ -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;Res&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;Int&lt;/span&gt;.compare j i)
             | &lt;span class=&quot;hljs-type&quot;&gt;None&lt;/span&gt; -&amp;gt; acc)
         | &lt;span class=&quot;hljs-type&quot;&gt;Compare_left_with&lt;/span&gt; (left, j) -&amp;gt; (
             &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;K&lt;/span&gt;.proj left &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;
             | &lt;span class=&quot;hljs-type&quot;&gt;Some&lt;/span&gt; _ -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;Res&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;Int&lt;/span&gt;.compare i j)
             | &lt;span class=&quot;hljs-type&quot;&gt;None&lt;/span&gt; -&amp;gt; acc)
         | _ -&amp;gt; acc)
       (&lt;span class=&quot;hljs-type&quot;&gt;Init&lt;/span&gt; (left, right))
  |&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;Res&lt;/span&gt; x -&amp;gt; x
  | _ -&amp;gt;
      raise
        (&lt;span class=&quot;hljs-type&quot;&gt;Invalid_argument&lt;/span&gt;
           &lt;span class=&quot;hljs-string&quot;&gt;&quot;comparison with at least one unregistered key variant&quot;&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This function gives us the overall structure and logic of &lt;code class=&quot;hljs&quot;&gt;compare&lt;/code&gt;, but of
course we are not done yet.&lt;/p&gt;
&lt;h3&gt;Step 2: Deal with GADTs&lt;/h3&gt;
&lt;p&gt;In practice and as hinted in the introduction of this section, &lt;code class=&quot;hljs&quot;&gt;dmap&lt;/code&gt; is not
expected a comparison function of type &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; key -&amp;gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;b&lt;/span&gt; key -&amp;gt; (&lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt;, &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;b&lt;/span&gt;) &lt;span class=&quot;hljs-type&quot;&gt;Dmap&lt;/span&gt;.cmp&lt;/code&gt;, not &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; key -&amp;gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;b&lt;/span&gt; key -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The first step is to update &lt;code class=&quot;hljs&quot;&gt;acc&lt;/code&gt; accordingly.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-patch&quot;&gt;type (&apos;a, &apos;b) acc =
   | Init : &apos;a key * &apos;b key -&amp;gt; (&apos;a, &apos;b) acc
   | Compare_left_with : &apos;a key * int -&amp;gt; (&apos;a, &apos;b) acc
   | Compare_right_with : int * &apos;b key -&amp;gt; (&apos;a, &apos;b) acc
&lt;span class=&quot;hljs-deletion&quot;&gt;-  | Res : int -&amp;gt; (&apos;a, &apos;b) acc&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+  | Res : (&apos;a, &apos;b) Dmap.cmp -&amp;gt; (&apos;a, &apos;b) acc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we focus our attention to modifying &lt;code class=&quot;hljs language-ocaml&quot;&gt;compare&lt;/code&gt;, by modifying its
type signature, and by updating its definition to make use of the new
&lt;code class=&quot;hljs language-ocaml&quot;&gt;acc&lt;/code&gt; type.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-patch&quot;&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-let compare : type a b. a key -&amp;gt; b key -&amp;gt; int =&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+let compare : type a b. a key -&amp;gt; b key -&amp;gt; (a, b) Dmap.cmp =&lt;/span&gt;
  fun left right -&amp;gt;
   List.to_seq !registered_keys
   |&amp;gt; Seq.fold_lefti
       (fun (acc : (a, b) acc) i (module K : KEY) -&amp;gt;
          match acc with
          | Init (left, right) -&amp;gt; (
              match (K.proj left, K.proj right) with
&lt;span class=&quot;hljs-deletion&quot;&gt;-             | Some left, Some right -&amp;gt; Res (K.compare left right)&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+             | Some left, Some right -&amp;gt;&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+                 let x = K.compare left right in&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+                 Res (if x = 0 then Eq else if x &amp;lt; 0 then Lt else Gt)&lt;/span&gt;
              | Some _, None -&amp;gt; Compare_right_with (i, right)
              | None, Some _ -&amp;gt; Compare_left_with (left, i)
              | None, None -&amp;gt; acc)
          | Compare_right_with (j, right) -&amp;gt; (
              match K.proj right with
&lt;span class=&quot;hljs-deletion&quot;&gt;-             | Some _ -&amp;gt; Res (Int.compare j i)&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+             | Some _ -&amp;gt;&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+                 let x = Int.compare j i in&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+                 Res (if x &amp;lt; 0 then Lt else Gt)&lt;/span&gt;
              | None -&amp;gt; acc)
          | Compare_left_with (left, j) -&amp;gt; (
              match K.proj left with
&lt;span class=&quot;hljs-deletion&quot;&gt;-             | Some _ -&amp;gt; Res (Int.compare i j)&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+             | Some _ -&amp;gt;&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+                 let x = Int.compare j i in&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+                 Res (if x &amp;lt; 0 then Lt else Gt)&lt;/span&gt;
              | None -&amp;gt; acc)
          | _ -&amp;gt; acc)
        (Init (left, right))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point, we are remembered that the OCaml compiler is not that easy to
please when GADTs are involved. In particular, it complains for our use
of &lt;code class=&quot;hljs&quot;&gt;Eq&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;46 |               Res (if x = 0 then Eq else if x &amp;lt; 0 then Lt else Gt)
                                      ^^
Error: This expression has type (a, a) Dmap.cmp
       but an expression was expected of type (a, b) Dmap.cmp
       Type a is not compatible with type b
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This error message is the result of a tragedy in two acts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The &lt;code class=&quot;hljs&quot;&gt;Eq&lt;/code&gt; constructor of &lt;code class=&quot;hljs&quot;&gt;cmp&lt;/code&gt; is of type &lt;code class=&quot;hljs&quot;&gt;(&apos;a, &apos;a) cmp&lt;/code&gt;. That is, only two
keys associated with values of the same type can be equal.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;hljs&quot;&gt;compare&lt;/code&gt; takes two keys whose types can be different, and even if &lt;code class=&quot;hljs&quot;&gt;proj&lt;/code&gt; is
expected to return a &lt;code class=&quot;hljs&quot;&gt;Some&lt;/code&gt; only when both keys are constructed with the
same constructor, &lt;em&gt;nothing&lt;/em&gt; in its type enforces that invariant.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As such, OCaml is not convinced with our code alone that &lt;code class=&quot;hljs&quot;&gt;a = b&lt;/code&gt;, and rejects
it.&lt;/p&gt;
&lt;p&gt;One possible trick here is to rely on an equality witness type&lt;label for=&quot;fn7&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn7&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;This is &lt;em&gt;the&lt;/em&gt; trick to keep in mind when playing with GADTs, to a
point where &lt;code class=&quot;hljs language-ocaml&quot;&gt;eq&lt;/code&gt; could arguably be added to the OCaml’s standard
library. &lt;/span&gt;
&lt;/span&gt;, and
refine &lt;code class=&quot;hljs&quot;&gt;proj&lt;/code&gt; in order to convince OCaml our code is type-safe.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; (_, _) eq = &lt;span class=&quot;hljs-type&quot;&gt;Refl&lt;/span&gt; : (&lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt;, &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt;) eq
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We then modify &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;KEY&lt;/span&gt;&lt;/code&gt; to have &lt;code class=&quot;hljs language-ocaml&quot;&gt;proj&lt;/code&gt; not only return the
arguments of the constructor, but also a type equality witness to unify the
polymorphic argument of &lt;code class=&quot;hljs&quot;&gt;key&lt;/code&gt; to the expected value type of said constructor.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-patch&quot;&gt; module type KEY = sig
   type t
&lt;span class=&quot;hljs-addition&quot;&gt;+  type r&lt;/span&gt;
 
&lt;span class=&quot;hljs-deletion&quot;&gt;-  val proj : &apos;a key -&amp;gt; t option&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+  val proj : &apos;a key -&amp;gt; (t * (&apos;a, r) eq) option&lt;/span&gt;
   val compare : t -&amp;gt; t -&amp;gt; int
 end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is enough to convince OCaml that &lt;code class=&quot;hljs&quot;&gt;a = b&lt;/code&gt;, because it gets a proof that &lt;code class=&quot;hljs&quot;&gt;a = K.r&lt;/code&gt; and &lt;code class=&quot;hljs&quot;&gt;b = K.r&lt;/code&gt;&lt;label for=&quot;fn8&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn8&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;But only if you actually match &lt;code class=&quot;hljs&quot;&gt;Refl&lt;/code&gt; explicitly, meaning the
pattern &lt;code class=&quot;hljs&quot;&gt;Some (left, _), Some (right, _)&lt;/code&gt; would still lead to the same
error as not returning &lt;code class=&quot;hljs&quot;&gt;Refl&lt;/code&gt; at all. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-patch&quot;&gt;           match (K.proj left, K.proj right) with
&lt;span class=&quot;hljs-deletion&quot;&gt;-          | Some left, Some right -&amp;gt;&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+          | Some (left, Refl), Some (right, Refl) -&amp;gt;&lt;/span&gt;
               let x = K.compare left right in
               Res (if x = 0 then Eq else if x &amp;lt; 0 then Lt else Gt)
           | Some _, None -&amp;gt; Compare_right_with (i, right)
           | None, Some _ -&amp;gt; Compare_left_with (left, i)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s it. &lt;code class=&quot;hljs&quot;&gt;compare&lt;/code&gt; is done, compiles, and satisfies the expectations of
&lt;code class=&quot;hljs&quot;&gt;dmap&lt;/code&gt;. We can instantiate its functor with our &lt;code class=&quot;hljs language-ocaml&quot;&gt;key&lt;/code&gt; extensible
type&lt;label for=&quot;fn9&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn9&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;This approach will lead every value of type &lt;code class=&quot;hljs&quot;&gt;Extensible_record.t&lt;/code&gt;
to share the same fields, which might not be you need.&lt;/span&gt;
&lt;span class=&quot;footnote-p&quot;&gt;One can imagine embedding the &lt;code class=&quot;hljs&quot;&gt;registered_keys&lt;/code&gt; list of known keys inside
the extensible records values, along with a heterogeneous map. This
would allow each value to have its own dynamic set of fields. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;Extensible_record&lt;/span&gt; = &lt;span class=&quot;hljs-type&quot;&gt;Dmap&lt;/span&gt;.&lt;span class=&quot;hljs-type&quot;&gt;Make&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; t = &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; key

  &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; compare = compare
&lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 3: Profit&lt;/h3&gt;
&lt;p&gt;To wrap up this article, we can come back to our initial example of a record
with two fields &lt;code class=&quot;hljs language-ocaml&quot;&gt;foo&lt;/code&gt; and &lt;code class=&quot;hljs language-ocaml&quot;&gt;bar&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here is how we can extend &lt;code class=&quot;hljs&quot;&gt;key&lt;/code&gt; to have a &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Foo&lt;/span&gt;&lt;/code&gt; constructor.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; _ key += &lt;span class=&quot;hljs-type&quot;&gt;Foo&lt;/span&gt; : &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; key

&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;()&lt;/span&gt; =
  register_key
    (&lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt;
      &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; t = &lt;span class=&quot;hljs-built_in&quot;&gt;unit&lt;/span&gt;
      &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; r = &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;

      &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; proj : &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; a. a key -&amp;gt; (t * (a, r) eq) option = &lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt;
        | &lt;span class=&quot;hljs-type&quot;&gt;Foo&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;Some&lt;/span&gt; (&lt;span class=&quot;hljs-literal&quot;&gt;()&lt;/span&gt;, &lt;span class=&quot;hljs-type&quot;&gt;Refl&lt;/span&gt;)
        | _ -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;None&lt;/span&gt;

      &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; compare &lt;span class=&quot;hljs-literal&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;()&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Similarly, here is how we can register &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Bar&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; _ key += &lt;span class=&quot;hljs-type&quot;&gt;Bar&lt;/span&gt; : &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;bool&lt;/span&gt; key

&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;()&lt;/span&gt; =
  register_key
    (&lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt;
      &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; t = &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;
      &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; r = &lt;span class=&quot;hljs-built_in&quot;&gt;bool&lt;/span&gt;

      &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; proj : &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; a. a key -&amp;gt; (t * (a, r) eq) option = &lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt;
        | &lt;span class=&quot;hljs-type&quot;&gt;Bar&lt;/span&gt; arg -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;Some&lt;/span&gt; (arg, &lt;span class=&quot;hljs-type&quot;&gt;Refl&lt;/span&gt;)
        | _ -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;None&lt;/span&gt;

      &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; compare = &lt;span class=&quot;hljs-type&quot;&gt;String&lt;/span&gt;.compare
    &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once registered, these two fields/keys can be used to populate an
&lt;code class=&quot;hljs&quot;&gt;Extensible_record.t&lt;/code&gt; value with values of the expected types.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;()&lt;/span&gt; =
  &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; record = &lt;span class=&quot;hljs-type&quot;&gt;Extensible_record&lt;/span&gt;.empty &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; record = &lt;span class=&quot;hljs-type&quot;&gt;Extensible_record&lt;/span&gt;.add &lt;span class=&quot;hljs-type&quot;&gt;Foo&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt; record &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; record = &lt;span class=&quot;hljs-type&quot;&gt;Extensible_record&lt;/span&gt;.add (&lt;span class=&quot;hljs-type&quot;&gt;Bar&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;foobar&quot;&lt;/span&gt;) &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt; record &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;assert&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;Extensible_record&lt;/span&gt;.find &lt;span class=&quot;hljs-type&quot;&gt;Foo&lt;/span&gt; record = &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;) ;
  &lt;span class=&quot;hljs-keyword&quot;&gt;assert&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;Extensible_record&lt;/span&gt;.find (&lt;span class=&quot;hljs-type&quot;&gt;Bar&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;foobar&quot;&lt;/span&gt;) record)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A nice happy consequence of this approach is that it allows us to register
private fields only a given module can manipulate. Indeed, if this module does
not expose the constructor of the key it relies on, then only it can interact
with this part of the extensible record.&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>The Chaotic Debut of My Software Projects</title>
      <link>https://soap.coffee/~lthms/posts/ChaoticDebut.html</link>
      <guid>https://soap.coffee/~lthms/posts/ChaoticDebut.html</guid>
      <pubDate>May 29, 2023</pubDate>
      <description>
        
        &lt;h1&gt;The Chaotic Debut of My Software Projects&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/opinions.html&quot; class=&quot;tag hover-peach&quot; marked=&quot;&quot;&gt;opinions&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;I am no stranger to the exciting feeling of starting new projects. By dint of
repeating this “exercise” over the years, I have come to build an intuitive
process which works for me. In this write-up, I want to give a try at
describing it, both for future references and in the hope that this might start
interesting conversations. I am curious to know whether or not my personal
“process” is shared with some of my fellow developers, though I would be
surprised if it weren’t the case, since there is nothing particularly clever or
revolutionary with what I am about to write.&lt;/p&gt;
&lt;h2&gt;A Story in Two Acts&lt;/h2&gt;
&lt;p&gt;In a nutshell, I can often divide the early days of my software projects into
two phases: the &lt;em&gt;exploration phase&lt;/em&gt; and the &lt;em&gt;rationalization phase&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The starting point of the exploration phase is a &lt;em&gt;need&lt;/em&gt;, and a direction I want
to take to address this need. For instance, the starting point of the
&lt;a href=&quot;https://ocaml.org/p/data-encoding/latest/doc/Data_encoding/V1/Encoding/Compact/&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;Compact&lt;/code&gt; module of
&lt;code class=&quot;hljs&quot;&gt;data-encoding&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;
was the need to encode in bytes arbitrary values, and the direction was to do
that with &lt;code class=&quot;hljs&quot;&gt;data-encoding&lt;/code&gt;. For &lt;a href=&quot;https://github.com/lthms/spatial-shell&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;Spatial
Shell&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, I wanted badly to enjoy
&lt;a href=&quot;https://material-shell.com/&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;Material Shell&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;’s user experience without having
to switch to Gnome 3 and the direction was set when I discovered &lt;a href=&quot;https://man.archlinux.org/man/sway-ipc.7.en&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;sway’s RPC
protocol&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The goal of the exploration phase is for me to turn the direction into a
destination, so to speak. When I start, my knowledge of both the problem I want
to solve and the solution I am trying to build is vague, and needs refinement.
There are intuitions I need to challenge, APIs I need to learn, boilerplate I
need to understand. More often than not, this phase is messy. Commits are not
nice, standalone units of changes: it is way too early for that. I use Git
merely as a way to throw away a dead-end, and resume exploring down another
path from a reasonable save point. I put most if not all my code into one file,
I don’t write comments, encapsulation and abstraction become foreign words I
forget about for a while. My goal is to come up with a prototype which captures
the key features I am looking for, and to learn as much as possible in the
process. This exploration phase shouldn’t last too long, because it is very
context sensitive. If I am interrupted long enough, I am likely to lose the
mental map of my messy code, and to forget the key insights I was learning
while navigating it.&lt;/p&gt;
&lt;p&gt;I want to emphasis that the exploration phase should definitely touch to the
mundane, boring things like the CLI, the decoding of configuration files, the
encoding of persistent states, etc. These things tend to have a pervasive
impact on the rest of a software development if they are not taken into account
early. Because I am confronting myself to these forbidding parts, I am forced to understand the
pain points they will bring, and to plan for them.&lt;/p&gt;
&lt;p&gt;At some point, most of my questions have found their answers, and I am starting
to tackle features which go beyond the scope of the minimal set of features I
was initially after. When this time comes, friction is starting to appear
because of the bad quality of the codebase. All the shortcuts are coming back
to bite me and slow me down, while wild bugs enjoy the lack of invariant
enforcement and multiply.&lt;/p&gt;
&lt;p&gt;This is actually a good sign: the exploration is over, and before going any
further, it is time for me to take a step back and &lt;em&gt;rationalize&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The rationalization phase is the unique opportunity to “learn what I have
learned,” by revisiting every line of the code you have written, challenge it,
and hopefully come up with a solution for its most outstanding issues. I do
that by splitting up the monolithic that came out of the exploration phase into
a sane, navigable hierarchy of modules with clear, manageable APIs. This allows
me to fine-tune the design, to tweak the parts of the API exposed to the users
(the “boring parts” I mention for the exploration phase), and to remove any
dead code I thought might be useful or needed, but actually didn&apos;t cut it to the
prototype.&lt;/p&gt;
&lt;p&gt;This second phase often feels like a sprint. The second I am throwing myself at
it, the project stops working, and most of the time, it won’t even fully
compile before I’m actually done. This sometimes feels a bit overwhelming,
though the use of strongly typed programming language like OCaml or Rust has
proven to be of tremendous help, at least as long as I stick to moving code
around, and only amending it at the margin. Clearly, types and compile-time type
checking are my allies during what I often experience as a long snorkeling
session.&lt;/p&gt;
&lt;p&gt;When I’m done, I get my prototype working again, except it does not feel like a
prototype anymore. The feature set is the same, as is the user experience. But
the developer experience is totally different. I can now enjoy a codebase where
separation of concerns, encapsulation and abstraction play their rightful
roles, and allow me to reason about my software project more easily. This is
also the moment where I can slow down a bit, since it is no longer required for
me to keep the whole project architecture in my head. To a large extent, the
module hierarchy does that for me.&lt;/p&gt;
&lt;h2&gt;Random Thoughts&lt;/h2&gt;
&lt;p&gt;To me, this process feels a bit like a craft. I think I have become better at going
through it after every project I successfully bring at the end of the
rationalization phase. And I often feel a bit at lost when I am involved in a
project which does not follow this general approach.&lt;/p&gt;
&lt;p&gt;That being said, I have to admit it does not scale very well. If the whole
process does not fit in something like a week, then I will likely run out of
motivation before reaching stable grounds. For instance, the rationalization
phase often one to two days, during which I am basically stuck to my computer
for long hours.&lt;/p&gt;
&lt;p&gt;Finally, this process does not leave a lot of room for collaborating with other
developers. This is true both for the exploration phase (the “codebase” is
still a monolithic file that is partially rewritten over and over) and for the
rationalization phase (sometimes it feels like I am “discovering” the correct
way to organize the codebase while I organize it). However, collaboration
becomes possible (and even very rewarding) after the fact, when the codebase
“makes sense.”&lt;/p&gt;
&lt;p&gt;I guess it depends on the tradeoffs one is willing to make when starting a
project, the size and scale of the project, and the software developers and
entities involved.&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>What happened since December 2022?</title>
      <link>https://soap.coffee/~lthms/posts/May2023.html</link>
      <guid>https://soap.coffee/~lthms/posts/May2023.html</guid>
      <pubDate>May 18, 2023</pubDate>
      <description>
        
        &lt;h1&gt;What happened since December 2022?&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/emacs.html&quot; class=&quot;tag hover-lavender&quot; marked=&quot;&quot;&gt;emacs&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/meta.html&quot; class=&quot;tag hover-lemon&quot; marked=&quot;&quot;&gt;meta&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/neovim.html&quot; class=&quot;tag hover-sky&quot; marked=&quot;&quot;&gt;neovim&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/releases.html&quot; class=&quot;tag hover-mint&quot; marked=&quot;&quot;&gt;releases&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/spatial-shell.html&quot; class=&quot;tag hover-sky&quot; marked=&quot;&quot;&gt;spatial-shell&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;Initially, I started this “What happened” series as an exercise to publish
more regularly on this website. Suffice to say, I haven’t done a particularly
impressive job in that regard, which only means I have a lot of room for
improvement.&lt;/p&gt;
&lt;p&gt;Anyway, if the first few months of 2023 has been mostly &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$WORK&lt;/span&gt;&lt;/code&gt; focus,
the same cannot be said for April and May. For one, I have started
&lt;a href=&quot;/~lthms/running.html&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;running&lt;/a&gt; again. But this is only the tip of the iceberg.&lt;/p&gt;
&lt;h2&gt;Spatial Shell got its first releases&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/lthms/spatial-shell&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;Spatial Shell&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; is probably my hobby
project I am most excited about. The &lt;a href=&quot;/~lthms/posts/CFTSpatialShell.html&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;“call for testers”
article&lt;/a&gt; I have published recently managed to
catch the attention of a few folks&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;You want to hear a lesson I learned the hard way just after publishing
it? Before calling for testers, it is better to &lt;a href=&quot;https://github.com/lthms/spatial-shell/issues/2#issuecomment-1527193430&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;be sure your project can
actually be compiled easily by the potential
volunteers&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. &lt;/span&gt;
&lt;/span&gt;. The perspective to publish such a
write-up was a very strong source of motivation for me to clean up a project I
was using daily for several months now, and I am very satisfied with the
result.&lt;/p&gt;
&lt;p&gt;Mass adoption is still a distant horizon, but still, the project is now
mainstream enough that it has already been mentioned in &lt;a href=&quot;https://discuss.ocaml.org/t/window-manager-xmonad-in-ocaml/12048/4&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;a random topic on the
OCaml discourse by someone who isn’t
me&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. 🎉&lt;/p&gt;
&lt;p&gt;This led me to formally release a first version of Spatial Shell in the end of
April, and a second today. For the first time, I have also published &lt;a href=&quot;https://aur.archlinux.org/packages/spatial-shell&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;an
Archlinux package&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, to make
the life of potential early adopters even easier. Do not hesitate to upvote it
so that it can find its way to the &lt;code class=&quot;hljs&quot;&gt;extra&lt;/code&gt; repository some day.&lt;/p&gt;
&lt;h2&gt;Goodbye Emacs! Remember me, Neovim?&lt;/h2&gt;
&lt;p&gt;In 2015, I started using Coq for my PhD thesis and at the time, there was no
real support for (Neo)vim&lt;label for=&quot;fn2&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn2&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;The situation later improved. Nowadays, you can implement your theories
using &lt;a href=&quot;https://github.com/whonore/Coqtail&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;Coqtail&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, and &lt;a href=&quot;https://github.com/ejgallego/coq-lsp&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;Coq
LSP&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; will probably become a viable
and interesting setup in a near future. &lt;/span&gt;
&lt;/span&gt;. Everyone was using &lt;a href=&quot;https://proofgeneral.github.io/&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;Proof
General&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; and Emacs, so I was left with little
choice but to follow through. With only my courage and the &lt;a href=&quot;https://juanjoalvarez.net/posts/2014/vim-emacsevil-chaotic-migration-guide/&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;good advice of a
fellow “vimer” who had also made a similar
journey&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;,
I started using Emacs.&lt;/p&gt;
&lt;p&gt;Fast forward 8 years later, and my &lt;a href=&quot;https://src.soap.coffee/dotfiles/emacs.d&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;Emacs
configuration&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; has become a project
of its own. Overall, I was pretty happy with my setup, but in the same time, I
always remained a bit nostalgic of my Neovim days. This is probably why I
decided to give this old friend a try when my company bought me a new laptop. I
also used this as an opportunity to try out this LSP-thing everyone was talking
about.&lt;/p&gt;
&lt;p&gt;It has been a month now, and I do not plan to come back to my previous habits.
There are still some few edges here and there, I still need to get my head
around lua, but LSP is nice, and plugins like
&lt;a href=&quot;https://github.com/nvim-telescope/telescope.nvim&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;telescope&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; are simply too
beautiful.&lt;/p&gt;
&lt;p&gt;That being said, there was one aspect of moving from Emacs to Neovim I had not
anticipated: Org mode. Which constitutes a perfect transition to the next
session.&lt;/p&gt;
&lt;h2&gt;Website redesign, again&lt;/h2&gt;
&lt;p&gt;Did you notice this website has been revamping recently? The changes are
actually deeper than “just” a redesign, to a point where I had to port &lt;em&gt;all&lt;/em&gt; my
write-ups to a different markup language&lt;label for=&quot;fn3&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn3&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Are you starting to understand why “Org mode” was the perfect
transition to move on to this section? &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Why, you ask? Well, it’s actually pretty simple: as time goes, I’ve grown
lazier.&lt;/p&gt;
&lt;p&gt;Let me give you some context. Until very recently, my website was built around
the idea to have literate programming as a first-class citizen of my author
tools. For instance, you can have a look at &lt;a href=&quot;/~lthms/posts/CleopatraV1.html&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;what used to be the literate
program which was responsible for generating the
website&lt;/a&gt;. Similarly, most of &lt;a href=&quot;/~lthms/tags/coq.html&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;my write-ups about
Coq&lt;/a&gt; were actually Coq documents. Literate programming is
actually a very nice paradigm for authoring technical contents, because it
gives you the tools to keep said contents accurate and up-to-date. In a
nutshell, you cannot have a typo in one of your code snippets which would
prevent it from compiling, because you actually
compile the snippet and catch the typo when you try to generate your website.
Or at least, it is what I used to do.&lt;/p&gt;
&lt;p&gt;I decided to stop because, for all its benefits, this approach has one major
drawback: it is hard to maintain. I had invested quite some time and efforts to
keep my website sources under control, but it really was an everyday fight.
There are some strange things which start happening when you fully commit to
this, as I think I did. For instance, software dependencies tie your article
together. Suddenly, you cannot talk about this new fancy feature of the latest
Coq release without upgrading &lt;em&gt;all&lt;/em&gt; your write-ups implemented as Coq
documents&lt;label for=&quot;fn4&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn4&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Well, in theory you can. Just have each Coq document specifies the
Coq version it requires, and support this level of customization in your
build toolchain. But then, your blog takes forever to build from a cold
repository. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;That being said, most of the work had already been done. This website &lt;em&gt;was&lt;/em&gt; a
collection of literate programs, and I was pretty proud of the state of things.
I could deal with the annoyances&lt;label for=&quot;fn5&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn5&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Like using Coqdoc syntax to write my articles, for instance. I could
write about how the Coqdoc syntax irks me for ages. &lt;/span&gt;
&lt;/span&gt;. But then, as I explained in the
previous section, I decided to move away from Emacs. The first time I tried to
start a new write-up, it hit me.&lt;/p&gt;
&lt;p&gt;I used to write most of my contents using Org mode. Org mode, also known as
&lt;em&gt;the&lt;/em&gt; Emacs markup language.&lt;/p&gt;
&lt;p&gt;I know of at least &lt;a href=&quot;https://github.com/nvim-orgmode/orgmode&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;one “Org plugin” for
Neovim&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, but instead of giving it a
try, I decided to use this opportunity to tackle my “maintenance problem” once
and for all. &lt;em&gt;I gave up on literate programming for this website.&lt;/em&gt; As a result,
this website is now generated from Markdown files only (using
&lt;a href=&quot;https://github.com/markdown-it/markdown-it&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;markdown-it&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; with many plugins).
As a consequence, the generated HTML is way more “predictable.” This was enough
to motivate me at giving a try at &lt;a href=&quot;https://soupault.app/reference-manual/#metadata-extraction-and-rendering&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;Soupault’s
indexes&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;,
which are way more powerful than I anticipated. Now, this website has&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tags. Each write-up can be labeled with as many tags as I want, there is &lt;a href=&quot;/~lthms/tags&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;a
page which lists all the tags used in the website&lt;/a&gt;, and each tag has
its own page (for instance, the &lt;a href=&quot;/~lthms/tags/coq.html&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;coq&lt;/code&gt; tag&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;A &lt;a href=&quot;/~lthms/posts/index.xml&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;RSS feed&lt;/a&gt;. It was actually one of the main features I
really wanted to get with this revamp.&lt;/li&gt;
&lt;li&gt;Automatically generated list of articles in the &lt;a href=&quot;/~lthms/&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;home page&lt;/a&gt;, for each
series (see the &lt;a href=&quot;/~lthms/series/Ltac.html&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;Ltac series&lt;/a&gt; for instance). Before, I was
publishing “curated indexes,” or put in other words: I was writing these
indexes myself, by hand. And again, I’ve grown lazier.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It took me a week to go through this rework. Translating manually every write-up
was tedious, to say the least, as was implementing the Lua plugins for Soupault
since I have neither proficiency nor tooling to help me write Lua code. But I
am very glad for the final result.&lt;/p&gt;
&lt;p&gt;Also, I have invested in an Antidote license, so hopefully, this website will
have fewer typos and English butchering as of now. A clean text, delivered with
a nice and simple design, from a sane and maintainable &lt;a href=&quot;https://src.soap.coffee/soap.coffee/lthms.git/&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;Git
repository&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>Neovim, OCaml Interfaces, Tree-Sitter and LSP</title>
      <link>https://soap.coffee/~lthms/posts/NeovimOCamlTreeSitterAndLSP.html</link>
      <guid>https://soap.coffee/~lthms/posts/NeovimOCamlTreeSitterAndLSP.html</guid>
      <pubDate>May 1, 2023</pubDate>
      <description>
        
        &lt;h1&gt;Neovim, OCaml Interfaces, Tree-Sitter and LSP&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/ocaml.html&quot; class=&quot;tag hover-coral&quot; marked=&quot;&quot;&gt;ocaml&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/neovim.html&quot; class=&quot;tag hover-peach&quot; marked=&quot;&quot;&gt;neovim&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;Can we all agree that witnessing syntax highlighting being absolutely off is
probably the most annoying thing that can happen to anybody?&lt;/p&gt;
&lt;p&gt;I mean, just look at this horror.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/~lthms/img/wrong-highlighting.png&quot;&gt;&lt;figcaption&gt;&lt;p&gt;Syntax highlighting being absolutely wrong.&lt;/p&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;What you are looking at is the result of trying to enable &lt;code class=&quot;hljs&quot;&gt;tree-sitter&lt;/code&gt; for
OCaml hacking and calling it a day. In a nutshell, OCaml &lt;code class=&quot;hljs&quot;&gt;mli&lt;/code&gt; files are
quickly turning into a random mess of nonsensical colors, and I didn’t know
why. I tried to blame
&lt;a href=&quot;https://github.com/tree-sitter/tree-sitter-ocaml/issues/72&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;tree-sitter-ocaml&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;,
but, of course I was wrong.&lt;/p&gt;
&lt;p&gt;The issue is subtle, and to be honest, I don’t know if I totally grasp it. But
from my rough understanding, it breaks down as follows.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;hljs&quot;&gt;tree-sitter-ocaml&lt;/code&gt; defines two grammars: &lt;code class=&quot;hljs&quot;&gt;ocaml&lt;/code&gt; for the &lt;code class=&quot;hljs&quot;&gt;ml&lt;/code&gt; files, and
&lt;code class=&quot;hljs&quot;&gt;ocaml_interface&lt;/code&gt; (but &lt;code class=&quot;hljs&quot;&gt;ocamlinterface&lt;/code&gt; also works) for the &lt;code class=&quot;hljs&quot;&gt;mli&lt;/code&gt; files&lt;/li&gt;
&lt;li&gt;By default, neovim uses the filetype &lt;code class=&quot;hljs&quot;&gt;ocaml&lt;/code&gt; for &lt;code class=&quot;hljs&quot;&gt;mli&lt;/code&gt; files, so the incorrect
parser is being used for syntax highlighting. This explains the root issue&lt;/li&gt;
&lt;li&gt;Bonus: &lt;code class=&quot;hljs&quot;&gt;ocamllsp&lt;/code&gt; does not recognize the &lt;code class=&quot;hljs&quot;&gt;ocamlinterface&lt;/code&gt; filetype by
default (but somehow use the &lt;code class=&quot;hljs&quot;&gt;ocaml.interface&lt;/code&gt; id for &lt;code class=&quot;hljs&quot;&gt;mli&lt;/code&gt; files…&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;There is probably something to be done here. &lt;/span&gt;
&lt;/span&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, in order to have both &lt;code class=&quot;hljs&quot;&gt;tree-sitter&lt;/code&gt; and &lt;code class=&quot;hljs&quot;&gt;ocamllsp&lt;/code&gt; working at the same
time, I had to tweak my configuration a little bit.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-lua&quot;&gt;lspconfig.ocamllsp.setup({
  filetypes = vim.list_extend(
    &lt;span class=&quot;hljs-built_in&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&apos;lspconfig.server_configurations.ocamllsp&apos;&lt;/span&gt;)
      .default_config
      .filetypes,
    { &lt;span class=&quot;hljs-string&quot;&gt;&apos;ocamlinterface&apos;&lt;/span&gt; }
  ),
})

vim.cmd(&lt;span class=&quot;hljs-string&quot;&gt;[[au! BufNewFile,BufRead *.mli setfiletype ocamlinterface]]&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And now, I am blessed with a consistent syntax highlighting for my &lt;code class=&quot;hljs&quot;&gt;mli&lt;/code&gt; files.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/~lthms/img/good-highlighting.png&quot;&gt;&lt;figcaption&gt;&lt;p&gt;Syntax highlighting being absolutely right.&lt;/p&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>Spatial Shell: Call For Testers</title>
      <link>https://soap.coffee/~lthms/posts/CFTSpatialShell.html</link>
      <guid>https://soap.coffee/~lthms/posts/CFTSpatialShell.html</guid>
      <pubDate>April 27, 2023</pubDate>
      <description>
        
        &lt;h1&gt;Spatial Shell: Call For Testers&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/spatial-shell.html&quot; class=&quot;tag hover-rose&quot; marked=&quot;&quot;&gt;spatial-shell&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;In August 2022, I have discovered &lt;a href=&quot;https://material-shell.com&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;Material
Shell&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. A few weeks later, I had pieced together a
working prototype of a dynamic tiling management “a la Material Shell” for
&lt;a href=&quot;https://swaywm.org&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;sway&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. By October, the project was basically fulfilling my
needs, and I had already started to use it on my workstation&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I tried so you do not have to: having my graphical session going crazy
during a work meeting because of a software I had written. &lt;/span&gt;
&lt;/span&gt;. The project
sat there for a while until I rediscovered this thing called &lt;em&gt;holidays&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;For a short week, I tried to address at many of the remaining issues and
missing features that I was aware of. Then, I started to write
&lt;a href=&quot;https://lthms.github.io/spatial-shell/spatial.1.html&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;man pages&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, which
turned out to be the perfect opportunity to clean up every clunkiness I could
possibly find.&lt;/p&gt;
&lt;p&gt;I can’t help but find the result rather nice and satisfying, and I hope you
will enjoy it too! &lt;a href=&quot;https://github.com/lthms/spatial-shell&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;Spatial Shell&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;
works on my machine, which means it will definitely break on yours. But this is
where the fun lies, right? At this point, I definitely think the project is
ready to fall into the hands of (motivated) alpha testers.&lt;/p&gt;
&lt;p&gt;Anyway, let me give you a tour!&lt;/p&gt;
&lt;h2&gt;Spatial Model&lt;/h2&gt;
&lt;p&gt;At its core, Spatial Shell allows you to navigate a grid of windows.
Workspace are rows which can be individually configured to determine how many
windows (cells) you can see at once. More precisely, workspaces in Spatial
Shell can use two layouts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Maximize:&lt;/strong&gt; One window is displayed at a time&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Column:&lt;/strong&gt; Several windows are displayed side by side, to your convenience&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The reason &lt;strong&gt;Maximize&lt;/strong&gt; is not a particular case of &lt;strong&gt;Column&lt;/strong&gt;, but instead a
layout on its own, is to easily allow you to switch to and back from maximizing
the focused window. The following picture&lt;label for=&quot;fn2&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn2&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Created using &lt;a href=&quot;https://excalidraw.com/&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;Excalidraw&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. &lt;/span&gt;
&lt;/span&gt; summarizes one particular setup with
tree workspaces, each configured differently.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/~lthms/img/spatial-shell-example.png&quot;&gt;&lt;figcaption&gt;&lt;p&gt;Spatial Shell allows users to configure the layout of each workspace individually.&lt;/p&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Workspace 1 contains three windows, and uses the &lt;strong&gt;Column&lt;/strong&gt; layout to display
at most three windows, so each window is visible, with the focus being on
the leftmost one.&lt;/li&gt;
&lt;li&gt;Workspace 2 contains four windows, and uses the &lt;strong&gt;Column&lt;/strong&gt; layout to display at
most two windows. As a consequence, two windows are not visible.&lt;/li&gt;
&lt;li&gt;Workspace 3 contains two windows, and uses the &lt;strong&gt;Maximize&lt;/strong&gt; layout so only the
focused window is visible.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To help users know which window is currently holding the focus, Spatial Shell
slightly reduces the opacity of unfocused windows (as poorly hinted by the gray
backgrounds in the figure). Finally, Spatial Shell can also set a background
for empty workspaces (using &lt;code class=&quot;hljs language-bash&quot;&gt;swaybg&lt;/code&gt; under the hood).&lt;/p&gt;
&lt;p&gt;And this is basically it. There is not much more to say about Spatial Shell
features.&lt;/p&gt;
&lt;h2&gt;Configuration&lt;/h2&gt;
&lt;p&gt;From an implementation and user experience perspective, Spatial Shell is taking
inspiration from i3 and sway.&lt;/p&gt;
&lt;p&gt;More precisely, Spatial Shell comprises two executables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://lthms.github.io/spatial-shell/spatial.1.html&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;&lt;strong&gt;spatial&lt;/strong&gt;(1)&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, the
daemon implementing the spatial model described in the previous section, and&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lthms.github.io/spatial-shell/spatialmsg.1.html&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;&lt;strong&gt;spatialmsg&lt;/strong&gt;(1)&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, a
client used to control the current instance of spatial.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Assuming &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$spatial&lt;/span&gt;&lt;/code&gt; and &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$spatialmsg&lt;/span&gt;&lt;/code&gt; contains the paths to
spatial and spatialmsg binaries respectively, then the simplest sway
configuration to start using Spatial Shell is the following&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$spatial&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# moving the focus&lt;/span&gt;
bindsym &lt;span class=&quot;hljs-variable&quot;&gt;$mod&lt;/span&gt;+h &lt;span class=&quot;hljs-built_in&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$spatialmsg&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;focus left&quot;&lt;/span&gt;
bindsym &lt;span class=&quot;hljs-variable&quot;&gt;$mod&lt;/span&gt;+l &lt;span class=&quot;hljs-built_in&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$spatialmsg&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;focus right&quot;&lt;/span&gt;
bindsym &lt;span class=&quot;hljs-variable&quot;&gt;$mod&lt;/span&gt;+k &lt;span class=&quot;hljs-built_in&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$spatialmsg&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;focus up&quot;&lt;/span&gt;
bindsym &lt;span class=&quot;hljs-variable&quot;&gt;$mod&lt;/span&gt;+j &lt;span class=&quot;hljs-built_in&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$spatialmsg&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;focus down&quot;&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# moving the focused window&lt;/span&gt;
bindsym &lt;span class=&quot;hljs-variable&quot;&gt;$mod&lt;/span&gt;+Shift+h &lt;span class=&quot;hljs-built_in&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$spatialmsg&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;move left&quot;&lt;/span&gt;
bindsym &lt;span class=&quot;hljs-variable&quot;&gt;$mod&lt;/span&gt;+Shift+l &lt;span class=&quot;hljs-built_in&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$spatialmsg&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;move right&quot;&lt;/span&gt;
bindsym &lt;span class=&quot;hljs-variable&quot;&gt;$mod&lt;/span&gt;+Shift+k &lt;span class=&quot;hljs-built_in&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$spatialmsg&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;move up&quot;&lt;/span&gt;
bindsym &lt;span class=&quot;hljs-variable&quot;&gt;$mod&lt;/span&gt;+Shift+j &lt;span class=&quot;hljs-built_in&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$spatialmsg&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;move down&quot;&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# toggle between Maximize and Column layout&lt;/span&gt;
bindsym &lt;span class=&quot;hljs-variable&quot;&gt;$mod&lt;/span&gt;+space &lt;span class=&quot;hljs-built_in&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$spatialmsg&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;toggle layout&quot;&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# modify the number of windows to display in the Column layout&lt;/span&gt;
bindsym &lt;span class=&quot;hljs-variable&quot;&gt;$mod&lt;/span&gt;+i &lt;span class=&quot;hljs-built_in&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$spatialmsg&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;column count decrement&quot;&lt;/span&gt;
bindsym &lt;span class=&quot;hljs-variable&quot;&gt;$mod&lt;/span&gt;+o &lt;span class=&quot;hljs-built_in&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$spatialmsg&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;column count increment&quot;&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# start waybar, spatial will take care of the rest&lt;/span&gt;
&lt;span class=&quot;hljs-built_in&quot;&gt;exec&lt;/span&gt; waybar
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By default, Spatial Shell sets the initial configuration of a workspace to
the Column layout with two columns at most, and sets the opacity of the
unfocused windows to 75%. This can be customized, either globally or per
workspace, by creating a configuration file in
&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$XDG_CONFIG_HOME&lt;/span&gt;/spatial/config&lt;/code&gt;&lt;label for=&quot;fn3&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn3&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;If unset, &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$XDG_CONFIG_HOME&lt;/span&gt;&lt;/code&gt; defaults to
&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$HOME&lt;/span&gt;/.config&lt;/code&gt;. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;For instance, my config file looks like that.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;[workspace=3] default layout maximize
background &lt;span class=&quot;hljs-string&quot;&gt;&quot;~/.config/spatial/wallpaper.jpg&quot;&lt;/span&gt;
unfocus opacity 85
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See &lt;a href=&quot;https://lthms.github.io/spatial-shell/spatial.5.html&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;&lt;strong&gt;spatial&lt;/strong&gt;(5)&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; for
the list of commands supported by Spatial Shell.&lt;/p&gt;
&lt;p&gt;As a side note, readers familiar with sway will definitely pick the resemblance
with sway and swaymsg, and it actually goes pretty deep. In a nutshell, swaymsg
connects to a UNIX socket created by sway at startup time, to send it commands
(see &lt;a href=&quot;https://lthms.github.io/spatial-shell/spatial.5.html&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;&lt;strong&gt;spatial&lt;/strong&gt;(5)&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;)
using a dedicated IPC protocol inherited from i3 (see
&lt;a href=&quot;https://lthms.github.io/spatial-shell/sway-ipc.7.html&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;&lt;strong&gt;sway-ipc&lt;/strong&gt;(7)&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;). Not
only spatial also relies on sway IPC protocol to interact with sway and
implement its spatial model, it creates a UNIX of its own, and supports its own
protocol
(&lt;a href=&quot;https://lthms.github.io/spatial-shell/spatial-ipc.7.html%5D%5Bspatial-ipc.7.html&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;&lt;strong&gt;spatial-ipc&lt;/strong&gt;(7)&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;).&lt;/p&gt;
&lt;h2&gt;Waybar Integration&lt;/h2&gt;
&lt;p&gt;It is a common practice to use a so-called “bar” with sway, to display some
useful information about the current state of the system. In the &lt;code class=&quot;hljs&quot;&gt;contrib/&lt;/code&gt;
directory of &lt;a href=&quot;https://github.com/lthms/spatial-shell&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;Spatial Shell repository&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;,
interested readers will find a configuration for
&lt;a href=&quot;https://github.com/Alexays/Waybar&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;Waybar&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;&lt;label for=&quot;fn4&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn4&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Readers familiar with Material Shell design will not be surprised by
the general look and feel of the screenshot below. &lt;/span&gt;
&lt;/span&gt;. This configuration is
somewhat clunky at the moment, due to the limitations of the custom widget of
Waybar which does not allow to have one widget defines several “buttons.” I am
interested in investing a bit of time to see if I could write a native widget,
similarly to sway’s one.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/~lthms/img/spatial-shell.png&quot;&gt;&lt;figcaption&gt;&lt;p&gt;Mandatory screenshot of Spatial Shell, with the Waybar configuration.&lt;/p&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;That being said, the user experience with this integration is already pretty
neat. As long as you don’t need more than 6 workspaces and 8 windows per
workspaces&lt;label for=&quot;fn5&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn5&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;These constants are totally arbitrary and can be increased by
modifying the Waybar config, but the issue will remain that a
limit will exist. &lt;/span&gt;
&lt;/span&gt;, you are good to go!&lt;/p&gt;
&lt;h2&gt;Building from Source&lt;/h2&gt;
&lt;p&gt;As of April 2023, the only way to get Spatial Shell is to build it from source.&lt;/p&gt;
&lt;p&gt;You will need the following runtime dependencies:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;sway (i3 might be supported at some point)&lt;/li&gt;
&lt;li&gt;gmp (for bad reasons, fortunalety this will be removed at some point)&lt;/li&gt;
&lt;li&gt;swaybg&lt;/li&gt;
&lt;li&gt;waybar (if you want the full experience)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You will need the following build dependencies:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;opam&lt;/li&gt;
&lt;li&gt;scdoc (for the man pages)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then, building and installing Spatial Shell is as simple as using the two
following commands.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;make build-deps
make install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The latter command will install Spatial Shell’s binaries in
&lt;code class=&quot;hljs language-bash&quot;&gt;/usr/local/bin&lt;/code&gt;, and the man pages in &lt;code class=&quot;hljs language-bash&quot;&gt;/usr/local/man&lt;/code&gt;. You can
remove them with &lt;code class=&quot;hljs language-bash&quot;&gt;make uninstall&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To install Waybar theme, copy &lt;code class=&quot;hljs language-bash&quot;&gt;contrib/waybar/spatialbar.py&lt;/code&gt; to
&lt;code class=&quot;hljs language-bash&quot;&gt;/usr/local/bin/spatialbar&lt;/code&gt; for instance, and the Waybar style and
config file to &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$HOME&lt;/span&gt;/.config/waybar&lt;/code&gt;.&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>Patch Dependencies for Stacked Git</title>
      <link>https://soap.coffee/~lthms/posts/StackedGitPatchTheory.html</link>
      <guid>https://soap.coffee/~lthms/posts/StackedGitPatchTheory.html</guid>
      <pubDate>January 26, 2023</pubDate>
      <description>
        
        &lt;h1&gt;Patch Dependencies for Stacked Git&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/git.html&quot; class=&quot;tag hover-coral&quot; marked=&quot;&quot;&gt;git&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/opinions.html&quot; class=&quot;tag hover-mint&quot; marked=&quot;&quot;&gt;opinions&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;Every time I catch myself thinking about dependencies between
changeset of a software project, the fascinating field of patch
theories comes to my mind.&lt;/p&gt;
&lt;p&gt;A “patch theory” usually refers to the mathematical foundation behind
the data model of so-called Patch-based DVCS like Darcs and
Pijul. More precisely, a patch theory is an encoding of the state of a
repository, equipped with operations (gathered in so-called patches,
not to be confused with &lt;code class=&quot;hljs&quot;&gt;GNU diff&lt;/code&gt; patches) one can do to this
state. For instance, my rough understanding of Pijul’s patch theory is
that a repository is an oriented graph of lines, and a patch is a set
of operations onto this graph.&lt;/p&gt;
&lt;p&gt;An interesting aspect of patch theory is that it requires a partial
order for its patches, from which a Patch-based DVCS derives a
dependency graph. In a nutshell, a patch &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;P&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.13889em;&quot;&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; depends on the patches
which are responsible for the presence of the lines that &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;P&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.13889em;&quot;&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
modifies.&lt;/p&gt;
&lt;p&gt;I have always found this idea of a dependency graph for the patches
of a repository fascinating, because I though it would be a very
valuable tool in the context of software development.&lt;/p&gt;
&lt;p&gt;I wanted to slightly change the definition of what a patch
dependency is, though. See, the partial order of Darcs and Pijul
focus on syntactic dependencies: the relation between lines in text
files. They need that to reconstruct these text files in the file
system of their users. As a software developers writing these text
files, I quickly realized these dependencies were of little interest
to me, though. What I wanted to be able to express was that a
feature introduced by a patch &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;P&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.13889em;&quot;&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; relied on a fix introduced by a
patch &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msup&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;mo mathvariant=&quot;normal&quot; lspace=&quot;0em&quot; rspace=&quot;0em&quot;&gt;′&lt;/mo&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;P&apos;&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7519em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.13889em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.7519em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;′&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;I have experimented with Darcs and Pijul quite a bit, with this idea
stuck in the back of my mind. At the end of this journey, I
convinced myself&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I am not trying to convince you, per say. This is a very personal
and subjective feedback, it does not mean someone else couldn&apos;t reach a
different conclusion. &lt;/span&gt;
&lt;/span&gt; (1) this beautiful idea I
had simply could not scale, and (2) neither I nor our industry is
ready to give up on the extensive ecosystem that has been built on top
of &lt;code class=&quot;hljs&quot;&gt;git&lt;/code&gt; just yet. As a consequence, my interest in Patch-based DVCS
decreased sensibly.&lt;/p&gt;
&lt;p&gt;Until very recently, that is. I got reminded of the appeal of a
dependency graph for changesets when I started adopted a Gitlab
workflow centered around Stacked Git and smaller, sometimes
interdependent MRs.&lt;/p&gt;
&lt;p&gt;A manually curated graph dependency for a whole repository is not
practical, but what about my local queue of patches, patiently
waiting to be integrated into the upstream repository I am
contributing too?  Not only does it look like a more approachable
task, it could make synchronizing my stacked MRs a lot easier.&lt;/p&gt;
&lt;p&gt;The workflow I have in mind would proceed as follows.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stacked Git’s &lt;code class=&quot;hljs&quot;&gt;new&lt;/code&gt; and &lt;code class=&quot;hljs&quot;&gt;edit&lt;/code&gt; commands could be extended to let
developers declare dependencies between their patches. It would be
the commands’ responsibility to enforce the wellfoundness of the
dependency graph (&lt;em&gt;e.g.&lt;/em&gt;, prevent the introduction of cycles in the
graph, and maybe diamonds too&lt;label for=&quot;fn2&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn2&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;At least in a first version. There is definitely value in being
able to work with two independent patches in conjunction with a third one
that needs them both. That being said, our goal here is to organize our
work locally, and if it is made easier by declaring artificial dependency,
this is a pragmatic sacrifice I am personally willing to make. &lt;/span&gt;
&lt;/span&gt;).&lt;/li&gt;
&lt;li&gt;The &lt;code class=&quot;hljs&quot;&gt;series&lt;/code&gt; command could be improved to display the resulting
dependency graph.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;hljs&quot;&gt;push&lt;/code&gt; and &lt;code class=&quot;hljs&quot;&gt;pop&lt;/code&gt; would automatically take care (pushing or popping)
of the selected patch(es) dependencies.&lt;/li&gt;
&lt;li&gt;Ideally, Stacked Git would get a new command &lt;code class=&quot;hljs&quot;&gt;prepare &amp;lt;PATCH NAME&amp;gt;&lt;/code&gt;
which would pop every patches applied, then only only push &lt;code class=&quot;hljs&quot;&gt;&amp;lt;PATCH NAME&amp;gt;&lt;/code&gt; and its dependencies (in the reverse order). Developers could
fix conflicts if need be. That is, Stacked Git would not be
responsible for the consistency or correctness of the dependency
graph.&lt;/li&gt;
&lt;li&gt;Stacked Git could get commands to detect potential issues with the
dependency graph specified by the developer (mostly consisting in
dry-run of &lt;code class=&quot;hljs&quot;&gt;prepare&lt;/code&gt; to check if it would lead to conflicts).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Because what we want is semantic dependencies, not syntactic dependencies
between patches, I really think it makes a lot of sense to completely delegate
the dependencies declaration to the developer&lt;label for=&quot;fn3&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn3&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Further versions of Stacked Git could explore computing the
dependency graph automatically, similarly to what Git does. But I think
that if Darcs and Pijul told us anything, it&apos;s that this computation is far
from being trivial. &lt;/span&gt;
&lt;/span&gt;. The very mundane
example that convinced me is the &lt;code class=&quot;hljs&quot;&gt;CHANGELOG&lt;/code&gt; file any mature software project
ends up maintaining. If the contribution guidelines require to modify the
&lt;code class=&quot;hljs&quot;&gt;CHANGELOG&lt;/code&gt; file in the same commit as a feature is introduced, then the
patches to two independent features will systematically conflict. This does not
mean, from my patch queue perspective, I should be forced to &lt;code class=&quot;hljs&quot;&gt;pop&lt;/code&gt; the first
commit before starting to work on the second one. It just means that when I
call &lt;code class=&quot;hljs&quot;&gt;stg prepare&lt;/code&gt;, I can have to fix a conflict, but fixing Git conflicts is
part of the job after all&lt;label for=&quot;fn4&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn4&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;And we have tools to help us. I wonder to which extends &lt;code class=&quot;hljs&quot;&gt;git rerere&lt;/code&gt;
could save the day in some cases, for instance. &lt;/span&gt;
&lt;/span&gt;. If for some reasons solving a conflict
proves to be too cumbersome, I can always acknowledge that, and declare a new
dependency to the appropriate patch. It only means I and my reviewers will be
constrained a bit more than expected when dealing with my stack of MRs.&lt;/p&gt;
&lt;p&gt;I am under the impression that this model extends quite nicely the current way
Stacked Git is working. To its core, it extends its data model to constraint a
bit &lt;code class=&quot;hljs&quot;&gt;push&lt;/code&gt; and &lt;code class=&quot;hljs&quot;&gt;pop&lt;/code&gt;, and empowers developers to organize a bit its local mess.&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>How I Keep Using Stacked Git at $WORK</title>
      <link>https://soap.coffee/~lthms/posts/StackedGit2.html</link>
      <guid>https://soap.coffee/~lthms/posts/StackedGit2.html</guid>
      <pubDate>January 16, 2023</pubDate>
      <description>
        
        &lt;h1&gt;How I Keep Using Stacked Git at &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$WORK&lt;/span&gt;&lt;/code&gt;&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/git.html&quot; class=&quot;tag hover-periwinkle&quot; marked=&quot;&quot;&gt;git&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/workflow.html&quot; class=&quot;tag hover-mint&quot; marked=&quot;&quot;&gt;workflow&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;One year ago, I have published an article summarizing &lt;a href=&quot;/~lthms/posts/StackedGit.html&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;my experience using
Stacked Git at &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$WORK&lt;/span&gt;&lt;/code&gt;&lt;/a&gt;. Twelve months later,
enough has changed to motivate a spin-off piece.&lt;/p&gt;
&lt;h2&gt;Stacked Git is &lt;em&gt;Fast&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;Firstly, it is important to state that my main complaint about
Stacked Git is now a thing of the past&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;For fairness, I have removed the related section in my previous
write-up. &lt;/span&gt;
&lt;/span&gt;! Stacked Git does not feel slow
anymore, and far from it. This is because &lt;a href=&quot;https://github.com/stacked-git/stgit/discussions/185&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;Stacked Git 2.0 has been rewritten
in Rust&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. While RiiR
(&lt;em&gt;Rewrite it in Rust&lt;/em&gt;) is a running meme on the Internet, in this particular
case, the result is very exciting.&lt;/p&gt;
&lt;p&gt;Thanks to the performance boost, my Zsh prompt does not take 0.1s to
appear!&lt;/p&gt;
&lt;p&gt;Speaking of Zsh prompt, basically what I ended up displaying is &lt;code class=&quot;hljs&quot;&gt;(&amp;lt;TOP PATCH NAME&amp;gt; &amp;lt;APPLIED PATCHES COUNT&amp;gt;/&amp;lt;PATCHSET SIZE&amp;gt; &amp;lt;HIDDEN PATCHES COUNT)&lt;/code&gt;. For
instance, &lt;code class=&quot;hljs&quot;&gt;(fix-1337 1/2 3)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In case you want to take inspiration in my somewhat working configuration, here
is the snippet of interest.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;local&lt;/span&gt; series_top=&lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-subst&quot;&gt;$(stg top 2&amp;gt; /dev/null)&lt;/span&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;hljs-built_in&quot;&gt;local&lt;/span&gt; total=&lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-subst&quot;&gt;$(stg series 2&amp;gt; /dev/null | wc -l)&lt;/span&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;hljs-built_in&quot;&gt;local&lt;/span&gt; hidden=&lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-subst&quot;&gt;$(stg series --hidden 2&amp;gt; /dev/null | wc -l)&lt;/span&gt;&quot;&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; [[ &lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-variable&quot;&gt;${total}&lt;/span&gt;&quot;&lt;/span&gt; -gt 0 ]]; &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;hljs-built_in&quot;&gt;local&lt;/span&gt; not_applied=&lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-subst&quot;&gt;$(stg series | grep -E &apos;^-&apos; | wc -l)&lt;/span&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;hljs-built_in&quot;&gt;local&lt;/span&gt; applied=&lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-subst&quot;&gt;$(($total - $not_applied)&lt;/span&gt;)&quot;&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; [[ -z &lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-variable&quot;&gt;${series_top}&lt;/span&gt;&quot;&lt;/span&gt; ]]; &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;
        series_top=&lt;span class=&quot;hljs-string&quot;&gt;&quot;·&quot;&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;fi&lt;/span&gt;

    &lt;span class=&quot;hljs-built_in&quot;&gt;echo&lt;/span&gt; -n &lt;span class=&quot;hljs-string&quot;&gt;&quot;(&lt;span class=&quot;hljs-variable&quot;&gt;${status_color}&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;${series_top}&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;${applied}&lt;/span&gt;/&lt;span class=&quot;hljs-variable&quot;&gt;${total}&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;${hidden}&lt;/span&gt;)&quot;&lt;/span&gt;
    &lt;span class=&quot;hljs-built_in&quot;&gt;echo&lt;/span&gt; -n &lt;span class=&quot;hljs-string&quot;&gt;&quot;  (&lt;span class=&quot;hljs-subst&quot;&gt;$(current_branch)&lt;/span&gt;)&quot;&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Branchless Workflow&lt;/h2&gt;
&lt;p&gt;Last year, I was using Stacked Git on top of git branches. More precisely, I
had one branch for each (stack of) Merge Request. It worked well, because my
typical MR counted 3 to 4 commits in average.&lt;/p&gt;
&lt;p&gt;Fast forward today, and things have changed on this front too. In a nutshell, I
have become a “one commit per MR” maximalist of sort&lt;label for=&quot;fn2&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn2&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;It goes without saying that this approach comes with its set of
drawbacks too.&lt;/span&gt;
&lt;span class=&quot;footnote-p&quot;&gt;During the past year, I’ve pushed fairly large commits which could have
been split into several smaller ones, for the sake of keeping my “one
commit per MR” policy. I have also had to manage large stacks of MRs. &lt;/span&gt;
&lt;/span&gt;. I find this
approach very effective to get more focused reviews, and to reduce the time it
takes for a given MR to be integrated into the main branch.&lt;/p&gt;
&lt;p&gt;My previous approach based on git branches did not scale well with
this new mindset, and during the course of the year, I stopped using
branches altogether&lt;label for=&quot;fn3&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn3&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I have not invented the branchless workflow, of
course.&lt;/span&gt;
&lt;span class=&quot;footnote-p&quot;&gt;After it was first published, someone posted a link to my Stacked Git
article on Hacker News, and &lt;a href=&quot;https://news.ycombinator.com/item?id=29959224&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;&lt;em&gt;@arxanas&lt;/em&gt; posted a comment about
&lt;code class=&quot;hljs&quot;&gt;git-branchless&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. I tried
the tool, and even if it never clicked for me, I was really compelled by
its core ideas.&lt;/span&gt;
&lt;span class=&quot;footnote-p&quot;&gt;Similarly, &lt;a href=&quot;https://drewdevault.com/2020/04/06/My-weird-branchless-git-workflow.html&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;Drew DeVault has published a complete article on its own
branchless workflow in
2020&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;These days, I proceed as follows.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I name each patch after the branch to which I will push it on our
upstream Git remote.&lt;/li&gt;
&lt;li&gt;99% of the time, I push my work using &lt;code class=&quot;hljs language-bash&quot;&gt;git push -f upstream @:$(stg top)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;I created a small git plugin I called &lt;code class=&quot;hljs&quot;&gt;git-prepare&lt;/code&gt; which allows
me to select one of the patch of my current patchset using &lt;code class=&quot;hljs&quot;&gt;fzf&lt;/code&gt;,
and which pops all other patches that are currently applied.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code class=&quot;hljs&quot;&gt;git-prepare&lt;/code&gt; is really straightforward:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;#!/bin/sh&lt;/span&gt;
patch=$(stg series -P | fzf)

&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; [[ ! $? -eq 0 ]] ; &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;hljs-built_in&quot;&gt;exit&lt;/span&gt; $?
&lt;span class=&quot;hljs-keyword&quot;&gt;fi&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; [ -n &lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-subst&quot;&gt;$(stg series -A)&lt;/span&gt;&quot;&lt;/span&gt; ]; &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;
    stg pop -a
&lt;span class=&quot;hljs-keyword&quot;&gt;fi&lt;/span&gt;

stg push &lt;span class=&quot;hljs-variable&quot;&gt;${patch}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The main hurdle which I still need to figure out is how to deal with
stacked MRs. Currently, this is very manual. I need to remember
which commit belongs to the stack, the order and dependencies of
these commits, and I need to publish each commit individually using
&lt;code class=&quot;hljs language-bash&quot;&gt;stg push; git push @:$(stg top)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The pragmatic answer is definitely to come back to git branches &lt;em&gt;for
this particular use case&lt;/em&gt;, but it&apos;s not the &lt;em&gt;fun&lt;/em&gt; answer. So from
time to time, I try to experiment with alternative approaches. My current
intuition is that, by adopting a naming convention for my patches, I
could probably implement a thin tooling on top of Stacked Git to
deal with dependents commits.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Putting aside stacked MRs for now, I am really satisfied with my
workflow. It’s very lightweight and intuitive, and working without
Stacked Git now feels backward and clunky.&lt;/p&gt;
&lt;p&gt;So I will take this opportunity to thank one more time Stacked Git’s
authors and contributors. You all are making my professional like
easier with your project.&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>What happened in October and November 2022?</title>
      <link>https://soap.coffee/~lthms/posts/November2022.html</link>
      <guid>https://soap.coffee/~lthms/posts/November2022.html</guid>
      <pubDate>November 19, 2022</pubDate>
      <description>
        
        &lt;h1&gt;What happened in October and November 2022?&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/spatial-shell.html&quot; class=&quot;tag hover-periwinkle&quot; marked=&quot;&quot;&gt;spatial-shell&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/nanowrimo.html&quot; class=&quot;tag hover-peach&quot; marked=&quot;&quot;&gt;nanowrimo&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/coqffi.html&quot; class=&quot;tag hover-coral&quot; marked=&quot;&quot;&gt;coqffi&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;It is November 19 today, and I’m one month and 4 days late for the October
Retrospective! Truth is, &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$WORK&lt;/span&gt;&lt;/code&gt; has been intense lately, to a point
where I have not made much progress on my side projects. Anyway.&lt;/p&gt;
&lt;p&gt;I have implemented the last feature I was really missing in my daily
use of Spatial Sway: moving windows to adjacent workspaces. As a
result, I think I can say that Spatial Sway has really reached the
“Minimum Viable Product” stage, with a convenient UX, and a nice
enough UI. It is still lacking when it comes to configurability,
though. It is the next item of my TODO list, but I have no idea when I
will implement the support for a configuration file.&lt;/p&gt;
&lt;p&gt;Another highlight of the past two months was the
&lt;a href=&quot;https://nanowrimo.org&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;NaNoWriMo&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. I took the last week of October and the
first week of November off to plan and start writing a fiction project for it.
Writing again was really nice, and I even gave writing fiction in English a
shot. That made me uncover a bug in the English support of
&lt;a href=&quot;https://crates.io/crates/ogam&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;ogam&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, my markup language for fiction writers,
which led me to publish a fix on Crates.io. However, as soon as I came back to
&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$WORK&lt;/span&gt;&lt;/code&gt;, my writing spree ended. That’s okay, though. It gave me plenty
of ideas for future sessions. Thanks, NaNoWriMo! Sorry to quit so soon, and see
you next year, maybe.&lt;/p&gt;
&lt;p&gt;Finally, a nice surprise of the past month is that &lt;a href=&quot;https://github.com/ocaml/dune/pull/6489&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;someone has started working
on adding proper support for &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; to
&lt;code class=&quot;hljs&quot;&gt;dune&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, the build system for OCaml
and Coq! I’m thrilled by this. Thanks,
&lt;a href=&quot;https://github.com/Alizter&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;&lt;strong&gt;@Alizter&lt;/strong&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;This wraps up this retrospective. I hope I will have more interesting,
concrete news to share next month.&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>What happened in September 2022?</title>
      <link>https://soap.coffee/~lthms/posts/September2022.html</link>
      <guid>https://soap.coffee/~lthms/posts/September2022.html</guid>
      <pubDate>September 18, 2022</pubDate>
      <description>
        
        &lt;h1&gt;What happened in September 2022?&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/spatial-shell.html&quot; class=&quot;tag hover-peach&quot; marked=&quot;&quot;&gt;spatial-shell&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/meta.html&quot; class=&quot;tag hover-lemon&quot; marked=&quot;&quot;&gt;meta&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;It is September 18 today, and it has already been a month since I
decided to start these retrospectives. This means it is time to take a
step back and reflect of what happened these past few thirty days or
so&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;There is the shocking news that I have started to use syntax
highlighting again. But let’s not linger too much into it just yet. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;h2&gt;Spatial Sway&lt;/h2&gt;
&lt;p&gt;A few days after publishing my August Retrospective, I have learned
the existence of &lt;a href=&quot;https://material-shell.com&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;Material Shell&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, an extension for
GNOME 3 that provides a very interesting user experience.&lt;/p&gt;
&lt;p&gt;I tried it for a few hours, but the thing kept crashing (it’s
probably on me, I did not even remember I had Gnome installed on my
machine, and I would not be surprised the culprit was my dusty setup
rather than Material Shell itself). The experience remained very
promising, though. Their “spatial model” especially felt like a very
good fit for me. Basically, the main idea is that you have a grid of
windows, with your workspaces acting as the rows. You can navigate
horizontally (from one workspace to another), or horizontally, and
you choose how many windows you want to see at once on your screen.&lt;/p&gt;
&lt;p&gt;And so for a few hours, I was a bit frustrated by the situation…
until I learned about how one can actually manage and extend Sway
(the Wayland compositor I use for several years now) thanks to its IPC
protocol.  I spend like three days experimenting, first in Rust, then in
OCaml&lt;label for=&quot;fn2&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn2&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;This was actually an interesting thought process. I am using OCaml at
&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$WORK&lt;/span&gt;&lt;/code&gt; for about more than a year now.&lt;/span&gt;
&lt;span class=&quot;footnote-p&quot;&gt;I have curated a setup that works pretty well, and I am familiar with the
development tools. On the contrary, I had not written a line of Rust for at
least a year, my Emacs configuration for this language was broken, and I
had lost all my fluency in this language. Still, I was not expecting to
pick OCaml when I started this project. &lt;/span&gt;
&lt;/span&gt;, and by the end of the week, I had a first working prototype I
called &lt;a href=&quot;https://github.com/lthms/spatial-shell&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;Spatial Sway&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. It works pretty
well; well enough that I am using it daily for several weeks now. It feels
clunky at times, but it works well, and I have been able to write a
&lt;a href=&quot;https://github.com/Alexays/Waybar&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;Waybar&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; configuration heavily inspired on
Material Shell UI.&lt;/p&gt;
&lt;p&gt;Overall, I am pretty satisfied with this turnout. Writing a hobbyist
software project is always nice, but the ones you can integrate in
your daily workflow are the best one. The last time I did that was
&lt;a href=&quot;https://sr.ht/~lthms/keyrd&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;&lt;strong&gt;keyrd&lt;/strong&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, my little keystrokes counting
daemon&lt;label for=&quot;fn3&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn3&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;19,970,965 since I started using it at the time of writing this
article &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Anyway, lots remains to be said about Spatial Sway, but I might save
it for a bit later. I still have some key features to implement
(notably, moving a window to another workspace), then I will
probably try to advertise it a bit. I am under the impression this
project could be of interest for others, and I would love to see it
used by folks willing to give a Material Shell-like experience a
try, without having to deal with Gnome Shell. By the way,
considering Sway is a drop-in replacement for i3, and that it
implements the exact same IPC protocol, there is no reason why
Spatial Sway is actually Sway specific, and I will rename it Spatial
Shell at some point.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/~lthms/img/spatial-sway-preview.png&quot;&gt;&lt;figcaption&gt;&lt;p&gt;Mandatory screenshot of Spatial Sway.&lt;/p&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;h2&gt;This Website&lt;/h2&gt;
&lt;p&gt;On a side note, I have started to refine the layout of this website
a bit. Similarly, I have written a new, curated home page where I
want to highlight the most recent things I have published on the
Internet.&lt;/p&gt;
&lt;p&gt;I have been experimenting with
&lt;a href=&quot;https://github.com/cpitclaudel/alectryon/&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;Alectryon&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; as a way to replace
&lt;code class=&quot;hljs&quot;&gt;coqdoc&lt;/code&gt;, to improve the readability of my Coq-related articles. Unfortunately,
it looks like this tool is missing &lt;a href=&quot;https://github.com/cpitclaudel/alectryon/issues/86&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;a key feature I
need&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. I might try to get
my hand dirty and implement it myself if I find the time and the motivation
in the following weeks.&lt;/p&gt;
&lt;p&gt;Finally, reading about how &lt;a href=&quot;https://xeiaso.net/talks/how-my-website-works&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;Xe Iaso’s talk about how she generates her
blog&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; was very inspiring to me.
I can only suggest that you have a look.&lt;/p&gt;
&lt;p&gt;Though not to the same extent, I also think I have spent way too much effort in
my website. Most of my Coq-related articles are actual Coq program, expect the
articles about &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; which are Org mode literate programs. Hell, this website
itself used to be a literate program of the sort, until I stopped using my
homegrown literate programming toolchain &lt;strong&gt;&lt;code class=&quot;hljs&quot;&gt;cleopatra&lt;/code&gt;&lt;/strong&gt; last month. At some
point, I have even spent a bit of time to ensure most of the pages of this
website were granted a 100/100 on websites like PageSpeed Insight&lt;label for=&quot;fn4&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn4&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Good news, I’ve just checked, and it still is! &lt;/span&gt;
&lt;/span&gt;. I
had almost forgotten.&lt;/p&gt;
&lt;p&gt;A lot remains to be done, but watching this talk made me reflect on
the job done. And opened my eyes to a new perspective, too. We will
see what translates into reality.&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>What happened in August 2022?</title>
      <link>https://soap.coffee/~lthms/posts/August2022.html</link>
      <guid>https://soap.coffee/~lthms/posts/August2022.html</guid>
      <pubDate>August 15, 2022</pubDate>
      <description>
        
        &lt;h1&gt;What happened in August 2022?&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/emacs.html&quot; class=&quot;tag hover-mint&quot; marked=&quot;&quot;&gt;emacs&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/meta.html&quot; class=&quot;tag hover-lemon&quot; marked=&quot;&quot;&gt;meta&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;Without further ado, let’s take a look at what was achieved
for the last thirty days or so.&lt;/p&gt;
&lt;h2&gt;Emacs&lt;/h2&gt;
&lt;p&gt;I have started tweaking and improving my Emacs
&lt;a href=&quot;https://src.soap.coffee/dotfiles/emacs.d.git&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;configuration&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;
again&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;After having used Emacs for seven years now, I am nowhere close
to consider my configuration as a done project. I really envy developers
who are using their editor with little to no customization. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;h3&gt;Theme Selection Menu&lt;/h3&gt;
&lt;p&gt;The change I am the most excited about is that I have &lt;em&gt;finally&lt;/em&gt; reduced the
boilerplate in need to write to use a new theme. I am very indecisive when
it comes to theming. I like to have my choices, and I get tired of any
color scheme pretty quickly. As a consequence, I introduced a customizable
variable to let me select a theme dynamically, and have this choice persist
across Emacs session.&lt;/p&gt;
&lt;p&gt;I have a Hydra menu that allows me to select which theme I want to
use for the time being. It looks like this.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/~lthms/img/select-theme.png&quot;&gt;&lt;figcaption&gt;&lt;p&gt;A Hydra menu for selecting a theme.&lt;/p&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;But adding new entries to this menu was very cumbersome, and mostly
boilerplate that I know a good macro could abstract away. And I can
finally report that I was right all along. I have my macros now,
and they allow me to have the Hydra menu above generated with these
simple lines of code.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-lisp&quot;&gt;(&lt;span class=&quot;hljs-name&quot;&gt;use-theme&lt;/span&gt; ancientless &lt;span class=&quot;hljs-string&quot;&gt;&quot;a&quot;&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;:straight&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;:load-path&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;~/.emacs.d/lisp&quot;&lt;/span&gt;)
(&lt;span class=&quot;hljs-name&quot;&gt;use-theme&lt;/span&gt; darkless &lt;span class=&quot;hljs-string&quot;&gt;&quot;d&quot;&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;:straight&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;:load-path&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;~/.emacs.d/lisp&quot;&lt;/span&gt;)
(&lt;span class=&quot;hljs-name&quot;&gt;use-theme&lt;/span&gt; brightless &lt;span class=&quot;hljs-string&quot;&gt;&quot;b&quot;&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;:straight&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;:load-path&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;~/.emacs.d/lisp&quot;&lt;/span&gt;)
(&lt;span class=&quot;hljs-name&quot;&gt;use-theme&lt;/span&gt; monotropic &lt;span class=&quot;hljs-string&quot;&gt;&quot;m&quot;&lt;/span&gt;)
(&lt;span class=&quot;hljs-name&quot;&gt;use-theme&lt;/span&gt; monokai &lt;span class=&quot;hljs-string&quot;&gt;&quot;M&quot;&lt;/span&gt;)
(&lt;span class=&quot;hljs-name&quot;&gt;use-theme&lt;/span&gt; nothing &lt;span class=&quot;hljs-string&quot;&gt;&quot;n&quot;&lt;/span&gt;)
(&lt;span class=&quot;hljs-name&quot;&gt;use-theme&lt;/span&gt; eink &lt;span class=&quot;hljs-string&quot;&gt;&quot;e&quot;&lt;/span&gt;)
(&lt;span class=&quot;hljs-name&quot;&gt;use-theme&lt;/span&gt; dracula &lt;span class=&quot;hljs-string&quot;&gt;&quot;D&quot;&lt;/span&gt;)
(&lt;span class=&quot;hljs-name&quot;&gt;use-theme&lt;/span&gt; chocolate &lt;span class=&quot;hljs-string&quot;&gt;&quot;c&quot;&lt;/span&gt;)
(&lt;span class=&quot;hljs-name&quot;&gt;use-themes-from&lt;/span&gt; tao-theme
                 &apos;((&lt;span class=&quot;hljs-string&quot;&gt;&quot;tl&quot;&lt;/span&gt; . tao-yang)
                   (&lt;span class=&quot;hljs-string&quot;&gt;&quot;td&quot;&lt;/span&gt; . tao-yin)))
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Eldoc and Flycheck Popups&lt;/h3&gt;
&lt;p&gt;I have been experimenting with several combinations of packages to
have Eldoc and Flycheck using pop-up-like mechanisms to report
things to me, instead of the echo area.&lt;/p&gt;
&lt;p&gt;The winning setup for now is the one that uses the &lt;a href=&quot;https://github.com/cpitclaudel/quick-peek&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;quick-peek&lt;/code&gt;
package&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. That is,
&lt;a href=&quot;https://github.com/flycheck/flycheck-inline&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;flycheck-inline&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; (customized to
use &lt;code class=&quot;hljs&quot;&gt;quick-peek&lt;/code&gt;, as suggested in their README), and
&lt;a href=&quot;https://melpa.org/#/eldoc-overlay&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;eldoc-overlay&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. This works well enough,
so the pop-ups of eldoc are maybe a bit too distracting.&lt;/p&gt;
&lt;p&gt;#&lt;a href=&quot;/~lthms/img/flycheck-inline.png&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;flycheck-inline&lt;/code&gt; in action with an OCaml compilation error.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In my quest for pop-ups, I ran into several issues with the packages I tried
out. For instance, &lt;a href=&quot;https://github.com/casouri/eldoc-box&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;eldoc-box&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; was very
nice, but also very slow for some reason. It turns out there was an issue
about that slowness, wherein the culprit was identified. This allowed me to
&lt;a href=&quot;https://github.com/casouri/eldoc-box/pull/48&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;submit a pull request that got merged rather
quickly&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Similarly, after a packages update, I discovered
&lt;a href=&quot;https://github.com/flycheck/flycheck-ocaml&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;flycheck-ocaml&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; was no longer
working, and &lt;a href=&quot;https://github.com/flycheck/flycheck-ocaml/pull/14&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;submit a patch to fix the
issue&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;This Website&lt;/h2&gt;
&lt;p&gt;I have not been investing a lot of time in this website for the past
six years or so. This month, things change a bit on that side too.&lt;/p&gt;
&lt;h3&gt;New Contents&lt;/h3&gt;
&lt;p&gt;First, I have published a (short) article on &lt;a href=&quot;/~lthms/posts/RankNTypesInOCaml.html&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;higher-order
polymorphism in OCaml&lt;/a&gt;. The goal was for me to
log somewhere the solution for an odd problem I was confronted to at
&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$WORK&lt;/span&gt;&lt;/code&gt;, but the resulting article was not doing a great job as
conveying this. In particular, two comments on Reddit motivated me to rework
it, and I am glad I did. I hope you enjoy the retake.&lt;/p&gt;
&lt;p&gt;Once this was out of the way, I decided that generating this website was taking
way too much time for no good enough reason. The culprit was &lt;strong&gt;&lt;code class=&quot;hljs&quot;&gt;cleopatra&lt;/code&gt;&lt;/strong&gt;, a
toolchain I had developed in 2020 to integrate the build process of this
website as additional contents that I thought might interest people. The sad
things were: &lt;strong&gt;&lt;code class=&quot;hljs&quot;&gt;cleopatra&lt;/code&gt;&lt;/strong&gt; was adding a significant overhead, and I never take
the time to actually document them properly.&lt;/p&gt;
&lt;h3&gt;Under the Hood&lt;/h3&gt;
&lt;p&gt;Overall, the cost of using &lt;strong&gt;&lt;code class=&quot;hljs&quot;&gt;cleopatra&lt;/code&gt;&lt;/strong&gt; was not worth the burden, and so I
got rid of it. Fortunately, it was not very difficult, since the job of
&lt;strong&gt;&lt;code class=&quot;hljs&quot;&gt;cleopatra&lt;/code&gt;&lt;/strong&gt; was to extracting the generation processes from org files; I
just add to implement a small &lt;code class=&quot;hljs&quot;&gt;makefile&lt;/code&gt; to make use of these files, without
having to rely on &lt;strong&gt;&lt;code class=&quot;hljs&quot;&gt;cleopatra&lt;/code&gt;&lt;/strong&gt; anymore.&lt;/p&gt;
&lt;p&gt;This was something I was pondering to do for a long time, and as
often in these circumstances, this gave me the extra motivation I
needed to tackle other ideas I had in mind for this website. This
is why now, rather than starting one Emacs process per Org file I
have to process, my build toolchain starts one Emacs server, and
later uses &lt;code class=&quot;hljs&quot;&gt;emacsclient&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now, most of the build time is spent by &lt;a href=&quot;https://soupault.app&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;soupault&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. I guess
I will have to spend some time on the Lua plugins I have developed for it at
some point.&lt;/p&gt;
&lt;h2&gt;A New Mailing List&lt;/h2&gt;
&lt;p&gt;Finally, I have created &lt;a href=&quot;https://lists.sr.ht/~lthms/public-inbox&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;a public
mailing&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; list that is available if you
want to start a discussion on one of my articles. Don’t hesitate to use it, or
to register to it!&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>Writing a Function Whose Argument is a Polymorphic Function in OCaml</title>
      <link>https://soap.coffee/~lthms/posts/RankNTypesInOCaml.html</link>
      <guid>https://soap.coffee/~lthms/posts/RankNTypesInOCaml.html</guid>
      <pubDate>August 7, 2022</pubDate>
      <description>
        
        &lt;h1&gt;Writing a Function Whose Argument is a Polymorphic Function in OCaml&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/ocaml.html&quot; class=&quot;tag hover-periwinkle&quot; marked=&quot;&quot;&gt;ocaml&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;In OCaml, it is not possible to write a function whose argument is a
polymorphic function. Trying to write such a function results in the
type-checker complaining back at you.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; foo (&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; a b) id (x : a) (y : b) = (id x, id y)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;Line 1, characters 50-51:
1 | let foo (type a b) id (x : a) (y : b) = (id x, id y);;
                                                      ^
Error: This expression has type b but an expression was expected
of type a
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When OCaml tries to type check &lt;code class=&quot;hljs language-ocaml&quot;&gt;foo&lt;/code&gt;, it infers &lt;code class=&quot;hljs language-ocaml&quot;&gt;id&lt;/code&gt; expects an
argument of type &lt;code class=&quot;hljs language-ocaml&quot;&gt;a&lt;/code&gt; because of &lt;code class=&quot;hljs language-ocaml&quot;&gt;id x&lt;/code&gt;, then fails when trying
to type check &lt;code class=&quot;hljs language-ocaml&quot;&gt;id y&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The trick to be able to write &lt;code class=&quot;hljs language-ocaml&quot;&gt;foo&lt;/code&gt; is to use records. Indeed, while
the argument of a function cannot be polymorphic, the field of a record can.
This effectively makes it possible to write &lt;code class=&quot;hljs language-ocaml&quot;&gt;foo&lt;/code&gt;, at the cost of a
level of indirection.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; id = {id : &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt;. &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt;}

&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; foo {id} x y = (id x, id y)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From a runtime perspective, it is possible to tell OCaml to remove the
introduced indirection with the &lt;code class=&quot;hljs language-ocaml&quot;&gt;unboxed&lt;/code&gt; annotation. There is nothing
we can do in the source, though. We need to destruct &lt;code class=&quot;hljs language-ocaml&quot;&gt;id&lt;/code&gt; in
&lt;code class=&quot;hljs language-ocaml&quot;&gt;foo&lt;/code&gt;, and we need to construct it at its call site.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;g {id = &lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; x -&amp;gt; x}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As a consequence, this solution is not a silver bullet, but it is an option
that is worth considering if, &lt;em&gt;e.g.&lt;/em&gt;, it allows us to export a cleaner API to the
consumer of a module. Personally, I have been considering this trick recently
to remove the need for a library to be implemented as a functor.&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>How I Use Stacked Git at $WORK</title>
      <link>https://soap.coffee/~lthms/posts/StackedGit.html</link>
      <guid>https://soap.coffee/~lthms/posts/StackedGit.html</guid>
      <pubDate>January 16, 2022</pubDate>
      <description>
        
        &lt;h1&gt;How I Use Stacked Git at &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$WORK&lt;/span&gt;&lt;/code&gt;&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/git.html&quot; class=&quot;tag hover-coral&quot; marked=&quot;&quot;&gt;git&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/workflow.html&quot; class=&quot;tag hover-periwinkle&quot; marked=&quot;&quot;&gt;workflow&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;According to &lt;a href=&quot;https://lobste.rs/s/s6quvg/stacked_git&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;my Lobste.rs history&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, I
have run into &lt;a href=&quot;https://stacked-git.github.io&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;Stacked Git&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; in early April
2021, and I remember that its promises hit a soft spot. A few weeks later, I was
submitting &lt;a href=&quot;https://github.com/stacked-git/stgit/pull/100&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;a &lt;em&gt;pull request&lt;/em&gt; to teach Stacked Git to sign
commits&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. It was all I needed to
start using it at &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$WORK&lt;/span&gt;&lt;/code&gt;, and now it has become a cornerstone of my
development workflow.&lt;/p&gt;
&lt;h2&gt;What is Stacked Git?&lt;/h2&gt;
&lt;p&gt;Before going any further, it is probably a good idea to take a moment and
present Stacked Git. The website introduces the tool as follows:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Stacked Git, &lt;em&gt;StGit&lt;/em&gt; for short, is an application for managing Git
commits as a stack of patches.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are a few things to unpack here. First and as its name suggests, Stacked
Git is a tool built on top of Git&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;My main takeaway from my Pijul adventure is connected to this. Git
is not limited to the &lt;code class=&quot;hljs&quot;&gt;git&lt;/code&gt; binary. Git comes with a collection of powerful
forges, nice editor plugins, and years of good practices.&lt;/span&gt;
&lt;span class=&quot;footnote-p&quot;&gt;To this day, it’s neither the bugs nor the breaking changes that made me
quite Pijul. Those were expected. What I naively did not anticipate is the
dry feeling that Pijul was just the &lt;code class=&quot;hljs&quot;&gt;pijul&lt;/code&gt; binary, which left me with a
lot of tasks to do manually. &lt;/span&gt;
&lt;/span&gt;. It is &lt;em&gt;not&lt;/em&gt; a brand new VCS, and as
a consequence you keep using all your existing tools and plugins&lt;label for=&quot;fn2&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn2&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I am looking at you, Magit. &lt;/span&gt;
&lt;/span&gt;.
Secondly, Stacked Git helps you curate your Git history, by turning your
commits into patches, and your branches into stacks of patches. This speaks to
me, maybe because I have been fascinated by email-based workflows for quite
some time.&lt;/p&gt;
&lt;p&gt;To me, the two core features of Stacked Git are (1) allowing you to
name your commits, and (2) to navigate among them.
Together, they create a wonderful companion to help you keep your
history clean.&lt;/p&gt;
&lt;h2&gt;My Subset of Stacked Git&lt;/h2&gt;
&lt;p&gt;I do not want this article to be a Stacked Git tutorial.
Fortunately, I don’t really use the tool at its full potential.
I only care about a relatively small subset of commands I feel
comfortable with and use daily.&lt;/p&gt;
&lt;p&gt;First, to decide which commits are part of my “stack of patches,” I
can count of these commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;hljs&quot;&gt;stg new NAME&lt;/code&gt; creates an empty commit, and gives it the name
&lt;code class=&quot;hljs&quot;&gt;NAME&lt;/code&gt;.
Having a way to identify a patch with a meaningful name that is
resistant to rebase and amend is very nice.
These are two properties commit hashes do not have.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;hljs&quot;&gt;stg uncommit NAME&lt;/code&gt; names the most recent commit under my
stack with &lt;code class=&quot;hljs&quot;&gt;NAME&lt;/code&gt; and integrates it into it. I do this when I am
tasked to work on a merge request made by a colleague, for
instance.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;hljs&quot;&gt;stg commit&lt;/code&gt; removes from my stack its last patch. I do this when
said commit has been merged into &lt;code class=&quot;hljs&quot;&gt;master&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once my stack of patches is ready, the fun begins.&lt;/p&gt;
&lt;p&gt;At a given time, a patch can either be (1) applied, (2) unapplied, or (3)
hidden. On the one hand, if a patch is applied it is part of the Git history.
On the other hand, unapplying a patch means removing it from the working branch
(but not from the stack of patches of Stacked Git). If a patch becomes
irrelevant, but you don’t want to remove it entirely because it can become
handy later, you can hide it. A hidden patch sits beside the stack of patches,
and can be reintegrated if need be.&lt;/p&gt;
&lt;p&gt;Analogous to &lt;code class=&quot;hljs&quot;&gt;git log&lt;/code&gt; ---which allows you to visualize your Git history---,
&lt;code class=&quot;hljs&quot;&gt;stg series&lt;/code&gt; gives you a view of the state of your stack of patches. Patches
prefixed with &lt;code class=&quot;hljs&quot;&gt;+&lt;/code&gt; (or &lt;code class=&quot;hljs&quot;&gt;&amp;gt;&lt;/code&gt;) are applied, while &lt;code class=&quot;hljs&quot;&gt;-&lt;/code&gt; means the patch is unapplied.&lt;/p&gt;
&lt;p&gt;Then,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;hljs&quot;&gt;stg pop&lt;/code&gt; unapplies the patch on top of the list of applied
patches.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;hljs&quot;&gt;stg push&lt;/code&gt; applies the patch on the bottom of the list of unapplied
patches.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;hljs&quot;&gt;stg goto NAME&lt;/code&gt; unapplies or applies the necessary patches so that
&lt;code class=&quot;hljs&quot;&gt;NAME&lt;/code&gt; becomes the top patch of the list of applied patches.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both &lt;code class=&quot;hljs&quot;&gt;HEAD&lt;/code&gt; and the work tree are updated accordingly.&lt;/p&gt;
&lt;p&gt;In addition, &lt;code class=&quot;hljs&quot;&gt;stg sink&lt;/code&gt; and &lt;code class=&quot;hljs&quot;&gt;stg float&lt;/code&gt; allow reorganizing your
stack of patches, moving patches around.
Basically, they are like &lt;code class=&quot;hljs&quot;&gt;git rebase -i&lt;/code&gt;, but without having to use
&lt;code class=&quot;hljs&quot;&gt;$EDITOR&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Modifying patches is done with &lt;code class=&quot;hljs&quot;&gt;stg refresh&lt;/code&gt;.
It’s akin to &lt;code class=&quot;hljs&quot;&gt;git commit --amend&lt;/code&gt;, except it is more powerful because
you can modify any applied patches with the &lt;code class=&quot;hljs&quot;&gt;-p&lt;/code&gt; option.
I’d always encourage you to &lt;code class=&quot;hljs&quot;&gt;stg goto&lt;/code&gt; first, because &lt;code class=&quot;hljs&quot;&gt;stg refresh -p&lt;/code&gt; remains unfortunately error-prone (nothing prevents you from targeting
the wrong patch).
But when used carefully, it can be very handy.&lt;/p&gt;
&lt;p&gt;Finally, &lt;code class=&quot;hljs&quot;&gt;stg rebase REF&lt;/code&gt; moves your stack of patches on top of &lt;code class=&quot;hljs&quot;&gt;REF&lt;/code&gt;&lt;label for=&quot;fn3&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn3&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Stacked Git is supposedly able to detect, during a rebase, which of
your patches have been applied to your target branch. I’d rather use &lt;code class=&quot;hljs language-bash&quot;&gt;stg uncommit&lt;/code&gt; before doing the rebase, though. &lt;/span&gt;
&lt;/span&gt;.
It is akin to &lt;code class=&quot;hljs&quot;&gt;git rebase --onto&lt;/code&gt;, but more straightforward. What happens is
Stacked Git pop all the patches of my stack, reset the &lt;code class=&quot;hljs&quot;&gt;HEAD&lt;/code&gt; of the current
branch to &lt;code class=&quot;hljs&quot;&gt;REF&lt;/code&gt;, and tries applying the patches one by one In case of
conflicts, the process stop, and I am left with an empty patch, and a dirty
work tree with conflicts to solve. The hidden gem is that, contrary to &lt;code class=&quot;hljs&quot;&gt;git rebase&lt;/code&gt;, the repository is not “in the middle of a rebase.”&lt;/p&gt;
&lt;p&gt;Suppose there are many conflicting patches still waiting in my stack of patches,
and an urgent task I need to take care of first. I can just leave them here. I
can switch to another branch, and when I come back, I get my patches back. I
call this feature “incremental rebases.”&lt;/p&gt;
&lt;p&gt;And that is basically it. In a nutshell, Stacked Git equips commits with the
same features as branches.&lt;/p&gt;
&lt;h2&gt;My Stacked Git Workflow&lt;/h2&gt;
&lt;p&gt;As mentioned in the introduction of this article, Stacked Git has become a
cornerstone of my workflow. I’ve been asked a few times what this workflow is,
and why Magit is not enough&lt;label for=&quot;fn4&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn4&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;It’s always about Magit. ;) &lt;/span&gt;
&lt;/span&gt;. So let’s try to do that. But first, a
warning. Yes, because Stacked Git is only a wrapper above Git, everything I
will explain can be achieved using Git alone, especially if you are a Magit
wizard.&lt;/p&gt;
&lt;p&gt;Stacked Git makes just everything so more convenient to me.&lt;/p&gt;
&lt;h3&gt;Planning My Commits Ahead Of Time&lt;/h3&gt;
&lt;p&gt;I’ve been introduced to Git with a pretty simple workflow: I am
supposed to start working on a feature, and once it’s ready, I
can commit, and move on to the next task on my to-do list.&lt;/p&gt;
&lt;p&gt;To me, this approach is backward.
It makes you set your intent after the fact.
With Stacked Git, I often try to plan my final history /before
writing the very first line of code/.
Using &lt;code class=&quot;hljs&quot;&gt;stack new&lt;/code&gt;, I create my patches, and take the time to write
their description.
It helps me visualize where I want to go.
Then, I use &lt;code class=&quot;hljs&quot;&gt;stack goto&lt;/code&gt; to go back to the beginning of my stack,
and start working.&lt;/p&gt;
&lt;p&gt;It is not, and cannot be, an exact science. I often have to refine
them as my work progresses.
Yet, I think my Git history is cleaner, more focused, since I have
started this exercise.&lt;/p&gt;
&lt;h3&gt;Getting My Fixup Commits Right&lt;/h3&gt;
&lt;p&gt;Reviews are a fundamental aspect of a software developer job.
At &lt;code class=&quot;hljs&quot;&gt;$WORK&lt;/code&gt;, we use Gitlab and their merge requests workflow,
which I find very annoying, because it does not provide meaningful
ways to compare two versions of your submission&lt;label for=&quot;fn5&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn5&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;There is a notion of “versions” in Gitlab, but its ergonomics fall
short of my expectations for such a tool. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;What we end up doing is creating “fixup commits,” and we push them
to Gitlab so that reviewers can easily verify that their feedback
has correctly been taken into account.&lt;/p&gt;
&lt;p&gt;A fixup commit is a commit that will eventually be squashed into
another.
You can understand it as a delayed &lt;code class=&quot;hljs&quot;&gt;git commit --amend&lt;/code&gt;.
Git has some built-in features to manipulate them.
You create them with &lt;code class=&quot;hljs&quot;&gt;git commit --fixup=&amp;lt;HASH&amp;gt;&lt;/code&gt;, and they are
interpreted in a specific manner by &lt;code class=&quot;hljs&quot;&gt;git rebase -i&lt;/code&gt;.
But they have always felt to me like a sordid hack.
It is way too easy to create a fixup commit that targets the wrong
commit, and you can end up with strange conflicts when you finally
squash them.
That being said, if used carefully, they are a powerful tool to
keep a Git history clean.&lt;/p&gt;
&lt;p&gt;I am not sure we are using them carefully, though.&lt;/p&gt;
&lt;p&gt;Some reviews can be excruciating, with dozens of comments to
address, and theoretically as many fixup commits to create.
Then you push all of them on Gitlab, and days later, after the
green light from the reviewer, you get to call &lt;code class=&quot;hljs&quot;&gt;git rebase&lt;/code&gt;
and discover your history is broken, you have tones of conflicts
to fix, and you’re good for a long afternoon of untangling.&lt;/p&gt;
&lt;p&gt;The main reason behind this mess is that you end up fixing a commit
from the &lt;code class=&quot;hljs&quot;&gt;HEAD&lt;/code&gt; of your working branch, not the commit itself.
But with Stacked Git, things are different.
With &lt;code class=&quot;hljs&quot;&gt;stg goto&lt;/code&gt;, I put my working tree in the best state possible
to fix a commit: the commit itself.
I can use &lt;code class=&quot;hljs&quot;&gt;stg new&lt;/code&gt; to create a fixup commit, with a meaningful
name.
Then, I am forced to deal with the potential conflicts it brings
when I call &lt;code class=&quot;hljs&quot;&gt;stg push&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Once my reviewer is happy with my work, I can call &lt;code class=&quot;hljs&quot;&gt;stg squash&lt;/code&gt;.
It is less automated than &lt;code class=&quot;hljs&quot;&gt;git rebase -i&lt;/code&gt;, but the comfort I gained
during the development is worth this little annoyance.&lt;/p&gt;
&lt;h3&gt;Managing Stacked Merge Requests&lt;/h3&gt;
&lt;p&gt;At &lt;code class=&quot;hljs&quot;&gt;$WORK&lt;/code&gt;, we are trying to change how we deliver new features to
our &lt;code class=&quot;hljs&quot;&gt;master&lt;/code&gt; branch.
More precisely, we want to merge smaller contributions more
frequently.
We have had our fair share of large and complex merge requests that
were a nightmare to review in the past, and it’s really not a fun
position to be put in.&lt;/p&gt;
&lt;p&gt;For a few months, I have been involved in a project wherein we
decided /not/ to fall in the same trap again.
We agreed on a “planning of merge requests” and started working.
The first merge request was soon opened.
We’ve nominated an “owner” to take care of the review, and the rest
of the team carried on.
Before the first merge request was merged, the second one was
declared ready, and another owner was appointed.
Then, the owner of the first merge request had a baby, and yours
truly ended up having to manage two interdependent merge requests.&lt;/p&gt;
&lt;p&gt;It turns out Stacked Git is a wonderful tool to help me keep this
under control.&lt;/p&gt;
&lt;p&gt;I only have one branch, and I use the same workflow to deal with
feedback, even if they are coming from more than one merge
request.
To remember the structure of everything, I just prefix the name of
my patches with a merge request nickname.
So my stack will look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;+ mr1-base
+ mr1-tests
+ mr1-doc
&amp;gt; mr2-command
- mr2-tests
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A reviewer leaves a hard-truth comment that requires a significant rework of
the oldest merge request? &lt;code class=&quot;hljs&quot;&gt;stg goto&lt;/code&gt; reverts my work tree in the appropriate
state, and &lt;code class=&quot;hljs&quot;&gt;stg push&lt;/code&gt; allows me to deal with conflicts one patch at a time. If
I need to spend more time on the oldest merge request at some point, I can
continue my work, knowing the patches related to the newest one are awaiting in
my stack.&lt;/p&gt;
&lt;p&gt;The most annoying part is when the time comes to push everything. I need to
&lt;code class=&quot;hljs&quot;&gt;stg goto&lt;/code&gt; at the last patch of each merge request, and &lt;code class=&quot;hljs&quot;&gt;git push HEAD:the-branch&lt;/code&gt;. It’s not horrible. But I will probably try to automate it at
some point.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Overall, I am really thankful to Stacked Git’s authors! Thank you! You are
making my interactions with Git fun and carefree. You provide me some of the
convenience of patch-based VCS like &lt;a href=&quot;http://darcs.net&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;Darcs&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; and
&lt;a href=&quot;https://pijul.org&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;Pijul&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, but without sacrificing the power of Git.&lt;/p&gt;
&lt;p&gt;I encourage anyone to at least give it a try, and I really hope I
will be able to contribute back to Stacked Git in the near future.&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>Implementing an Echo Server in Coq with coqffi.1.0.0</title>
      <link>https://soap.coffee/~lthms/posts/CoqffiEcho.html</link>
      <guid>https://soap.coffee/~lthms/posts/CoqffiEcho.html</guid>
      <pubDate>December 10, 2020</pubDate>
      <description>
        
        &lt;h1&gt;Implementing an Echo Server in Coq with &lt;code class=&quot;hljs&quot;&gt;coqffi.1.0.0&lt;/code&gt;&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/coq.html&quot; class=&quot;tag hover-coral&quot; marked=&quot;&quot;&gt;coq&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/ocaml.html&quot; class=&quot;tag hover-peach&quot; marked=&quot;&quot;&gt;ocaml&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/coqffi.html&quot; class=&quot;tag hover-lemon&quot; marked=&quot;&quot;&gt;coqffi&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;In this article, we will demonstrate how &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; can be used to
implement an echo server, &lt;em&gt;i.e.&lt;/em&gt;, a TCP server which sends back any
input it receives from its clients.  In addition to &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt;, you will need to
install &lt;code class=&quot;hljs&quot;&gt;coq-simple-io&lt;/code&gt;.  The latter is available in the &lt;a href=&quot;https://github.com/coq/opam-coq-archive&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;released&lt;/code&gt; repository
of the Opam Coq Archive&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;opam install coq-coqffi coq-simple-io
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Besides,  you can download &lt;a href=&quot;/~lthms/files/coqffi-tutorial.tar.gz&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;the source tree presented in this
article&lt;/a&gt; if you want to try to read the source
directly, or modify it to your taste.&lt;/p&gt;
&lt;h2&gt;Project Layout&lt;/h2&gt;
&lt;p&gt;Before diving too much into the implementation of our echo server, we
first give an overview of the resulting project’s layout. Since we aim
at implementing a program, we draw our inspiration from the idiomatic
way of organizing a OCaml project.&lt;/p&gt;
&lt;p&gt;We have three directories at the root of the project.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code class=&quot;hljs&quot;&gt;ffi/&lt;/code&gt; contains the low-level OCaml code:&lt;/strong&gt;
It provides an OCaml library (&lt;code class=&quot;hljs&quot;&gt;ffi&lt;/code&gt;), and a Coq theory (&lt;code class=&quot;hljs language-coq&quot;&gt;FFI&lt;/code&gt;) which
gathers the FFI modules generated by &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code class=&quot;hljs&quot;&gt;src/&lt;/code&gt; contains the Coq implementation of our echo server:&lt;/strong&gt; It provides a
Coq theory (&lt;code class=&quot;hljs language-coq&quot;&gt;Echo&lt;/code&gt;) which depends on the &lt;code class=&quot;hljs language-coq&quot;&gt;FFI&lt;/code&gt; theory the
&lt;code class=&quot;hljs language-coq&quot;&gt;SimpleIO&lt;/code&gt; theory of &lt;code class=&quot;hljs&quot;&gt;coq-simple~io&lt;/code&gt;. This theory provides the
implementation of our echo server in Coq.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code class=&quot;hljs&quot;&gt;bin/&lt;/code&gt; contains the pieces of code to get an executable program:&lt;/strong&gt; It
contains a Coq module (&lt;code class=&quot;hljs&quot;&gt;echo.v&lt;/code&gt;) which configures and uses the extraction
mechanism to generate an OCaml module (&lt;code class=&quot;hljs&quot;&gt;echo.ml&lt;/code&gt;). This OCaml module can be
compiled to get an executable program.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note that we could have decided to only have one Coq theory. We could
also have added a fourth directory (&lt;code class=&quot;hljs&quot;&gt;theories/&lt;/code&gt;) for formal
verification specific code, but this is out of the scope of this
tutorial.&lt;/p&gt;
&lt;p&gt;Overall, we use &lt;code class=&quot;hljs&quot;&gt;dune&lt;/code&gt; to compile and compose the different parts of
the echo server. &lt;code class=&quot;hljs&quot;&gt;dune&lt;/code&gt; has a native —yet unstable at the time of
writing— support for building Coq projects, with very convenient
stanzas like &lt;code class=&quot;hljs&quot;&gt;coq.theory&lt;/code&gt; and &lt;code class=&quot;hljs&quot;&gt;coq.extraction&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The following graph summarizes the dependencies between each component
(plain arrows symbolize software dependencies).&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/~lthms/img/echo-deps.svg&quot; alt=&quot;The echo server dependy graph&quot;&gt;&lt;figcaption&gt;&lt;p&gt;The echo server dependency graph. Dashed boxes are generated.&lt;/p&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;We enable Coq-related stanza with &lt;code class=&quot;hljs language-lisp&quot;&gt;(&lt;span class=&quot;hljs-name&quot;&gt;using&lt;/span&gt; coq &lt;span class=&quot;hljs-number&quot;&gt;0.2&lt;/span&gt;)&lt;/code&gt; in the
&lt;code class=&quot;hljs language-dune&quot;&gt;dune-project&lt;/code&gt;. file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-lisp&quot;&gt;(&lt;span class=&quot;hljs-name&quot;&gt;lang&lt;/span&gt; dune &lt;span class=&quot;hljs-number&quot;&gt;2.7&lt;/span&gt;)
(&lt;span class=&quot;hljs-name&quot;&gt;using&lt;/span&gt; coq &lt;span class=&quot;hljs-number&quot;&gt;0.2&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The rest of this tutorial proceeds by diving into each directory.&lt;/p&gt;
&lt;h2&gt;FFI Bindings&lt;/h2&gt;
&lt;p&gt;Our objective is to implement an echo server, &lt;em&gt;i.e.&lt;/em&gt;, a server which
(1) accepts incoming connections, and (2) sends back any incoming
messages. We will consider two classes of effects. One is related to
creating and manipulating TCP sockets. The other is dedicated to
process management, more precisely to be able to fork when receiving
incoming connections.&lt;/p&gt;
&lt;p&gt;Therefore, the &lt;code class=&quot;hljs&quot;&gt;ffi&lt;/code&gt; library will provide two modules. Likewise, the
&lt;code class=&quot;hljs language-coq&quot;&gt;FFI&lt;/code&gt; theory will provide two analogous modules generated by &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In the &lt;code class=&quot;hljs&quot;&gt;ffi/&lt;/code&gt; directory, we add the following stanza to the &lt;code class=&quot;hljs&quot;&gt;dune&lt;/code&gt; file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-lisp&quot;&gt;(&lt;span class=&quot;hljs-name&quot;&gt;library&lt;/span&gt;
  (&lt;span class=&quot;hljs-name&quot;&gt;name&lt;/span&gt; ffi)
  (&lt;span class=&quot;hljs-name&quot;&gt;libraries&lt;/span&gt; unix))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code class=&quot;hljs&quot;&gt;dune&lt;/code&gt; will look for any &lt;code class=&quot;hljs&quot;&gt;.ml&lt;/code&gt; and &lt;code class=&quot;hljs&quot;&gt;.mli&lt;/code&gt; files within the directory and will
consider they belong to the &lt;code class=&quot;hljs&quot;&gt;ffi&lt;/code&gt; library. We use the
&lt;a href=&quot;https://caml.inria.fr/pub/docs/manual-ocaml/libref/Unix.html&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;unix&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; library
to implement the features we are looking for.&lt;/p&gt;
&lt;p&gt;Then, we add the following stanza to the &lt;code class=&quot;hljs&quot;&gt;dune&lt;/code&gt; file of the &lt;code class=&quot;hljs&quot;&gt;ffi/&lt;/code&gt;
directory.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-lisp&quot;&gt;(&lt;span class=&quot;hljs-name&quot;&gt;coq&lt;/span&gt;.theory
  (&lt;span class=&quot;hljs-name&quot;&gt;name&lt;/span&gt; FFI))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This tells &lt;code class=&quot;hljs&quot;&gt;dune&lt;/code&gt; to look for &lt;code class=&quot;hljs&quot;&gt;.v&lt;/code&gt; file within the &lt;code class=&quot;hljs&quot;&gt;ffi/&lt;/code&gt; directory,
in order to build them with Coq.  A nice feature of &lt;code class=&quot;hljs&quot;&gt;dune&lt;/code&gt; is that if we
automatically generate Coq files, they will be automatically “attached” to this
theory.&lt;/p&gt;
&lt;h3&gt;Sockets&lt;/h3&gt;
&lt;p&gt;Sockets are boring. The following OCaml module interface provides the
necessary type and functions to manipulate them.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; socket_descr

&lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; open_socket : &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; -&amp;gt; socket_descr
&lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; listen : socket_descr -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;unit&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; recv : socket_descr -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; send : socket_descr -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; accept_connection : socket_descr -&amp;gt; socket_descr
&lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; close_socket : socket_descr -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;unit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our focus is how to write the interface modules for &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt;. Since the object
of this tutorial is not the implementation of an echo server in itself, the
implementation details of the &lt;code class=&quot;hljs&quot;&gt;ffi&lt;/code&gt; library will not be discussed, but is
provided at the end of this article.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;hljs&quot;&gt;dune&lt;/code&gt; generates &lt;code class=&quot;hljs&quot;&gt;.cmi&lt;/code&gt; files for the &lt;code class=&quot;hljs&quot;&gt;.mli&lt;/code&gt; files of our library, and
provides the necessary bits to easily locate them. Besides, the
&lt;code class=&quot;hljs&quot;&gt;action&lt;/code&gt; stanza can be used here to tell to &lt;code class=&quot;hljs&quot;&gt;dune&lt;/code&gt; how to generate the
module &lt;code class=&quot;hljs&quot;&gt;Socket.v&lt;/code&gt; from &lt;code class=&quot;hljs&quot;&gt;file.cmi&lt;/code&gt;. We add the following entry to
&lt;code class=&quot;hljs&quot;&gt;ffi/dune&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-lisp&quot;&gt;(&lt;span class=&quot;hljs-name&quot;&gt;rule&lt;/span&gt;
  (&lt;span class=&quot;hljs-name&quot;&gt;target&lt;/span&gt; Socket.v)
  (&lt;span class=&quot;hljs-name&quot;&gt;action&lt;/span&gt; (&lt;span class=&quot;hljs-name&quot;&gt;run&lt;/span&gt; coqffi %{cmi&lt;span class=&quot;hljs-symbol&quot;&gt;:socket&lt;/span&gt;} -o %{target})))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We call &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; without any feature-related command-line argument,
which means only the &lt;code class=&quot;hljs&quot;&gt;simple-io&lt;/code&gt; feature is enabled. As a consequence,
the &lt;code class=&quot;hljs&quot;&gt;socket_descr&lt;/code&gt; type is axiomatized in Coq, and in addition to a
&lt;code class=&quot;hljs&quot;&gt;MonadSocket&lt;/code&gt; monad, &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; will generate an instance for this monad
for the &lt;code class=&quot;hljs&quot;&gt;IO&lt;/code&gt; monad of &lt;code class=&quot;hljs&quot;&gt;coq-simple-io&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The stanza generates the following Coq module.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;(* This file has been generated by coqffi. *)&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Implicit&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Arguments&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;Unset&lt;/span&gt; Strict &lt;span class=&quot;hljs-keyword&quot;&gt;Implicit&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;Set&lt;/span&gt; Contextual &lt;span class=&quot;hljs-keyword&quot;&gt;Implicit&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;Generalizable&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;All&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Variables&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;Close&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Scope&lt;/span&gt; nat_scope.

&lt;span class=&quot;hljs-keyword&quot;&gt;From&lt;/span&gt; CoqFFI &lt;span class=&quot;hljs-keyword&quot;&gt;Require&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Export&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Extraction&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;From&lt;/span&gt; SimpleIO &lt;span class=&quot;hljs-keyword&quot;&gt;Require&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Import&lt;/span&gt; IO_Monad.

&lt;span class=&quot;hljs-keyword&quot;&gt;Axiom&lt;/span&gt; socket_descr : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;.

&lt;span class=&quot;hljs-keyword&quot;&gt;Extract&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Constant&lt;/span&gt; socket_descr =&amp;gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;Ffi.Socket.socket_descr&quot;&lt;/span&gt;.

&lt;span class=&quot;hljs-comment&quot;&gt;(** * Impure Primitives *)&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;(** ** Monad Definition *)&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;Class&lt;/span&gt; MonadSocket (m : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;) : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt; :=
  { open_socket : string -&amp;gt; i63 -&amp;gt; m socket_descr
  ; listen : socket_descr -&amp;gt; m unit
  ; recv : socket_descr -&amp;gt; m string
  ; send : socket_descr -&amp;gt; string -&amp;gt; m i63
  ; accept_connection : socket_descr -&amp;gt; m socket_descr
  ; close_socket : socket_descr -&amp;gt; m unit
  }.

&lt;span class=&quot;hljs-comment&quot;&gt;(** ** [IO] Instance *)&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;Axiom&lt;/span&gt; io_open_socket : string -&amp;gt; i63 -&amp;gt; IO socket_descr.
&lt;span class=&quot;hljs-keyword&quot;&gt;Axiom&lt;/span&gt; io_listen : socket_descr -&amp;gt; IO unit.
&lt;span class=&quot;hljs-keyword&quot;&gt;Axiom&lt;/span&gt; io_recv : socket_descr -&amp;gt; IO string.
&lt;span class=&quot;hljs-keyword&quot;&gt;Axiom&lt;/span&gt; io_send : socket_descr -&amp;gt; string -&amp;gt; IO i63.
&lt;span class=&quot;hljs-keyword&quot;&gt;Axiom&lt;/span&gt; io_accept_connection : socket_descr -&amp;gt; IO socket_descr.
&lt;span class=&quot;hljs-keyword&quot;&gt;Axiom&lt;/span&gt; io_close_socket : socket_descr -&amp;gt; IO unit.

&lt;span class=&quot;hljs-keyword&quot;&gt;Extract&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Constant&lt;/span&gt; io_open_socket
  =&amp;gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;(fun x1 x2 k__ -&amp;gt; k__ ((Ffi.Socket.open_socket x1 x2)))&quot;&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;Extract&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Constant&lt;/span&gt; io_listen =&amp;gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;(fun x1 k__ -&amp;gt; k__ ((Ffi.Socket.listen x1)))&quot;&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;Extract&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Constant&lt;/span&gt; io_recv =&amp;gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;(fun x1 k__ -&amp;gt; k__ ((Ffi.Socket.recv x1)))&quot;&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;Extract&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Constant&lt;/span&gt; io_send
  =&amp;gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;(fun x1 x2 k__ -&amp;gt; k__ ((Ffi.Socket.send x1 x2)))&quot;&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;Extract&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Constant&lt;/span&gt; io_accept_connection
  =&amp;gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;(fun x1 k__ -&amp;gt; k__ ((Ffi.Socket.accept_connection x1)))&quot;&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;Extract&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Constant&lt;/span&gt; io_close_socket
  =&amp;gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;(fun x1 k__ -&amp;gt; k__ ((Ffi.Socket.close_socket x1)))&quot;&lt;/span&gt;.

&lt;span class=&quot;hljs-keyword&quot;&gt;Instance&lt;/span&gt; IO_MonadSocket : MonadSocket IO :=
  { open_socket := io_open_socket
  ; listen := io_listen
  ; recv := io_recv
  ; send := io_send
  ; accept_connection := io_accept_connection
  ; close_socket := io_close_socket
  }.

&lt;span class=&quot;hljs-comment&quot;&gt;(* The generated file ends here. *)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Process Management&lt;/h3&gt;
&lt;p&gt;In order to avoid a client to block the server by connecting to it
without sending anything, we can fork a new process for each client.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; identity = &lt;span class=&quot;hljs-type&quot;&gt;Parent&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; | &lt;span class=&quot;hljs-type&quot;&gt;Child&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; fork : &lt;span class=&quot;hljs-built_in&quot;&gt;unit&lt;/span&gt; -&amp;gt; identity
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This time, the &lt;code class=&quot;hljs&quot;&gt;proc.mli&lt;/code&gt; module interface introduces a transparent
type, /i.e./, it also provides its definition. This is a good use case
for the &lt;code class=&quot;hljs&quot;&gt;transparent-types&lt;/code&gt; feature of &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt;. In the stanza for
generating &lt;code class=&quot;hljs&quot;&gt;Proc.v&lt;/code&gt;, we enable it with the &lt;code class=&quot;hljs&quot;&gt;-ftransparent-types&lt;/code&gt;
command-line argument, like this.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-lisp&quot;&gt;(&lt;span class=&quot;hljs-name&quot;&gt;rule&lt;/span&gt;
  (&lt;span class=&quot;hljs-name&quot;&gt;target&lt;/span&gt; Proc.v)
  (&lt;span class=&quot;hljs-name&quot;&gt;action&lt;/span&gt; (&lt;span class=&quot;hljs-name&quot;&gt;run&lt;/span&gt; coqffi -ftransparent-types %{cmi&lt;span class=&quot;hljs-symbol&quot;&gt;:proc&lt;/span&gt;} -o %{target})))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which generates the following Coq module.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;(* This file has been generated by coqffi. *)&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Implicit&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Arguments&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;Unset&lt;/span&gt; Strict &lt;span class=&quot;hljs-keyword&quot;&gt;Implicit&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;Set&lt;/span&gt; Contextual &lt;span class=&quot;hljs-keyword&quot;&gt;Implicit&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;Generalizable&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;All&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Variables&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;Close&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Scope&lt;/span&gt; nat_scope.

&lt;span class=&quot;hljs-keyword&quot;&gt;From&lt;/span&gt; CoqFFI &lt;span class=&quot;hljs-keyword&quot;&gt;Require&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Export&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Extraction&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;From&lt;/span&gt; SimpleIO &lt;span class=&quot;hljs-keyword&quot;&gt;Require&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Import&lt;/span&gt; IO_Monad.

&lt;span class=&quot;hljs-keyword&quot;&gt;Inductive&lt;/span&gt; identity : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt; :=
| &lt;span class=&quot;hljs-type&quot;&gt;Parent&lt;/span&gt; (x0 : i63) : identity
| &lt;span class=&quot;hljs-type&quot;&gt;Child&lt;/span&gt; : identity.

&lt;span class=&quot;hljs-keyword&quot;&gt;Extract&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Inductive&lt;/span&gt; identity =&amp;gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;Ffi.Proc.identity&quot;&lt;/span&gt;
  [ &lt;span class=&quot;hljs-string&quot;&gt;&quot;Ffi.Proc.Parent&quot;&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;Ffi.Proc.Child&quot;&lt;/span&gt; ].

&lt;span class=&quot;hljs-comment&quot;&gt;(** * Impure Primitives *)&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;(** ** Monad Definition *)&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;Class&lt;/span&gt; MonadProc (m : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;) : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt; := { fork : unit -&amp;gt; m identity
                                             }.

&lt;span class=&quot;hljs-comment&quot;&gt;(** ** [IO] Instance *)&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;Axiom&lt;/span&gt; io_fork : unit -&amp;gt; IO identity.

&lt;span class=&quot;hljs-keyword&quot;&gt;Extract&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Constant&lt;/span&gt; io_fork =&amp;gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;(fun x1 k__ -&amp;gt; k__ ((Ffi.Proc.fork x1)))&quot;&lt;/span&gt;.

&lt;span class=&quot;hljs-keyword&quot;&gt;Instance&lt;/span&gt; IO_MonadProc : MonadProc IO := { fork := io_fork
                                        }.

&lt;span class=&quot;hljs-comment&quot;&gt;(* The generated file ends here. *)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We now have everything we need to implement an echo server in Coq.&lt;/p&gt;
&lt;h2&gt;Implementing an Echo Server&lt;/h2&gt;
&lt;p&gt;Our implementation will be part of a dedicated Coq theory, called &lt;code class=&quot;hljs language-coq&quot;&gt;Echo&lt;/code&gt;.
This is done easily a &lt;code class=&quot;hljs language-coq&quot;&gt;dune&lt;/code&gt; file in the &lt;code class=&quot;hljs&quot;&gt;src/&lt;/code&gt; directory, with the
following content.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-lisp&quot;&gt;(&lt;span class=&quot;hljs-name&quot;&gt;coq&lt;/span&gt;.theory
  (&lt;span class=&quot;hljs-name&quot;&gt;name&lt;/span&gt; Echo)
  (&lt;span class=&quot;hljs-name&quot;&gt;theories&lt;/span&gt; FFI))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the rest of this section, we will discuss the content of the unique
module of this theory. Hopefully, readers familiar with programming
impurity by means of monads will not find anything particularly
surprising here.&lt;/p&gt;
&lt;p&gt;Let us start with the inevitable sequence of import commands. We use
the &lt;code class=&quot;hljs language-coq&quot;&gt;Monad&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;MonadFix&lt;/code&gt; typeclasses of &lt;code class=&quot;hljs language-coq&quot;&gt;ExtLib&lt;/code&gt;, and our
FFI modules from the &lt;code class=&quot;hljs language-coq&quot;&gt;FFI&lt;/code&gt; theory we have previously defined.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;From&lt;/span&gt; ExtLib &lt;span class=&quot;hljs-keyword&quot;&gt;Require&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Import&lt;/span&gt; Monad MonadFix.
&lt;span class=&quot;hljs-keyword&quot;&gt;From&lt;/span&gt; FFI &lt;span class=&quot;hljs-keyword&quot;&gt;Require&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Import&lt;/span&gt; Proc Socket.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Letting Coq guess the type of unintroduced variables using the &lt;code class=&quot;hljs&quot;&gt;`&lt;/code&gt;
annotation (&lt;em&gt;e.g.&lt;/em&gt;, in presence of&lt;code class=&quot;hljs language-coq&quot;&gt; `{Monad m}&lt;/code&gt;, Coq understands &lt;code class=&quot;hljs&quot;&gt;m&lt;/code&gt;
is of type &lt;code class=&quot;hljs&quot;&gt;Type -&amp;gt; Type&lt;/code&gt;) is always nice, so we enable it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Generalizable&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;All&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Variables&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We enable the monad notation provided by &lt;code class=&quot;hljs&quot;&gt;ExtLib&lt;/code&gt;. In this article, we
prefer the &lt;code class=&quot;hljs&quot;&gt;let*&lt;/code&gt; notation (as recently introduced by OCaml) over the
&lt;code class=&quot;hljs&quot;&gt;&amp;lt;-&lt;/code&gt; notation of Haskell, but both are available.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Import&lt;/span&gt; MonadLetNotation.
&lt;span class=&quot;hljs-keyword&quot;&gt;Open&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Scope&lt;/span&gt; monad_scope.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we define a notation to be able to define local, monadic
recursive functions using the &lt;code class=&quot;hljs&quot;&gt;mfix&lt;/code&gt; combinator of the &lt;code class=&quot;hljs&quot;&gt;MonadFix&lt;/code&gt;
typeclass.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Notation&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;&apos;let_rec*&apos; f x &apos;:`&apos; p &apos;in&apos; q&quot;&lt;/span&gt; :`
  (&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; f :` mfix (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; f x `&amp;gt; p) &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt; q)
    (&lt;span class=&quot;hljs-built_in&quot;&gt;at&lt;/span&gt; level &lt;span class=&quot;hljs-number&quot;&gt;61&lt;/span&gt;, x &lt;span class=&quot;hljs-built_in&quot;&gt;pattern&lt;/span&gt;, f name, q &lt;span class=&quot;hljs-built_in&quot;&gt;at&lt;/span&gt; next level, &lt;span class=&quot;hljs-built_in&quot;&gt;right&lt;/span&gt; associativity).
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that &lt;code class=&quot;hljs&quot;&gt;mfix&lt;/code&gt; does /not/ check whether or not the defined function
will terminate (contrary to the &lt;code class=&quot;hljs&quot;&gt;fix&lt;/code&gt; keyword of Coq). This is
fortunate because in our case, we do not want our echo server to
converge, but rather to accept an infinite number of connections.&lt;/p&gt;
&lt;p&gt;We can demonstrate how this notation can be leveraged by defining a
generic TCP server, parameterized by a handler to deal with incoming
connections.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; tcp_srv `{Monad m, MonadFix m, MonadProc m, MonadSocket m}
    (handler : socket_descr -&amp;gt; m unit)
  : m unit :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt;* srv := open_socket &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8888&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt;
  listen srv;;

  let_rec* tcp_aux &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; :=
    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt;* client := accept_connection srv &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt;* res := fork tt &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; res &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
    | &lt;span class=&quot;hljs-type&quot;&gt;Parent&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; =&amp;gt; close_socket client &amp;gt;&amp;gt;= tcp_aux
    | &lt;span class=&quot;hljs-type&quot;&gt;Child&lt;/span&gt; =&amp;gt;  handler client
    &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt;

  tcp_aux tt.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The handler for the echo server is straightforward: it just reads
incoming bytes from the socket, sends it back, and closes the socket.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; echo_handler `{Monad m, MonadSocket m} (sock : socket_descr)
  : m unit :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt;* msg := recv sock &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt;
  send sock msg;;
  close_socket sock.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Composing our generic TCP server with our echo handler gives us an
echo server.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; echo_server `{Monad m, MonadFix m, MonadProc m, MonadSocket m}
  : m unit :=
  tcp_srv echo_handler.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; has generated typeclasses for the impure primitives
of &lt;code class=&quot;hljs&quot;&gt;proc.mli&lt;/code&gt; and &lt;code class=&quot;hljs&quot;&gt;socket.mli&lt;/code&gt;, &lt;code class=&quot;hljs&quot;&gt;echo_server&lt;/code&gt; is polymorphic, and can
be instantiated for different monads. When it comes to extracting our
program, we will generally prefer the &lt;code class=&quot;hljs&quot;&gt;IO&lt;/code&gt; monad of &lt;code class=&quot;hljs&quot;&gt;coq-simple-io&lt;/code&gt;.
But we could also imagine verifying the client handler with FreeSpec,
or the generic TCP server with Interaction Trees (which support
diverging computations). Overall, we can have different verification
strategies for different parts of our program, by leveraging the most
relevant framework for each part, yet being able to extract it in an
efficient form.&lt;/p&gt;
&lt;p&gt;The next section shows how this last part is achieved using, once
again, a convenient stanza of dune.&lt;/p&gt;
&lt;h2&gt;Extracting and Building an Executable&lt;/h2&gt;
&lt;p&gt;The &lt;code class=&quot;hljs&quot;&gt;0.2&lt;/code&gt; version of the Coq-related stanzas of &lt;code class=&quot;hljs&quot;&gt;dune&lt;/code&gt; provides the
&lt;code class=&quot;hljs&quot;&gt;coq.extraction&lt;/code&gt; stanza, which can be used to build a Coq module
expected to generate &lt;code class=&quot;hljs&quot;&gt;ml&lt;/code&gt; files.&lt;/p&gt;
&lt;p&gt;In our case, we will write &lt;code class=&quot;hljs&quot;&gt;bin/echo.v&lt;/code&gt; to extract the &lt;code class=&quot;hljs&quot;&gt;echo_server&lt;/code&gt;
in a &lt;code class=&quot;hljs&quot;&gt;echo.ml&lt;/code&gt; module, and uses the &lt;code class=&quot;hljs&quot;&gt;executable&lt;/code&gt; stanza of &lt;code class=&quot;hljs&quot;&gt;dune&lt;/code&gt; to
get an executable from this file. To achieve this, the &lt;code class=&quot;hljs&quot;&gt;bin/dune&lt;/code&gt;
file simply requires these two stanzas.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-lisp&quot;&gt;(&lt;span class=&quot;hljs-name&quot;&gt;coq&lt;/span&gt;.extraction
  (&lt;span class=&quot;hljs-name&quot;&gt;prelude&lt;/span&gt; echo)
  (&lt;span class=&quot;hljs-name&quot;&gt;theories&lt;/span&gt; Echo)
  (&lt;span class=&quot;hljs-name&quot;&gt;extracted_modules&lt;/span&gt; echo))

(&lt;span class=&quot;hljs-name&quot;&gt;executable&lt;/span&gt;
  (&lt;span class=&quot;hljs-name&quot;&gt;name&lt;/span&gt; echo)
  (&lt;span class=&quot;hljs-name&quot;&gt;libraries&lt;/span&gt; ffi))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We are almost done. We now need to write the &lt;code class=&quot;hljs&quot;&gt;echo.v&lt;/code&gt; module, which
mostly consists of (1) providing a &lt;code class=&quot;hljs&quot;&gt;MonadFix&lt;/code&gt; instance for the &lt;code class=&quot;hljs&quot;&gt;IO&lt;/code&gt;
monad, (2) using the &lt;code class=&quot;hljs&quot;&gt;IO.unsafe_run&lt;/code&gt; function to escape the &lt;code class=&quot;hljs&quot;&gt;IO&lt;/code&gt;
monad, (3) calling the &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Extraction&lt;/span&gt;&lt;/code&gt; command to wrap it up.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;From&lt;/span&gt; Coq &lt;span class=&quot;hljs-keyword&quot;&gt;Require&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Extraction&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;From&lt;/span&gt; ExtLib &lt;span class=&quot;hljs-keyword&quot;&gt;Require&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Import&lt;/span&gt; MonadFix.
&lt;span class=&quot;hljs-keyword&quot;&gt;From&lt;/span&gt; SimpleIO &lt;span class=&quot;hljs-keyword&quot;&gt;Require&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Import&lt;/span&gt; SimpleIO.
&lt;span class=&quot;hljs-keyword&quot;&gt;From&lt;/span&gt; Echo &lt;span class=&quot;hljs-keyword&quot;&gt;Require&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Import&lt;/span&gt; Server.

&lt;span class=&quot;hljs-keyword&quot;&gt;Instance&lt;/span&gt; MonadFix_IO : MonadFix IO :=
  { mfix := @IO.fix_io }.

&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; main : io_unit :=
  IO.unsafe_run echo_server.

&lt;span class=&quot;hljs-keyword&quot;&gt;Extraction&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;echo.ml&quot;&lt;/span&gt; main.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since we are using the &lt;code class=&quot;hljs language-coq&quot;&gt;i63&lt;/code&gt; type (signed 63bits integers) of the
&lt;code class=&quot;hljs&quot;&gt;CoqFFI&lt;/code&gt; theory, and since &lt;code class=&quot;hljs language-coq&quot;&gt;i63&lt;/code&gt; is implemented under the hood with Coq
primitive integers, we &lt;em&gt;also&lt;/em&gt; need to provide a &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Uint63&lt;/span&gt;&lt;/code&gt; module with a
&lt;code class=&quot;hljs language-ocaml&quot;&gt;of_int&lt;/code&gt; function. Fortunately, this module is straightforward to
write.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; of_int x = x
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And &lt;em&gt;voilà&lt;/em&gt;. A call to &lt;code class=&quot;hljs&quot;&gt;dune&lt;/code&gt; at the root of the repository will
build everything (Coq and OCaml alike). Starting the echo server
is as simple as&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;dune &lt;span class=&quot;hljs-built_in&quot;&gt;exec&lt;/span&gt; bin/echo.exe
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And connecting to it can be achieved with a program like &lt;code class=&quot;hljs&quot;&gt;telnet&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-console&quot;&gt;&lt;span class=&quot;hljs-meta prompt_&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;language-bash&quot;&gt;telnet 127.0.0.1 8888&lt;/span&gt;
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is &apos;^]&apos;.
hello, echo server!
hello, echo server!
Connection closed by foreign host.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Appendix&lt;/h2&gt;
&lt;h3&gt;The &lt;code class=&quot;hljs&quot;&gt;Socket&lt;/code&gt; OCaml Module&lt;/h3&gt;
&lt;p&gt;There is not much to say, except that (as already stated) we use the
&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Unix&lt;/span&gt;&lt;/code&gt; module to manipulate sockets, and we attach to each socket a
buffer to store incoming bytes.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; buffer_size = &lt;span class=&quot;hljs-number&quot;&gt;1024&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; socket_descr = {
  fd : &lt;span class=&quot;hljs-type&quot;&gt;Unix&lt;/span&gt;.file_descr;
  recv_buffer : &lt;span class=&quot;hljs-built_in&quot;&gt;bytes&lt;/span&gt;;
}

&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; from_fd fd =
  &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; rbuff = &lt;span class=&quot;hljs-type&quot;&gt;Bytes&lt;/span&gt;.create buffer_size &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;
  { fd ` fd; recv_buffer ` rbuff }

&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; open_socket hostname port =
  &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;open&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;Unix&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; addr = inet_addr_of_string hostname &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; fd = socket &lt;span class=&quot;hljs-type&quot;&gt;PF_INET&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;SOCK_STREAM&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;
  setsockopt fd &lt;span class=&quot;hljs-type&quot;&gt;SO_REUSEADDR&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;;
  bind fd (&lt;span class=&quot;hljs-type&quot;&gt;ADDR_INET&lt;/span&gt; (addr, port));
  from_fd fd

&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; listen sock = &lt;span class=&quot;hljs-type&quot;&gt;Unix&lt;/span&gt;.listen sock.fd &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; recv sock =
  &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; s = &lt;span class=&quot;hljs-type&quot;&gt;Unix&lt;/span&gt;.read sock.fd sock.recv_buffer &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; buffer_size &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;
  &lt;span class=&quot;hljs-type&quot;&gt;Bytes&lt;/span&gt;.sub_string sock.recv_buffer &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; s

&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; send sock msg =
  &lt;span class=&quot;hljs-type&quot;&gt;Unix&lt;/span&gt;.write_substring sock.fd msg &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;String&lt;/span&gt;.length msg)

&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; accept_connection sock =
  &lt;span class=&quot;hljs-type&quot;&gt;Unix&lt;/span&gt;.accept sock.fd |&amp;gt; fst |&amp;gt; from_fd

&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; close_socket sock = &lt;span class=&quot;hljs-type&quot;&gt;Unix&lt;/span&gt;.close sock.fd
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;The &lt;code class=&quot;hljs&quot;&gt;Proc&lt;/code&gt; OCaml Module&lt;/h3&gt;
&lt;p&gt;Thanks to the &lt;code class=&quot;hljs&quot;&gt;Unix&lt;/code&gt; module, the implementation is pretty straightforward.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; identity = &lt;span class=&quot;hljs-type&quot;&gt;Parent&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; | &lt;span class=&quot;hljs-type&quot;&gt;Child&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; fork x =
  &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;Unix&lt;/span&gt;.fork x &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;
  | &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;Child&lt;/span&gt;
  | x -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;Parent&lt;/span&gt; x
&lt;/code&gt;&lt;/pre&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>coqffi.1.0.0 In A Nutshell</title>
      <link>https://soap.coffee/~lthms/posts/Coqffi-1-0-0.html</link>
      <guid>https://soap.coffee/~lthms/posts/Coqffi-1-0-0.html</guid>
      <pubDate>December 10, 2020</pubDate>
      <description>
        
        &lt;h1&gt;&lt;code class=&quot;hljs&quot;&gt;coqffi.1.0.0&lt;/code&gt; In A Nutshell&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/coq.html&quot; class=&quot;tag hover-lemon&quot; marked=&quot;&quot;&gt;coq&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/ocaml.html&quot; class=&quot;tag hover-sky&quot; marked=&quot;&quot;&gt;ocaml&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/coqffi.html&quot; class=&quot;tag hover-lavender&quot; marked=&quot;&quot;&gt;coqffi&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;For each entry of a &lt;code class=&quot;hljs&quot;&gt;cmi&lt;/code&gt; file (a &lt;em&gt;compiled&lt;/em&gt; &lt;code class=&quot;hljs&quot;&gt;mli&lt;/code&gt; file), &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt;
tries to generate an equivalent (from the extraction mechanism
perspective) Coq definition. In this article, we walk through how
&lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; works.&lt;/p&gt;
&lt;p&gt;Note that we do not dive into the vernacular commands &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt;
generates. They are of no concern for users of &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Getting Started&lt;/h2&gt;
&lt;h3&gt;Requirements&lt;/h3&gt;
&lt;p&gt;The latest version of &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; (&lt;code class=&quot;hljs&quot;&gt;1.0.0~beta8&lt;/code&gt;)
is compatible with OCaml &lt;code class=&quot;hljs&quot;&gt;4.08&lt;/code&gt; up to &lt;code class=&quot;hljs&quot;&gt;4.14&lt;/code&gt;, and Coq &lt;code class=&quot;hljs&quot;&gt;8.12&lt;/code&gt; up top
&lt;code class=&quot;hljs&quot;&gt;8.13&lt;/code&gt;.  If you want to use &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt;, but have incompatible
requirements of your own, feel free to
&lt;a href=&quot;https://github.com/coq-community/coqffi/issues&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;submit an issue&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Installing &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The recommended way to install &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; is through the
&lt;a href=&quot;https://coq.inria.fr/opam/www&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;Opam Coq Archive&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, in the &lt;code class=&quot;hljs&quot;&gt;released&lt;/code&gt;
repository.  If you haven’t activated this repository yet, you can use the
following bash command.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;opam repo add coq-released https://coq.inria.fr/opam/released
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, installing &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; is as simple as&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;opam install coq-coqffi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also get the source from &lt;a href=&quot;https://github.com/coq-community/coqffi&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;the upstream &lt;code class=&quot;hljs&quot;&gt;git&lt;/code&gt;
repository&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. The &lt;code class=&quot;hljs&quot;&gt;README&lt;/code&gt; provides the
necessary pieces of information to build it from source.&lt;/p&gt;
&lt;h3&gt;Additional Dependencies&lt;/h3&gt;
&lt;p&gt;One major difference between Coq and OCaml is that the former is pure,
while the latter is not. Impurity can be modeled in pure languages,
and Coq does not lack of frameworks in this respect. &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; currently
supports two of them:
&lt;a href=&quot;https://github.com/Lysxia/coq-simple-io&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;coq-simple-io&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; and
&lt;a href=&quot;https://github.com/ANSSI-FR/FreeSpec&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;FreeSpec&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. It is also possible to use it
with &lt;a href=&quot;https://github.com/DeepSpec/InteractionTrees&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;Interaction Trees&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, albeit
in a less direct manner.&lt;/p&gt;
&lt;h3&gt;Primitive Types&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; supports a set of primitive types, &lt;em&gt;i.e.&lt;/em&gt;, a set of OCaml
types for which it knows an equivalent type in Coq. The list is the
following (the Coq types are fully qualified in the table, but not in
the generated Coq module as the necessary &lt;code class=&quot;hljs&quot;&gt;Import&lt;/code&gt; statements are
generated too).&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;OCaml type&lt;/th&gt;
&lt;th&gt;Coq type&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;bool&lt;/span&gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;hljs&quot;&gt;Coq.Init.Datatypes.bool&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;char&lt;/span&gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;hljs&quot;&gt;Coq.Strings.Ascii.ascii&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;hljs&quot;&gt;CoqFFI.Data.Int.i63&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;hljs&quot;&gt;Coq.Init.Datatypes.list a&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;Seq&lt;/span&gt;.t&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;hljs&quot;&gt;CoqFFI.Data.Seq.t&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; option&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;hljs&quot;&gt;Coq.Init.Datatypes.option a&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;(&lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt;, &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;e&lt;/span&gt;) result&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;hljs&quot;&gt;Coq.Init.Datatypes.sum&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;hljs&quot;&gt;Coq.Strings.String.string&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;unit&lt;/span&gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;hljs&quot;&gt;Coq.Init.Datatypes.unit&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;exn&lt;/span&gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;hljs&quot;&gt;CoqFFI.Exn&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The &lt;code class=&quot;hljs language-coq&quot;&gt;i63&lt;/code&gt; type is introduced by the &lt;code class=&quot;hljs language-coq&quot;&gt;CoqFFI&lt;/code&gt; theory to provide
signed primitive integers to Coq users. They are implemented on top of the
(unsigned) Coq native integers introduced in Coq &lt;code class=&quot;hljs&quot;&gt;8.13&lt;/code&gt;. The &lt;code class=&quot;hljs&quot;&gt;i63&lt;/code&gt; type will be
deprecated once the support for &lt;a href=&quot;https://github.com/coq/coq/pull/13559&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;signed primitive
integers&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; is implemented&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;This is actually one of the sources of incompatibility of &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt;
with most recent versions of Coq. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;When processing the entries of a given interface model, &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; will
check that they only use these types, or types introduced by the
interface module itself.&lt;/p&gt;
&lt;p&gt;Sometimes, you may encounter a situation where you have two interface
modules &lt;code class=&quot;hljs&quot;&gt;b.mli&lt;/code&gt; and &lt;code class=&quot;hljs&quot;&gt;b.mli&lt;/code&gt;, such that &lt;code class=&quot;hljs&quot;&gt;b.mli&lt;/code&gt; uses a type introduced
in &lt;code class=&quot;hljs&quot;&gt;a.mli&lt;/code&gt;.  To deal with this scenario, you can use the &lt;code class=&quot;hljs&quot;&gt;--witness&lt;/code&gt;
flag to generate &lt;code class=&quot;hljs&quot;&gt;A.v&lt;/code&gt;.  This will tell &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; to also generate
&lt;code class=&quot;hljs&quot;&gt;A.ffi&lt;/code&gt;; this file can then be used when generating &lt;code class=&quot;hljs&quot;&gt;B.v&lt;/code&gt; thanks to
the &lt;code class=&quot;hljs&quot;&gt;-I&lt;/code&gt; option.  Furthermore, for &lt;code class=&quot;hljs&quot;&gt;B.v&lt;/code&gt; to compile the &lt;code class=&quot;hljs&quot;&gt;--require&lt;/code&gt;
option needs to be used to ensure the &lt;code class=&quot;hljs&quot;&gt;A&lt;/code&gt; Coq library (&lt;code class=&quot;hljs&quot;&gt;A.v&lt;/code&gt;) is
required.&lt;/p&gt;
&lt;p&gt;To give a more concrete example, given ~a.mli~&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; t
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and &lt;code class=&quot;hljs&quot;&gt;b.mli&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; a = &lt;span class=&quot;hljs-type&quot;&gt;A&lt;/span&gt;.t
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To generate &lt;code class=&quot;hljs&quot;&gt;A.v&lt;/code&gt;, we can use the following commands:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;ocamlc a.mli
coqffi --witness -o A.v a.cmi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which would generate the following axiom for &lt;code class=&quot;hljs&quot;&gt;t&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Axiom&lt;/span&gt; t : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, generating &lt;code class=&quot;hljs&quot;&gt;B.v&lt;/code&gt; can be achieved as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;ocamlc b.mli
coqffi -I A.ffi -ftransparent-types -r A -o B.v b.cmi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which results in the following output for &lt;code class=&quot;hljs&quot;&gt;v&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Require&lt;/span&gt; A.

&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; u : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt; := A.t.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Code Generation&lt;/h2&gt;
&lt;p&gt;&lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; distinguishes five types of entries: types, pure values,
impure primitives, asynchronous primitives, exceptions, and
modules. We now discuss how each one of them is handled.&lt;/p&gt;
&lt;h3&gt;Types&lt;/h3&gt;
&lt;p&gt;By default, &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; generates axiomatized definitions for each type defined in
a &lt;code class=&quot;hljs&quot;&gt;.cmi&lt;/code&gt; file. This means that &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; t&lt;/code&gt; becomes &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Axiom&lt;/span&gt; t : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;&lt;/code&gt;.
Polymorphism is supported, &lt;em&gt;i.e.&lt;/em&gt;, &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; t&lt;/code&gt; becomes &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Axiom&lt;/span&gt; t : &lt;span class=&quot;hljs-keyword&quot;&gt;forall&lt;/span&gt; (a : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;), &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It is possible to provide a “model” for a type using the &lt;code class=&quot;hljs&quot;&gt;coq_model&lt;/code&gt;
annotation, for instance, for reasoning purposes. That is, we can specify
that a type is equivalent to a &lt;code class=&quot;hljs&quot;&gt;list&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; t [@@coq_model &lt;span class=&quot;hljs-string&quot;&gt;&quot;list&quot;&lt;/span&gt;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This generates the following Coq definition.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; t : &lt;span class=&quot;hljs-keyword&quot;&gt;forall&lt;/span&gt; (a : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;), &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt; := list.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is important to be careful when using the =coq_model= annotation. More
precisely, the fact that &lt;code class=&quot;hljs&quot;&gt;t&lt;/code&gt; is a &lt;code class=&quot;hljs&quot;&gt;list&lt;/code&gt; in the “Coq universe” shall not be
used while the implementation phase, only the verification phase.&lt;/p&gt;
&lt;p&gt;Unnamed polymorphic type parameters are also supported. In presence of
such parameters, &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; will find it a name that is not already
used. For instance,&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; (_, &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt;) ast
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;becomes&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Axiom&lt;/span&gt; ast : &lt;span class=&quot;hljs-keyword&quot;&gt;forall&lt;/span&gt; (b : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;) (a : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;), &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; has got an experimental feature called &lt;code class=&quot;hljs&quot;&gt;transparent-types&lt;/code&gt;
(enabled by using the &lt;code class=&quot;hljs&quot;&gt;-ftransparent-types&lt;/code&gt; command-line argument). If the type
definition is given in the module interface, then &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; tries to generate
an equivalent definition in Coq. For instance,&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; llist =
  | &lt;span class=&quot;hljs-type&quot;&gt;LCons&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; * (&lt;span class=&quot;hljs-built_in&quot;&gt;unit&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; llist)
  | &lt;span class=&quot;hljs-type&quot;&gt;LNil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;becomes&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Inductive&lt;/span&gt; llist (a : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;) : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt; :=
| &lt;span class=&quot;hljs-type&quot;&gt;LCons&lt;/span&gt; (x0 : a) (x1 : unit -&amp;gt; llist a) : llist a
| &lt;span class=&quot;hljs-type&quot;&gt;LNil&lt;/span&gt; : llist a.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Mutually recursive types are supported, so&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; even = &lt;span class=&quot;hljs-type&quot;&gt;Zero&lt;/span&gt; | &lt;span class=&quot;hljs-type&quot;&gt;ESucc&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;of&lt;/span&gt; odd
&lt;span class=&quot;hljs-keyword&quot;&gt;and&lt;/span&gt; odd = &lt;span class=&quot;hljs-type&quot;&gt;OSucc&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;of&lt;/span&gt; even
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;becomes&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Inductive&lt;/span&gt; odd : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt; :=
| &lt;span class=&quot;hljs-type&quot;&gt;OSucc&lt;/span&gt; (x0 : even) : odd
&lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt; even : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt; :=
| &lt;span class=&quot;hljs-type&quot;&gt;Zero&lt;/span&gt; : even
| &lt;span class=&quot;hljs-type&quot;&gt;ESucc&lt;/span&gt; (x0 : odd) : even.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Besides, &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; supports alias types, as suggested in this write-up
when we discuss witness files.&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;hljs&quot;&gt;transparent-types&lt;/code&gt; feature is &lt;strong&gt;experimental&lt;/strong&gt;, and is currently
limited to variant types. It notably does not support records. Besides, it may
generate incorrect Coq types, because it does not check whether or not the
&lt;a href=&quot;https://coq.inria.fr/refman/language/core/inductive.html#positivity-condition&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;positivity
condition&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;
is satisfied.&lt;/p&gt;
&lt;h3&gt;Pure values&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; decides whether or not a given OCaml value is pure or impure
with the following heuristics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Constants are pure&lt;/li&gt;
&lt;li&gt;Functions are impure by default&lt;/li&gt;
&lt;li&gt;Functions with a &lt;code class=&quot;hljs&quot;&gt;coq_model&lt;/code&gt; annotation are pure&lt;/li&gt;
&lt;li&gt;Functions marked with the &lt;code class=&quot;hljs&quot;&gt;pure&lt;/code&gt; annotation are pure&lt;/li&gt;
&lt;li&gt;If the &lt;code class=&quot;hljs&quot;&gt;pure-module&lt;/code&gt; feature is enabled (&lt;code class=&quot;hljs&quot;&gt;-fpure-module&lt;/code&gt;), then synchronous
functions (which do not live inside the
&lt;a href=&quot;https://ocsigen.org/lwt/5.3.0/manual/manual&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;~Lwt~&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; monad) are pure&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Similarly to types, &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; generates axioms (or definitions if the
&lt;code class=&quot;hljs&quot;&gt;coq_model&lt;/code&gt; annotation is used) for pure values. Then,&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; unpack : &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; -&amp;gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;char&lt;/span&gt; * &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;) option [@@pure]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;becomes&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Axiom&lt;/span&gt; unpack : &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; -&amp;gt; option (ascii * &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;).
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Polymorphic values are supported.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; map : (&lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;b&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;b&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt; [@@pure]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;becomes&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Axiom&lt;/span&gt; map : &lt;span class=&quot;hljs-keyword&quot;&gt;forall&lt;/span&gt; (a : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;) (b : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;), (a -&amp;gt; b) -&amp;gt; list a -&amp;gt; list b.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Again, unnamed polymorphic typse are supported, so&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; ast_to_string : _ ast -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; [@@pure]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;becomes&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Axiom&lt;/span&gt; ast_to_string : &lt;span class=&quot;hljs-keyword&quot;&gt;forall&lt;/span&gt; (a : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;), string.
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Impure Primitives&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; reserves a special treatment for /impure/ OCaml functions.
Impurity is usually handled in pure programming languages by means of
monads, and &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; is no exception to the rule.&lt;/p&gt;
&lt;p&gt;Given the set of impure primitives declared in an interface module,
&lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; will (1) generate a typeclass which gathers these primitives,
and (2) generate instances of this typeclass for supported backends.&lt;/p&gt;
&lt;p&gt;We illustrate the rest of this section with the following impure
primitives.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; echo : &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;unit&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; scan : &lt;span class=&quot;hljs-built_in&quot;&gt;unit&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;where &lt;code class=&quot;hljs&quot;&gt;echo&lt;/code&gt; allows writing something the standard output, and &lt;code class=&quot;hljs&quot;&gt;scan&lt;/code&gt;
to read the standard input.&lt;/p&gt;
&lt;p&gt;Assuming the processed module interface is named &lt;code class=&quot;hljs&quot;&gt;console.mli&lt;/code&gt;, the
following Coq typeclass is generated.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Class&lt;/span&gt; MonadConsole (m : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;) := { echo : string -&amp;gt; m unit
                                         ; scan : unit -&amp;gt; m string
                                         }.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using this typeclass and with the additional support of an additional
&lt;code class=&quot;hljs&quot;&gt;Monad&lt;/code&gt; typeclass, we can specify impure computations which interacts
with the console. For instance, with the support of &lt;code class=&quot;hljs&quot;&gt;ExtLib&lt;/code&gt;, one can
write.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; pipe `{Monad m, MonadConsole m} : m unit :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt;* msg := scan () &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt;
  echo msg.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is no canonical way to model impurity in Coq, but over the years
several frameworks have been released to tackle this challenge.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; provides three features related to impure primitives.&lt;/p&gt;
&lt;h4&gt;&lt;code class=&quot;hljs&quot;&gt;simple-io&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;When this feature is enabled, &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; generates an instance of the
typeclass for the =IO= monad introduced in the &lt;code class=&quot;hljs&quot;&gt;coq-simple-io&lt;/code&gt; package&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Axiom&lt;/span&gt; io_echo : string -&amp;gt; IO unit.
&lt;span class=&quot;hljs-keyword&quot;&gt;Axiom&lt;/span&gt; io_scan : unit -&amp;gt; IO string.

&lt;span class=&quot;hljs-keyword&quot;&gt;Instance&lt;/span&gt; IO_MonadConsole : MonadConsole IO := { echo := io_echo
                                              ; scan := io_scan
                                              }.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is enabled by default, but can be disabled using the
&lt;code class=&quot;hljs&quot;&gt;-fno-simple-io&lt;/code&gt; command-line argument.&lt;/p&gt;
&lt;h4&gt;&lt;code class=&quot;hljs&quot;&gt;interface&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;When this feature is enabled, &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; generates an inductive type which
describes the set of primitives available, to be used with frameworks like
&lt;a href=&quot;https://github.com/lthms/FreeSpec&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;FreeSpec&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; or &lt;a href=&quot;https://github.com/DeepSpec/InteractionTrees&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;Interactions
Trees&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Inductive&lt;/span&gt; CONSOLE : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt; :=
| &lt;span class=&quot;hljs-type&quot;&gt;Echo&lt;/span&gt; : string -&amp;gt; CONSOLE unit
| &lt;span class=&quot;hljs-type&quot;&gt;Scan&lt;/span&gt; : unit -&amp;gt; CONSOLE string.

&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; inj_echo `{Inject CONSOLE m} (x0 : string) : m unit :=
  inject (Echo x0).

&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; inj_scan `{Inject CONSOLE m} (x0 : unit) : m string :=
  inject (Scan x0).

&lt;span class=&quot;hljs-keyword&quot;&gt;Instance&lt;/span&gt; Inject_MonadConsole `{Inject CONSOLE m} : MonadConsole m :=
  { echo := inj_echo
  ; scan := inj_scan
  }.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Providing an instance of the form &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;forall&lt;/span&gt; i, Inject i M&lt;/code&gt; is enough for
your monad &lt;code class=&quot;hljs&quot;&gt;M&lt;/code&gt; to be compatible with this feature&lt;label for=&quot;fn2&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn2&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;See for instance &lt;a href=&quot;https://github.com/lthms/FreeSpec/blob/master/theories/FFI/FFI.v&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;how FreeSpec implements
it&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;). &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;h4&gt;&lt;code class=&quot;hljs&quot;&gt;freespec&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;When this feature in enabled, &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; generates a semantics for the
inductive type generated by the &lt;code class=&quot;hljs&quot;&gt;interface&lt;/code&gt; feature.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Axiom&lt;/span&gt; unsafe_echo : string -&amp;gt; unit.
&lt;span class=&quot;hljs-keyword&quot;&gt;Axiom&lt;/span&gt; unsafe_scan : uint -&amp;gt; string.

&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; console_unsafe_semantics : semantics CONSOLE :=
  bootstrap (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; a e =&amp;gt;
    local &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; e &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt; CONSOLE a &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; a &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
          | &lt;span class=&quot;hljs-type&quot;&gt;Echo&lt;/span&gt; x0 =&amp;gt; unsafe_echo x0
          | &lt;span class=&quot;hljs-type&quot;&gt;Scan&lt;/span&gt; x0 =&amp;gt; unsafe_scan x0
          &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;).
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Asynchronous Primitives&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; also reserves a special treatment for &lt;em&gt;asynchronous&lt;/em&gt;
primitives —&lt;em&gt;i.e.&lt;/em&gt;, functions which live inside the &lt;code class=&quot;hljs&quot;&gt;Lwt&lt;/code&gt; monad— when
the &lt;code class=&quot;hljs&quot;&gt;lwt&lt;/code&gt; feature is enabled.&lt;/p&gt;
&lt;p&gt;The treatment is very analogous to the one for impure primitives: (1)
a typeclass is generated (with the &lt;code class=&quot;hljs&quot;&gt;_Async&lt;/code&gt; suffix), and (2) an
instance for the &lt;code class=&quot;hljs&quot;&gt;Lwt&lt;/code&gt; monad is generated. Besides, an instance for
the “synchronous” primitives is also generated for &lt;code class=&quot;hljs&quot;&gt;Lwt&lt;/code&gt;. If the
&lt;code class=&quot;hljs&quot;&gt;interface&lt;/code&gt; feature is enabled, an interface datatype is generated,
which means you can potentially use Coq to reason about your
asynchronous programs (using FreeSpec and alike, although the
interleaving of asynchronous programs in not yet supported in
FreeSpec).&lt;/p&gt;
&lt;p&gt;By default, the type of the &lt;code class=&quot;hljs&quot;&gt;Lwt&lt;/code&gt; monad is &lt;code class=&quot;hljs&quot;&gt;Lwt.t&lt;/code&gt;. You can override
this setting using the &lt;code class=&quot;hljs&quot;&gt;--lwt-alias&lt;/code&gt; option.  This can be useful when
you are using an alias type in place of &lt;code class=&quot;hljs&quot;&gt;Lwt.t&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Exceptions&lt;/h3&gt;
&lt;p&gt;OCaml features an exception mechanism. Developers can define their
own exceptions using the &lt;code class=&quot;hljs&quot;&gt;exception&lt;/code&gt; keyword, whose syntax is similar
to the constructors’ definition. For instance,&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;exception&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;Foo&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; * &lt;span class=&quot;hljs-built_in&quot;&gt;bool&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;introduces a new exception &lt;code class=&quot;hljs&quot;&gt;Foo&lt;/code&gt; which takes two parameters of type &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/code&gt; and
&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;bool&lt;/span&gt;&lt;/code&gt;. &lt;code class=&quot;hljs&quot;&gt;Foo (x, y)&lt;/code&gt; constructs of value of type &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;exn&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For each new exception introduced in an OCaml module, &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt;
generates (1) a so-called “proxy type,” and (2) conversion functions
to and from this type.&lt;/p&gt;
&lt;p&gt;Coming back to our example, the “proxy type” generates by &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; is&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Inductive&lt;/span&gt; FooExn : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt; :=
| &lt;span class=&quot;hljs-type&quot;&gt;MakeFooExn&lt;/span&gt; (x0 : i63) (x1 : bool) : FooExn.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; generates conversion functions.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Axiom&lt;/span&gt; exn_of_foo : FooExn -&amp;gt; exn.
&lt;span class=&quot;hljs-keyword&quot;&gt;Axiom&lt;/span&gt; foo_of_exn : exn -&amp;gt; option FooExn.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Besides, &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; also generates an instance for the &lt;code class=&quot;hljs&quot;&gt;Exn&lt;/code&gt; typeclass
provided by the &lt;code class=&quot;hljs&quot;&gt;CoqFFI&lt;/code&gt; theory:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Instance&lt;/span&gt; FooExn_Exn : Exn FooExn :=
  { to_exn := exn_of_foo
  ; of_exn := foo_of_exn
  }.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Under the hood, &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;exn&lt;/span&gt;&lt;/code&gt; is an
&lt;a href=&quot;https://caml.inria.fr/pub/docs/manual-ocaml/extensiblevariants.html&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;extensible
datatype&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;,
and how &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; supports it will probably be generalized in future releases.&lt;/p&gt;
&lt;p&gt;Finally, &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; has a minimal support for functions which may raise
exceptions. Since OCaml type system does not allow to identify such
functions, they need to be annotated explicitly, using the
=may_raise= annotation. In such a case, &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; will change the
return type of the function to use the =sum= Coq inductive type.&lt;/p&gt;
&lt;p&gt;For instance,&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; from_option : &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; option -&amp;gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; [@@may_raise] [@@pure]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;becomes&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Axiom&lt;/span&gt; from_option : &lt;span class=&quot;hljs-keyword&quot;&gt;forall&lt;/span&gt; (a : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;), option a -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;sum&lt;/span&gt; a exn.
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Modules&lt;/h3&gt;
&lt;p&gt;Lastly, &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; supports OCaml modules described within &lt;code class=&quot;hljs&quot;&gt;mli&lt;/code&gt; files,
when they are specified as &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;T&lt;/span&gt; : &lt;span class=&quot;hljs-keyword&quot;&gt;sig&lt;/span&gt; ... &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;&lt;/code&gt;. For instance,&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;T&lt;/span&gt; : &lt;span class=&quot;hljs-keyword&quot;&gt;sig&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; t

  &lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; to_string : t -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; [@@pure]
&lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;becomes&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Module&lt;/span&gt; T.
  &lt;span class=&quot;hljs-keyword&quot;&gt;Axiom&lt;/span&gt; t : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;.

  &lt;span class=&quot;hljs-keyword&quot;&gt;Axiom&lt;/span&gt; to_string : t -&amp;gt; string.
&lt;span class=&quot;hljs-keyword&quot;&gt;End&lt;/span&gt; T.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As of now, the following construction is unfortunately &lt;em&gt;not&lt;/em&gt;
supported, and will be ignored by &lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;S&lt;/span&gt; = &lt;span class=&quot;hljs-keyword&quot;&gt;sig&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; t

  &lt;span class=&quot;hljs-keyword&quot;&gt;val&lt;/span&gt; to_string : t -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;string&lt;/span&gt; [@@pure]
&lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;T&lt;/span&gt; : &lt;span class=&quot;hljs-type&quot;&gt;S&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Moving Forward&lt;/h2&gt;
&lt;p&gt;&lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; comes with a comprehensive man page. In addition, the
interested reader can proceed to the next article of this series,
which explains how &lt;a href=&quot;/~lthms/posts/CoqffiEcho.html&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;coqffi&lt;/code&gt; can be used to easily implement an echo
server in Coq&lt;/a&gt;.&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>Pattern Matching on Types and Contexts</title>
      <link>https://soap.coffee/~lthms/posts/LtacPatternMatching.html</link>
      <guid>https://soap.coffee/~lthms/posts/LtacPatternMatching.html</guid>
      <pubDate>August 28, 2020</pubDate>
      <description>
        
        &lt;h1&gt;Pattern Matching on Types and Contexts&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/coq.html&quot; class=&quot;tag hover-peach&quot; marked=&quot;&quot;&gt;coq&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;In the &lt;a href=&quot;/~lthms/posts/LtacMetaprogramming.html&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;a previous article&lt;/a&gt; of our series on
Ltac, we have shown how tactics allow for constructing Coq terms incrementally.
Ltac programs (“proof scripts”) generate terms, and the shape of said terms can
be very different regarding the initial context. For instance, &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;induction&lt;/span&gt; x&lt;/code&gt; will refine the current goal by using an inductive principle dedicated to
the type of &lt;code class=&quot;hljs language-coq&quot;&gt;x&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is possible because Ltac allows for pattern matching on types and
contexts. In this article, we give a short introduction on this feature of
key importance.&lt;/p&gt;
&lt;h2&gt;To &lt;code class=&quot;hljs language-coq&quot;&gt;lazymatch&lt;/code&gt; or to &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt;&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Gallina provides one pattern matching construction, whose semantics is always
the same: for a given term, the first pattern to match will always be selected.
On the contrary, Ltac provides several pattern matching constructions with
different semantics. This key difference has probably been motivated because
Ltac is not a total language: a tactic may not always succeed.&lt;/p&gt;
&lt;p&gt;Ltac programmers can use &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt;&lt;/code&gt; or &lt;code class=&quot;hljs language-coq&quot;&gt;lazymatch&lt;/code&gt;. One the one hand,
with &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt;&lt;/code&gt;, if one pattern matches, but the branch body fails, Coq will
backtrack and try the next branch. On the other hand, &lt;code class=&quot;hljs language-coq&quot;&gt;lazymatch&lt;/code&gt; will
stop with an error.&lt;/p&gt;
&lt;p&gt;So, for instance, the two following tactics will print two different messages:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Ltac&lt;/span&gt; match_failure :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; goal &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;_&lt;/span&gt;
    =&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;fail&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;fail in first branch&quot;&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;_&lt;/span&gt;
    =&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;fail&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;fail in second branch&quot;&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;.

&lt;span class=&quot;hljs-keyword&quot;&gt;Ltac&lt;/span&gt; lazymatch_failure :=
  lazymatch goal &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;_&lt;/span&gt;
    =&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;fail&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;fail in first branch&quot;&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;_&lt;/span&gt;
    =&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;fail&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;fail in second branch&quot;&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can try that quite easily by starting a dumb goal (eg. &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Goal&lt;/span&gt; (True).&lt;/code&gt;)
and call our tactic. For &lt;code class=&quot;hljs language-coq&quot;&gt;match_failure&lt;/code&gt;, we get:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;Ltac call to &quot;match_failure&quot; failed.
Error: Tactic failure: fail in second branch.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On the other hand, for &lt;code class=&quot;hljs language-coq&quot;&gt;lazymatch_failure&lt;/code&gt;, we get:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;Ltac call to &quot;match_failure&apos;&quot; failed.
Error: Tactic failure: fail in first branch.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Moreover, pattern matching allows for matching over &lt;em&gt;patterns&lt;/em&gt;, not just
constants. Here, Ltac syntax differs from Gallina’s. In Gallina, if a
variable name is used in a pattern, Gallina creates a new variable in the
scope of the related branch. If a variable with the same name already
existed, it is shadowed. On the contrary, in Ltac, using a variable name
as-is in a pattern implies an equality check.&lt;/p&gt;
&lt;p&gt;To illustrate this difference, we can take the example of the following
tactic.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Ltac&lt;/span&gt; successive x y :=
  lazymatch y &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;S&lt;/span&gt; x =&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;idtac&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;_&lt;/span&gt; =&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;fail&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;successive x y&lt;/code&gt; will fail if &lt;code class=&quot;hljs language-coq&quot;&gt;y&lt;/code&gt; is not the successor of
&lt;code class=&quot;hljs language-coq&quot;&gt;x&lt;/code&gt;. On the contrary, the “syntactically equivalent” function in Gallina
will exhibit a totally different behavior.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; successor (x y : nat) : bool :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; y &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;S&lt;/span&gt; x =&amp;gt; true
  | &lt;span class=&quot;hljs-type&quot;&gt;_&lt;/span&gt; =&amp;gt; false
  &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, the first branch of the pattern match is systematically selected when
&lt;code class=&quot;hljs language-coq&quot;&gt;y&lt;/code&gt; is not &lt;code class=&quot;hljs language-coq&quot;&gt;O&lt;/code&gt;, and in this branch, the argument &lt;code class=&quot;hljs language-coq&quot;&gt;x&lt;/code&gt; is shadowed by the
predecessor of &lt;code class=&quot;hljs language-coq&quot;&gt;y&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For Ltac to adopt a behavior similar to Gallina, the &lt;code class=&quot;hljs language-coq&quot;&gt;?&lt;/code&gt; prefix shall be
used. For instance, the following tactic will check whether its argument
has a known successor, prints it if it does, or fail otherwise.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Ltac&lt;/span&gt; print_pred_or_zero x :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; x &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;S&lt;/span&gt; ?x =&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;idtac&lt;/span&gt; x
  | &lt;span class=&quot;hljs-type&quot;&gt;_&lt;/span&gt; =&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;fail&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On the one hand, &lt;code class=&quot;hljs language-coq&quot;&gt;print_pred_or_zero &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;&lt;/code&gt; will print &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;/code&gt;. On the
other hand, if there exists a variable &lt;code class=&quot;hljs language-coq&quot;&gt;x : nat&lt;/code&gt; in the context, calling
&lt;code class=&quot;hljs language-coq&quot;&gt;print_pred_or_zero x&lt;/code&gt; will fail, since the exact value of &lt;code class=&quot;hljs language-coq&quot;&gt;x&lt;/code&gt; is
not known.&lt;/p&gt;
&lt;h3&gt;Pattern Matching on Types with &lt;code class=&quot;hljs language-coq&quot;&gt;type of&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code class=&quot;hljs language-coq&quot;&gt;type of&lt;/code&gt; operator can be used in conjunction to pattern matching to
generate different terms according to the type of a variable. We could
leverage this to reimplement &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;induction&lt;/span&gt;&lt;/code&gt; for instance.&lt;/p&gt;
&lt;p&gt;As an example, we propose the following &lt;code class=&quot;hljs language-coq&quot;&gt;not_nat&lt;/code&gt; tactic which, given an
argument &lt;code class=&quot;hljs language-coq&quot;&gt;x&lt;/code&gt;, fails if &lt;code class=&quot;hljs language-coq&quot;&gt;x&lt;/code&gt; is of type &lt;code class=&quot;hljs language-coq&quot;&gt;nat&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Ltac&lt;/span&gt; not_nat x :=
  lazymatch type of x &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;nat&lt;/span&gt; =&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;fail&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;argument is of type nat&quot;&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;_&lt;/span&gt; =&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;idtac&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this definition, &lt;code class=&quot;hljs language-coq&quot;&gt;not_nat true&lt;/code&gt; succeeds since &lt;code class=&quot;hljs language-coq&quot;&gt;true&lt;/code&gt; is of
type &lt;code class=&quot;hljs language-coq&quot;&gt;bool&lt;/code&gt;, and &lt;code class=&quot;hljs language-coq&quot;&gt;not_nat O&lt;/code&gt; since &lt;code class=&quot;hljs language-coq&quot;&gt;O&lt;/code&gt; encodes &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;0&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;0&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; in
&lt;code class=&quot;hljs language-coq&quot;&gt;nat&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We can also use the &lt;code class=&quot;hljs language-coq&quot;&gt;?&lt;/code&gt; prefix to write true pattern. For instance, the
following tactic will fail if the type of its supplied argument has at least
one parameter.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Ltac&lt;/span&gt; not_param_type x :=
  lazymatch type of x &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;?f&lt;/span&gt; ?a =&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;fail&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;argument is of type with parameter&quot;&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;_&lt;/span&gt; =&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;idtac&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both &lt;code class=&quot;hljs language-coq&quot;&gt;not_param_type (@nil nat)&lt;/code&gt; of type &lt;code class=&quot;hljs language-coq&quot;&gt;list nat&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;@eq_refl nat &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;/code&gt; of type &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;/code&gt; fail, but &lt;code class=&quot;hljs language-coq&quot;&gt;not_param_type &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;/code&gt; of type
&lt;code class=&quot;hljs language-coq&quot;&gt;nat&lt;/code&gt; succeeds. *)&lt;/p&gt;
&lt;h2&gt;Pattern Matching on the Context with &lt;code class=&quot;hljs language-coq&quot;&gt;goal&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Lastly, we discuss how Ltac allows for inspecting the context (&lt;em&gt;i.e.&lt;/em&gt;, the
hypotheses and the goal) using the &lt;code class=&quot;hljs language-coq&quot;&gt;goal&lt;/code&gt; keyword.&lt;/p&gt;
&lt;p&gt;For instance, we propose a naive implementation of the &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;subst&lt;/span&gt;&lt;/code&gt; tactic
as follows.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Ltac&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;subst&lt;/span&gt;&apos; :=
  &lt;span class=&quot;hljs-built_in&quot;&gt;repeat&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; goal &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
    | &lt;span class=&quot;hljs-type&quot;&gt;H&lt;/span&gt; :  ?x = &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; |&lt;span class=&quot;hljs-type&quot;&gt;- context&lt;/span&gt;[?x]
      =&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;repeat&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; H; &lt;span class=&quot;hljs-built_in&quot;&gt;clear&lt;/span&gt; H
    &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With &lt;code class=&quot;hljs language-coq&quot;&gt;goal&lt;/code&gt;, patterns are of the form &lt;code class=&quot;hljs language-coq&quot;&gt;H : (&lt;span class=&quot;hljs-built_in&quot;&gt;pattern&lt;/span&gt;), ... |&lt;span class=&quot;hljs-type&quot;&gt;- (pattern&lt;/span&gt;)&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;At the left side of &lt;code class=&quot;hljs language-coq&quot;&gt;|&lt;span class=&quot;hljs-type&quot;&gt;-&lt;/span&gt;&lt;/code&gt;, we match on hypotheses. Beware that
contrary to variable names in pattern, hypothesis names behaves as in
Gallina (i.e., fresh binding, shadowing, etc.). In the branch, we are
looking for equations, i.e., a hypothesis of the form &lt;code class=&quot;hljs language-coq&quot;&gt;?x = &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;At the right side of &lt;code class=&quot;hljs language-coq&quot;&gt;|&lt;span class=&quot;hljs-type&quot;&gt;-&lt;/span&gt;&lt;/code&gt;, we match on the goal.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In both cases, Ltac makes available an interesting operator,
&lt;code class=&quot;hljs language-coq&quot;&gt;context[(&lt;span class=&quot;hljs-built_in&quot;&gt;pattern&lt;/span&gt;)&lt;/code&gt;], which is satisfied if &lt;code class=&quot;hljs language-coq&quot;&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;pattern&lt;/span&gt;)&lt;/code&gt; appears somewhere in
the object we are pattern matching against. So, the branch of the &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt;&lt;/code&gt;
reads as follows: we are looking for an equation &lt;code class=&quot;hljs language-coq&quot;&gt;H&lt;/code&gt; which specifies the
value of an object &lt;code class=&quot;hljs language-coq&quot;&gt;x&lt;/code&gt; which appears in the goal. If such an equation
exists, &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;subst&lt;/span&gt;&apos;&lt;/code&gt; tries to &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; x&lt;/code&gt; as many times as possible.&lt;/p&gt;
&lt;p&gt;This implementation of &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;subst&lt;/span&gt;&apos;&lt;/code&gt; is very fragile, and will not work if the
equation is of the form &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; = ?x&lt;/code&gt;, and it may behave poorly if we have
“transitive equations”, such as there exists hypotheses &lt;code class=&quot;hljs language-coq&quot;&gt;?x = ?y&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;?y = &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt;&lt;/code&gt;. Motivated readers may be interested in proposing a more robust
implementation of &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;subst&lt;/span&gt;&apos;&lt;/code&gt;.&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>Ltac is an Imperative Metaprogramming Language</title>
      <link>https://soap.coffee/~lthms/posts/LtacMetaprogramming.html</link>
      <guid>https://soap.coffee/~lthms/posts/LtacMetaprogramming.html</guid>
      <pubDate>August 28, 2020</pubDate>
      <description>
        
        &lt;h1&gt;Ltac is an Imperative Metaprogramming Language&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/coq.html&quot; class=&quot;tag hover-sky&quot; marked=&quot;&quot;&gt;coq&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;Coq is often depicted as an &lt;em&gt;interactive&lt;/em&gt; proof assistant, thanks to its
proof environment. Inside the proof environment, Coq presents the user a
goal, and said user solves said goal by means of tactics which describes a
logical reasoning. For instance, to reason by induction, one can use the
&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;induction&lt;/span&gt;&lt;/code&gt; tactic, while a simple case analysis can rely on the
&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;destruct&lt;/span&gt;&lt;/code&gt; or &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;case_eq&lt;/span&gt;&lt;/code&gt; tactics, etc.  It is not uncommon for new
Coq users to be introduced to Ltac, the Coq default tactic language, using this
proof-centric approach. This is not surprising, since writing proofs remains
the main use case for Ltac. In practice, though, this discourse remains an
abstraction which hides away what actually happens under the hood when Coq
executes a proof script.&lt;/p&gt;
&lt;p&gt;To really understand what Ltac is about, we need to recall ourselves that
Coq kernel is mostly a type checker. A theorem statement is expressed as a
“type” (which lives in a dedicated sort called &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Prop&lt;/span&gt;&lt;/code&gt;), and a proof of
this theorem is a term of this type, just like the term &lt;code class=&quot;hljs language-coq&quot;&gt;S (S O)&lt;/code&gt; (&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;2&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;)
is of type &lt;code class=&quot;hljs language-coq&quot;&gt;nat&lt;/code&gt;.  Proving a theorem in Coq requires to construct a term
of the type encoding said theorem, and Ltac allows for incrementally
constructing this term, one step at a time.&lt;/p&gt;
&lt;p&gt;Ltac generates terms, therefore it is a metaprogramming language. It does it
incrementally, by using primitives to modifying an implicit state, therefore
it is an imperative language. Henceforth, it is an imperative
metaprogramming language.&lt;/p&gt;
&lt;p&gt;To summarize, a goal presented by Coq inside the environment proof is a hole
within the term being constructed. It is presented to users as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A list of “hypotheses,” which are nothing more than the variables
in the scope of the hole&lt;/li&gt;
&lt;li&gt;A type, which is the type of the term to construct to fill the hole&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We illustrate what happens under the hood of Coq executes a simple proof
script. One can use the &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Show&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;&lt;/code&gt; vernacular command to exhibit
this.&lt;/p&gt;
&lt;p&gt;We illustrate how Ltac works with the following example.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Theorem&lt;/span&gt; add_n_O : &lt;span class=&quot;hljs-keyword&quot;&gt;forall&lt;/span&gt; (n : nat), n + O = n.
&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;&lt;/code&gt; vernacular command starts the proof environment. Since no
tactic has been used, the term we are trying to construct consists solely in a
hole, while Coq presents us a goal with no hypothesis, and with the exact type
of our theorem, that is &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;forall&lt;/span&gt; (n : nat), n + O = n&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A typical Coq course will explain to students the &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;intro&lt;/span&gt;&lt;/code&gt; tactic allows for
turning the premise of an implication into an hypothesis within the context.&lt;/p&gt;
&lt;p class=&quot;katex-block&quot;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mo&gt;⊢&lt;/mo&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;mo&gt;→&lt;/mo&gt;&lt;mi&gt;Q&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;C \vdash P \rightarrow Q
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.07153em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;⊢&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.13889em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;→&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8778em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;Q&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;becomes&lt;/p&gt;
&lt;p class=&quot;katex-block&quot;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mtext&gt;&amp;nbsp;&lt;/mtext&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;mo&gt;⊢&lt;/mo&gt;&lt;mi&gt;Q&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;C,\ P \vdash Q
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.07153em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.13889em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;⊢&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8778em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;Q&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;This is a fundamental rule of deductive reasoning, and &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;intro&lt;/span&gt;&lt;/code&gt; encodes it.
It achieves this by refining the current hole into an anonymous function.
When we use&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;  &lt;span class=&quot;hljs-built_in&quot;&gt;intro&lt;/span&gt; n.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;it refines the term&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;  ?Goal1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;into&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;  &lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; (n : nat) =&amp;gt; ?Goal2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The next step of this proof is to reason about induction on &lt;code class=&quot;hljs&quot;&gt;n&lt;/code&gt;. For &lt;code class=&quot;hljs&quot;&gt;nat&lt;/code&gt;,
it means that to be able to prove&lt;/p&gt;
&lt;p class=&quot;katex-block&quot;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;∀&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;P&lt;/mi&gt;&lt;mtext&gt;&amp;nbsp;&lt;/mtext&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\forall n, \mathrm{P}\ n
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∀&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathrm&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;we need to prove that&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;P&lt;/mi&gt;&lt;mtext&gt;&amp;nbsp;&lt;/mtext&gt;&lt;mn&gt;0&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\mathrm{P}\ 0&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathrm&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;∀&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;P&lt;/mi&gt;&lt;mtext&gt;&amp;nbsp;&lt;/mtext&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mo&gt;→&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;P&lt;/mi&gt;&lt;mtext&gt;&amp;nbsp;&lt;/mtext&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\forall n, \mathrm{P}\ n \rightarrow \mathrm{P}\ (S n)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∀&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathrm&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;→&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathrm&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.05764em;&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;induction&lt;/span&gt;&lt;/code&gt; tactic effectively turns our goal into two subgoals. But
why is that? Because, under the hood, Ltac is refining the current goal using
the &lt;code class=&quot;hljs language-coq&quot;&gt;nat_ind&lt;/code&gt; function automatically generated by Coq when &lt;code class=&quot;hljs language-coq&quot;&gt;nat&lt;/code&gt;
was defined. The type of &lt;code class=&quot;hljs language-coq&quot;&gt;nat_ind&lt;/code&gt; is&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;  &lt;span class=&quot;hljs-keyword&quot;&gt;forall&lt;/span&gt; (P : nat -&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Prop&lt;/span&gt;),
    P &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;
    -&amp;gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;forall&lt;/span&gt; n : nat, P n -&amp;gt; P (S n))
    -&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;forall&lt;/span&gt; n : nat, P n
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Interestingly enough, &lt;code class=&quot;hljs language-coq&quot;&gt;nat_ind&lt;/code&gt; is not an axiom. It is a regular Coq
function, whose definition is&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;  &lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; (P : nat -&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Prop&lt;/span&gt;) (f : P &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)
      (f0 : &lt;span class=&quot;hljs-keyword&quot;&gt;forall&lt;/span&gt; n : nat, P n -&amp;gt; P (S n)) =&amp;gt;
  &lt;span class=&quot;hljs-built_in&quot;&gt;fix&lt;/span&gt; F (n : nat) : P n :=
    &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; n &lt;span class=&quot;hljs-built_in&quot;&gt;as&lt;/span&gt; n0 &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; (P n0) &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
    | &lt;span class=&quot;hljs-type&quot;&gt;0&lt;/span&gt; =&amp;gt; f
    | &lt;span class=&quot;hljs-type&quot;&gt;S&lt;/span&gt; n0 =&amp;gt; f0 n0 (F n0)
    &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, after executing&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;  &lt;span class=&quot;hljs-built_in&quot;&gt;induction&lt;/span&gt; n.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The hidden term we are constructing becomes&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;  (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; n : nat =&amp;gt;
     nat_ind
       (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; n0 : nat =&amp;gt; n0 + &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; = n0)
       ?Goal3
       (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; (n0 : nat) (IHn : n0 + &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; = n0) =&amp;gt; ?Goal4)
       n)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And Coq presents us two goals.&lt;/p&gt;
&lt;p&gt;First, we need to prove &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;P&lt;/mi&gt;&lt;mtext&gt;&amp;nbsp;&lt;/mtext&gt;&lt;mn&gt;0&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\mathrm{P}\ 0&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathrm&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, &lt;em&gt;i.e.&lt;/em&gt;,
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;0&lt;/mn&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mn&gt;0&lt;/mn&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;0&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;0 + 0 = 0&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7278em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. Similarly to Coq presenting a goal when what we are actually doing
is constructing a term, the use of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;=&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.3669em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;+&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; (&lt;em&gt;i.e.&lt;/em&gt;, the Coq notations
mechanism) hides much here. We can ask Coq to be more explicit by using the
vernacular command &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Printing&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;All&lt;/span&gt;&lt;/code&gt; to learn that when Coq presents us
a goal of the form &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; + &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;/code&gt;, it is actually looking for a term of type
&lt;code class=&quot;hljs language-coq&quot;&gt;@eq nat (Nat.add O O) O&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;Nat.add&lt;/code&gt; is a regular Coq (recursive) function.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;  &lt;span class=&quot;hljs-built_in&quot;&gt;fix&lt;/span&gt; add (n m : nat) {struct n} : nat :=
    &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; n &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
    | &lt;span class=&quot;hljs-type&quot;&gt;0&lt;/span&gt; =&amp;gt; m
    | &lt;span class=&quot;hljs-type&quot;&gt;S&lt;/span&gt; p =&amp;gt; S (add p m)
    &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Similarly, &lt;code class=&quot;hljs language-coq&quot;&gt;eq&lt;/code&gt; is &lt;em&gt;not&lt;/em&gt; an axiom. It is a regular inductive type, defined
as follows.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Inductive&lt;/span&gt; eq (A : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;) (x : A) : A -&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Prop&lt;/span&gt; :=
| &lt;span class=&quot;hljs-type&quot;&gt;eq_refl&lt;/span&gt; : eq A x x
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Coming back to our current goal, proving &lt;code class=&quot;hljs language-coq&quot;&gt;@eq nat (Nat.add &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;/code&gt;&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;That is, &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; + &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;/code&gt; &lt;/span&gt;
&lt;/span&gt;
requires to construct a term of a type whose only constructor is
&lt;code class=&quot;hljs language-coq&quot;&gt;eq_refl&lt;/code&gt;. &lt;code class=&quot;hljs language-coq&quot;&gt;eq_refl&lt;/code&gt; accepts one argument, and encodes the proof
that said argument is equal to itself. In practice, Coq type checker will accept
the term &lt;code class=&quot;hljs language-coq&quot;&gt;@eq_refl &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; x&lt;/code&gt; when it expects a term of type &lt;code class=&quot;hljs language-coq&quot;&gt;@eq &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; x y&lt;/code&gt;
&lt;em&gt;if&lt;/em&gt; it can reduce &lt;code class=&quot;hljs language-coq&quot;&gt;x&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;y&lt;/code&gt; to the same term.&lt;/p&gt;
&lt;p&gt;Is it the case for &lt;code class=&quot;hljs language-coq&quot;&gt;@eq nat (Nat.add &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;/code&gt;? It is, since by definition
of &lt;code class=&quot;hljs language-coq&quot;&gt;Nat.add&lt;/code&gt;, &lt;code class=&quot;hljs language-coq&quot;&gt;Nat.add &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; x&lt;/code&gt; is reduced to &lt;code class=&quot;hljs language-coq&quot;&gt;x&lt;/code&gt;. We can use the
&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;reflexivity&lt;/span&gt;&lt;/code&gt; tactic to tell Coq to fill the current hole with
&lt;code class=&quot;hljs language-coq&quot;&gt;eq_refl&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;  + &lt;span class=&quot;hljs-built_in&quot;&gt;reflexivity&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Suspicious readers may rely on &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Show&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;&lt;/code&gt; to verify this assertion.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;  (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; n : nat =&amp;gt;
     nat_ind
       (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; n0 : nat =&amp;gt; n0 + &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; = n0)
       eq_refl
       (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; (n0 : nat) (IHn : n0 + &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; = n0) =&amp;gt; ?Goal4)
       n)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;?Goal3&lt;/code&gt; has indeed be replaced by &lt;code class=&quot;hljs&quot;&gt;eq_refl&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;One goal remains, as we need to prove that if &lt;code class=&quot;hljs language-coq&quot;&gt;n + &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; = n&lt;/code&gt;, then &lt;code class=&quot;hljs language-coq&quot;&gt;S n + &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; = S n&lt;/code&gt;. Coq can reduce &lt;code class=&quot;hljs language-coq&quot;&gt;S n + &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;/code&gt; to &lt;code class=&quot;hljs language-coq&quot;&gt;S (n + &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)&lt;/code&gt; by definition
of &lt;code class=&quot;hljs language-coq&quot;&gt;Nat.add&lt;/code&gt;, but it cannot reduce &lt;code class=&quot;hljs language-coq&quot;&gt;S n&lt;/code&gt; more than it already is.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;  + &lt;span class=&quot;hljs-built_in&quot;&gt;cbn&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We cannot just use &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;reflexivity&lt;/span&gt;&lt;/code&gt; here (&lt;em&gt;i.e.&lt;/em&gt;, fill the hole with
&lt;code class=&quot;hljs language-coq&quot;&gt;eq_refl&lt;/code&gt;), since &lt;code class=&quot;hljs language-coq&quot;&gt;S (n + &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;S n&lt;/code&gt; cannot be reduced to
the same term.&lt;/p&gt;
&lt;p&gt;However, at this point of the proof, we have the &lt;code class=&quot;hljs language-coq&quot;&gt;IHn&lt;/code&gt; hypothesis (&lt;em&gt;i.e.&lt;/em&gt;, the
&lt;code class=&quot;hljs language-coq&quot;&gt;IHn&lt;/code&gt; argument of the anonymous function whose body we are trying to
construct). The &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt;&lt;/code&gt; tactic allows for substituting in a type an
occurrence of &lt;code class=&quot;hljs language-coq&quot;&gt;x&lt;/code&gt; by &lt;code class=&quot;hljs language-coq&quot;&gt;y&lt;/code&gt; as long as we have a proof of &lt;code class=&quot;hljs language-coq&quot;&gt;x = y&lt;/code&gt;. *)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; IHn.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Similarly to &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;induction&lt;/span&gt;&lt;/code&gt; using a dedicated function, &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt;&lt;/code&gt; refines
the current hole with the &lt;code class=&quot;hljs language-coq&quot;&gt;eq_ind_r&lt;/code&gt; function&lt;label for=&quot;fn2&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn2&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Again, not an axiom. &lt;/span&gt;
&lt;/span&gt;. Replacing &lt;code class=&quot;hljs language-coq&quot;&gt;n + &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;/code&gt; with &lt;code class=&quot;hljs language-coq&quot;&gt;n&lt;/code&gt; transforms the goal into &lt;code class=&quot;hljs language-coq&quot;&gt;S n = S n&lt;/code&gt;. Here, we
can use &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;reflexivity&lt;/span&gt;&lt;/code&gt; (i.e., &lt;code class=&quot;hljs language-coq&quot;&gt;eq_refl&lt;/code&gt;) to conclude. *)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;    &lt;span class=&quot;hljs-built_in&quot;&gt;reflexivity&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After this last tactic, the work is done. There is no more goal to fill inside
the proof term that we have carefully constructed.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;  (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; n : nat =&amp;gt;
     nat_ind
       (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; n0 : nat =&amp;gt; n0 + &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; = n0)
       eq_refl
       (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; (n0 : nat) (IHn : n0 + &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; = n0) =&amp;gt;
          eq_ind_r (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; n1 : nat =&amp;gt; S n1 = S n0) eq_refl IHn)
       n)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can finally use &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Qed&lt;/span&gt;&lt;/code&gt; or &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Defined&lt;/span&gt;&lt;/code&gt; to tell Coq to type check this
term. That is, Coq does not trust Ltac, but rather type check the term to
verify it is correct. This way, in case Ltac has a bug which makes it
construct an ill-formed type, at the very least Coq can reject it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Qed&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In conclusion, tactics are used to incrementally refine hole inside a term
until the latter is complete. They do it in a very specific manner, to
encode certain reasoning rules.&lt;/p&gt;
&lt;p&gt;On the other hand, the &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;refine&lt;/span&gt;&lt;/code&gt; tactic provides a generic, low-level way
to do the same thing. Knowing how a given tactic works allows for mimicking
its behavior using the &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;refine&lt;/span&gt;&lt;/code&gt; tactic.&lt;/p&gt;
&lt;p&gt;If we take the previous theorem as an example, we can prove it using this
alternative proof script.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Theorem&lt;/span&gt; add_n_O&apos; : &lt;span class=&quot;hljs-keyword&quot;&gt;forall&lt;/span&gt; (n : nat), n + O = n.
&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;.
  &lt;span class=&quot;hljs-built_in&quot;&gt;refine&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; n =&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt;).
  &lt;span class=&quot;hljs-built_in&quot;&gt;refine&lt;/span&gt; (nat_ind (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; n =&amp;gt; n + &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; = n) &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; n).
  + &lt;span class=&quot;hljs-built_in&quot;&gt;refine&lt;/span&gt; eq_refl.
  + &lt;span class=&quot;hljs-built_in&quot;&gt;refine&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; m IHm =&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt;).
    &lt;span class=&quot;hljs-built_in&quot;&gt;refine&lt;/span&gt; (eq_ind_r (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; n =&amp;gt; S n = S m) &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; IHm).
    &lt;span class=&quot;hljs-built_in&quot;&gt;refine&lt;/span&gt; eq_refl.
&lt;span class=&quot;hljs-keyword&quot;&gt;Qed&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>Mixing Ltac and Gallina for Fun and Profit</title>
      <link>https://soap.coffee/~lthms/posts/MixingLtacAndGallina.html</link>
      <guid>https://soap.coffee/~lthms/posts/MixingLtacAndGallina.html</guid>
      <pubDate>July 26, 2020</pubDate>
      <description>
        
        &lt;h1&gt;Mixing Ltac and Gallina for Fun and Profit&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/coq.html&quot; class=&quot;tag hover-periwinkle&quot; marked=&quot;&quot;&gt;coq&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;One of the most misleading introductions to Coq is to say that “Gallina is
for programs, while tactics are for proofs.”  Indeed, in Coq we construct
terms of given types, always. Terms encodes both programs and proofs about
these programs. Gallina is the preferred way to construct programs, and
tactics are the preferred way to construct proofs.&lt;/p&gt;
&lt;p&gt;The key word here is “preferred.” We do not always need to use tactics to
construct a proof term. Conversely, there are some occasions where
constructing a program with tactics become handy. Furthermore, Coq actually
allows for &lt;em&gt;mixing together&lt;/em&gt; Ltac and Gallina.&lt;/p&gt;
&lt;p&gt;In the &lt;a href=&quot;/~lthms/posts/LtacPatternMatching.html&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;previous article of this series&lt;/a&gt;, we
discuss how Ltac provides two very interesting features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;With &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; goal &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;&lt;/code&gt; it can inspect its context&lt;/li&gt;
&lt;li&gt;With &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; type of &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;&lt;/code&gt; it can pattern matches on types&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It turns out these features are more than handy when it comes to
metaprogramming (that is, the generation of programs by programs).&lt;/p&gt;
&lt;h2&gt;A Tale of Two Worlds, and Some Bridges&lt;/h2&gt;
&lt;p&gt;Constructing terms proofs directly in Gallina often happens when one is
writing dependently typed definition. For instance, we can write a type-safe
&lt;code class=&quot;hljs language-coq&quot;&gt;from_option&lt;/code&gt; function (inspired by &lt;a href=&quot;https://plv.csail.mit.edu/blog/unwrapping-options.html&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;this very nice
write-up&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;) such that
the option to unwrap shall be accompanied by a proof that said option contains
something. This extra argument is used in the &lt;code class=&quot;hljs language-coq&quot;&gt;None&lt;/code&gt; case to derive a
proof of &lt;code class=&quot;hljs language-coq&quot;&gt;False&lt;/code&gt;, from which we can derive
anything.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; is_some {α} (x : option α) : bool :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; x &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt; Some &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; =&amp;gt; true | &lt;span class=&quot;hljs-type&quot;&gt;None&lt;/span&gt; =&amp;gt; false &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;.

&lt;span class=&quot;hljs-keyword&quot;&gt;Lemma&lt;/span&gt; is_some_None {α} (x : option α)
  : x = None -&amp;gt; is_some x &amp;lt;&amp;gt; true.
&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;. &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; H. &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; H. &lt;span class=&quot;hljs-built_in&quot;&gt;discriminate&lt;/span&gt;. &lt;span class=&quot;hljs-keyword&quot;&gt;Qed&lt;/span&gt;.

&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; from_option {α}
    (x : option α) (some : is_some x = true)
  : α :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; x &lt;span class=&quot;hljs-built_in&quot;&gt;as&lt;/span&gt; y &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; x = y -&amp;gt; α &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;Some&lt;/span&gt; x =&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; =&amp;gt; x
  | &lt;span class=&quot;hljs-type&quot;&gt;None&lt;/span&gt; =&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; equ =&amp;gt; False_rect α (is_some_None x equ some)
  &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt; eq_refl.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In &lt;code class=&quot;hljs language-coq&quot;&gt;from_option&lt;/code&gt;, we construct two proofs without using tactics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;False_rect α (is_some_None x equ some)&lt;/code&gt; to exclude the absurd case&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;eq_refl&lt;/code&gt; in conjunction with a dependent pattern matching (if you are
not familiar with this trick: the main idea is to allow Coq to
“remember” that &lt;code class=&quot;hljs language-coq&quot;&gt;x = None&lt;/code&gt; in the second branch)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We can use another approach. We can decide to implement &lt;code class=&quot;hljs language-coq&quot;&gt;from_option&lt;/code&gt;
with a proof script.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; from_option&apos; {α}
    (x : option α) (some : is_some x = true)
  : α.
&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;.
  &lt;span class=&quot;hljs-built_in&quot;&gt;case_eq&lt;/span&gt; x.
  + &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; y &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt;.
    &lt;span class=&quot;hljs-built_in&quot;&gt;exact&lt;/span&gt; y.
  + &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; equ.
    &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; equ &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt; some.
    now &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; is_some_None &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt; some.
&lt;span class=&quot;hljs-keyword&quot;&gt;Defined&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is a third approach we can consider: mixing Gallina terms and tactics.
This is possible thanks to the &lt;code class=&quot;hljs language-coq&quot;&gt;ltac:()&lt;/code&gt; feature.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; from_option&apos;&apos; {α}
    (x : option α) (some : is_some x = true)
  : α :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; x &lt;span class=&quot;hljs-built_in&quot;&gt;as&lt;/span&gt; y &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; x = y -&amp;gt; α &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;Some&lt;/span&gt; x =&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; =&amp;gt; x
  | &lt;span class=&quot;hljs-type&quot;&gt;None&lt;/span&gt; =&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; equ =&amp;gt; ltac:(&lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; equ &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt; some;
                             now &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; is_some_None &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt; some)
  &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt; eq_refl.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When Coq encounters &lt;code class=&quot;hljs language-coq&quot;&gt;ltac:()&lt;/code&gt;, it treats it as a hole. It sets up a
corresponding goal, and tries to solve it with the supplied tactic.&lt;/p&gt;
&lt;p&gt;Conversely, there exists ways to construct terms in Gallina when writing a proof
script. Certain tactics take such terms as arguments. Besides, Ltac provides
&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;constr&lt;/span&gt;:()&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;uconstr:()&lt;/code&gt; which work similarly to
&lt;code class=&quot;hljs language-coq&quot;&gt;ltac:()&lt;/code&gt;. The difference between &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;constr&lt;/span&gt;:()&lt;/code&gt; and
&lt;code class=&quot;hljs language-coq&quot;&gt;uconstr:()&lt;/code&gt; is that Coq will try to assign a type to the argument of
&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;constr&lt;/span&gt;:()&lt;/code&gt;, but will leave the argument of &lt;code class=&quot;hljs language-coq&quot;&gt;uconstr:()&lt;/code&gt; untyped.&lt;/p&gt;
&lt;p&gt;For instance, consider the following tactic definition.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Tactic&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Notation&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;wrap_id&quot;&lt;/span&gt; uconstr(x) :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; f := uconstr:(&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; x =&amp;gt; x) &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt;
  &lt;span class=&quot;hljs-built_in&quot;&gt;exact&lt;/span&gt; (f x).
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both &lt;code class=&quot;hljs language-coq&quot;&gt;x&lt;/code&gt; the argument of &lt;code class=&quot;hljs language-coq&quot;&gt;wrap_id&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;f&lt;/code&gt; the anonymous identity function
are not typed. It is only when they are composed together as an argument of
&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;exact&lt;/span&gt;&lt;/code&gt; (which expects a typed argument, more precisely of the type of the
goal) that Coq actually tries to type check it.&lt;/p&gt;
&lt;p&gt;As a consequence, &lt;code class=&quot;hljs language-coq&quot;&gt;wrap_id&lt;/code&gt; generates a specialized identity function for
each specific context.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; zero : nat := ltac:(wrap_id &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;).
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The generated anonymous identity function is &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; x : nat =&amp;gt; x&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; empty_list α : list α := ltac:(wrap_id nil).
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The generated anonymous identity function is &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; x : list α =&amp;gt; x&lt;/code&gt;.
Besides, we do not need to give more type information about &lt;code class=&quot;hljs language-coq&quot;&gt;nil&lt;/code&gt;. If
&lt;code class=&quot;hljs language-coq&quot;&gt;wrap_id&lt;/code&gt; were to be expecting a typed term, we would have to replace
&lt;code class=&quot;hljs language-coq&quot;&gt;nil&lt;/code&gt; by [(@nil α)].&lt;/p&gt;
&lt;h2&gt;Beware the Automation Elephant in the Room&lt;/h2&gt;
&lt;p&gt;Proofs and computational programs are encoded in Coq as terms, but there is a
fundamental difference between them, and it is highlighted by one of the axioms
provided by the Coq standard library: proof irrelevance.&lt;/p&gt;
&lt;p&gt;Proof irrelevance states that two proofs of the same theorem (i.e., two proof
terms which share the same type) are essentially equivalent, and can be
substituted without threatening the trustworthiness of the system. From a
formal methods point of view, it makes sense. Even if we value “beautiful
proofs,” we mostly want correct proofs.&lt;/p&gt;
&lt;p&gt;The same reasoning does &lt;em&gt;not&lt;/em&gt; apply to computational programs. Two functions of
type &lt;code class=&quot;hljs language-coq&quot;&gt;nat -&amp;gt; nat -&amp;gt; nat&lt;/code&gt; are unlikely to be equivalent.  For instance,
&lt;code class=&quot;hljs language-coq&quot;&gt;add&lt;/code&gt;, &lt;code class=&quot;hljs language-coq&quot;&gt;mul&lt;/code&gt; or &lt;code class=&quot;hljs language-coq&quot;&gt;sub&lt;/code&gt; share the same type, but computes
totally different results.&lt;/p&gt;
&lt;p&gt;Using tactics such as &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;auto&lt;/span&gt;&lt;/code&gt; to generate terms which do not live inside
&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Prop&lt;/span&gt;&lt;/code&gt; is risky, to say the least. For instance,&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; add (x y : nat) : nat := ltac:(&lt;span class=&quot;hljs-built_in&quot;&gt;auto&lt;/span&gt;).
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works, but it is certainly not what you would expect:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;add = &lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; y : nat =&amp;gt; y
     : nat -&amp;gt; nat -&amp;gt; nat
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That being said, if we keep that in mind, and assert the correctness of the
generated programs (either by providing a proof, or by extensively testing it),
there is no particular reason not to use Ltac to generate terms when it makes
sense.&lt;/p&gt;
&lt;p&gt;Dependently typed programming can help you here. If we decorate the return type of
a function with the expected properties of the result wrt. the function’s
arguments, we can ensure the function is correct, and conversely prevent tactics
such as &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;auto&lt;/span&gt;&lt;/code&gt; to generate “incorrect” terms. Interested readers may
refer to &lt;a href=&quot;/~lthms/posts/StronglySpecifiedFunctions.html&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;the dedicated series on this very
website&lt;/a&gt;.&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>Proving Algebraic Datatypes are “Algebraic”</title>
      <link>https://soap.coffee/~lthms/posts/AlgebraicDatatypes.html</link>
      <guid>https://soap.coffee/~lthms/posts/AlgebraicDatatypes.html</guid>
      <pubDate>July 12, 2020</pubDate>
      <description>
        
        &lt;h1&gt;Proving Algebraic Datatypes are “Algebraic”&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/coq.html&quot; class=&quot;tag hover-periwinkle&quot; marked=&quot;&quot;&gt;coq&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;Several programming languages allow programmers to define (potentially
recursive) custom types, by composing together existing ones. For instance, in
OCaml, one can define lists as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt; =
| &lt;span class=&quot;hljs-type&quot;&gt;Cons&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; * &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;
| &lt;span class=&quot;hljs-type&quot;&gt;Nil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This translates in Haskell as&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;List&lt;/span&gt; a =&lt;/span&gt;
  &lt;span class=&quot;hljs-type&quot;&gt;Cons&lt;/span&gt; a (&lt;span class=&quot;hljs-type&quot;&gt;List&lt;/span&gt; a)
| &lt;span class=&quot;hljs-type&quot;&gt;Nil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In Rust as&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-rust&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;List&lt;/span&gt;&amp;lt;A&amp;gt; {
  &lt;span class=&quot;hljs-title function_ invoke__&quot;&gt;Cons&lt;/span&gt;(A, &lt;span class=&quot;hljs-type&quot;&gt;Box&lt;/span&gt;&amp;lt;List&amp;lt;a&amp;gt;&amp;gt;),
  Nil,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or in Coq as&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Inductive&lt;/span&gt; list a :=
| &lt;span class=&quot;hljs-type&quot;&gt;cons&lt;/span&gt; : a -&amp;gt; list a -&amp;gt; list a
| &lt;span class=&quot;hljs-type&quot;&gt;nil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And so forth.&lt;/p&gt;
&lt;p&gt;Each language will have its own specific constructions, and the type systems
of OCaml, Haskell, Rust and Coq —to only cite them— are far from being
equivalent. That being said, they often share a common “base formalism,”
usually (and sometimes abusively) referred to as &lt;em&gt;algebraic datatypes&lt;/em&gt;. This
expression is used because under the hood any datatype can be encoded as a
composition of types using two operators: sum (&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;+&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;) and product (&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;*&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4653em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∗&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;) for
types.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;a + b&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is the disjoint union of types &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;a&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;b&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. Any term of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;a&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
can be injected into &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;a + b&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, and the same goes for &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;b&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. Conversely,
a term of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;a + b&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; can be projected into either &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;a&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; or &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;b&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;a * b&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4653em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is the Cartesian product of types &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;a&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;b&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. Any term of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;a *
b&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4653em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is made of one term of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;a&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and one term of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;b&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; (think tuples).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For an algebraic datatype, one constructor allows for defining “named
tuples,” that is ad hoc product types. Besides, constructors are mutually
exclusive: you cannot define the same term using two different constructors.
Therefore, a datatype with several constructors is reminiscent of a disjoint
union.  Coming back to the &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;l&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;i&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;s&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;t&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\mathrm{list}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathrm&quot;&gt;list&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; type, under the syntactic sugar of
algebraic datatypes, we can define it as&lt;/p&gt;
&lt;p class=&quot;katex-block&quot;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;l&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;i&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;s&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;t&lt;/mi&gt;&lt;/mrow&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;/msub&gt;&lt;mo&gt;≡&lt;/mo&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;u&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;n&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;i&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;t&lt;/mi&gt;&lt;/mrow&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;msub&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;l&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;i&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;s&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;t&lt;/mi&gt;&lt;/mrow&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\mathrm{list}_\alpha \equiv \mathrm{unit} + \alpha * \mathrm{list}_\alpha
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8444em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathrm&quot;&gt;list&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;≡&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7512em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathrm&quot;&gt;unit&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4653em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8444em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathrm&quot;&gt;list&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;where &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;u&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;n&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;i&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;t&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\mathrm{unit}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6679em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathrm&quot;&gt;unit&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; models the &lt;code class=&quot;hljs language-coq&quot;&gt;nil&lt;/code&gt; case, and &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;msub&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;l&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;i&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;s&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;t&lt;/mi&gt;&lt;/mrow&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;α * \mathrm{list}_\alpha&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4653em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8444em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathrm&quot;&gt;list&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
models the &lt;code class=&quot;hljs language-coq&quot;&gt;cons&lt;/code&gt; case.&lt;/p&gt;
&lt;p&gt;The set of types which can be defined in a language together with &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;+&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;*&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4653em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∗&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; form an “algebraic structure” in the mathematical sense, hence the
name. It means the definitions of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;+&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;*&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4653em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∗&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; have to satisfy properties
such as commutativity or the existence of neutral elements. In this article,
we will prove some of them in Coq. More precisely,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;+&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is commutative, that is &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;∀&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mtext&gt;&amp;nbsp;&lt;/mtext&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\forall (x, y),\ x + y = y + x&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∀&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7778em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;+&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is associative, that is &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;∀&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;z&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mtext&gt;&amp;nbsp;&lt;/mtext&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mi&gt;z&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mi&gt;z&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\forall (x, y, z),\ (x + y) + z = x + (y + z)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∀&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.04398em;&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.04398em;&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.04398em;&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;+&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; has a neutral element, that is &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;∃&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;/msub&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mtext&gt;&amp;nbsp;&lt;/mtext&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;∀&lt;/mi&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mtext&gt;&amp;nbsp;&lt;/mtext&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;/msub&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\exists e_s,\ \forall x,\ x + e_s = x&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∃&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∀&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.5806em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;*&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4653em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∗&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is commutative, that is &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;∀&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mtext&gt;&amp;nbsp;&lt;/mtext&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\forall (x, y),\ x * y = y * x&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∀&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6597em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;*&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4653em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∗&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is associative, that is &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;∀&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;z&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mtext&gt;&amp;nbsp;&lt;/mtext&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mi&gt;z&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mi&gt;z&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\forall (x, y, z),\ (x * y) * z = x * (y * z)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∀&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.04398em;&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.04398em;&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4653em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.04398em;&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;*&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4653em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∗&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; has a neutral element, that is &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;∃&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;/msub&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mtext&gt;&amp;nbsp;&lt;/mtext&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;∀&lt;/mi&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mtext&gt;&amp;nbsp;&lt;/mtext&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;/msub&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\exists e_p,\ \forall x,\ x * e_p = x&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.9805em;vertical-align:-0.2861em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∃&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2861em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∀&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7167em;vertical-align:-0.2861em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2861em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;The distributivity of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;+&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;*&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4653em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∗&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, that is &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;∀&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;z&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mtext&gt;&amp;nbsp;&lt;/mtext&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mi&gt;z&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mi&gt;z&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\forall
(x, y, z),\ x * (y + z) = x * y + x * z&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∀&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.04398em;&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.04398em;&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4653em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7778em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4653em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.04398em;&quot;&gt;z&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;*&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4653em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∗&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; has an absorbing element, that is &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;∃&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;/msub&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mtext&gt;&amp;nbsp;&lt;/mtext&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;∀&lt;/mi&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mtext&gt;&amp;nbsp;&lt;/mtext&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;/msub&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\exists e_a,\ \forall x, \ x * e_a = e_a&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∃&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∀&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.5806em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.5806em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the record, the &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;sum&lt;/span&gt;&lt;/code&gt; (&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;+&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;) and &lt;code class=&quot;hljs language-coq&quot;&gt;prod&lt;/code&gt; (&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;*&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4653em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∗&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;) types are defined
in Coq as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Inductive&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;sum&lt;/span&gt; (A B : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;) : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt; :=
| &lt;span class=&quot;hljs-type&quot;&gt;inl&lt;/span&gt; : A -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;sum&lt;/span&gt; A B
| &lt;span class=&quot;hljs-type&quot;&gt;inr&lt;/span&gt; : B -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;sum&lt;/span&gt; A B

&lt;span class=&quot;hljs-keyword&quot;&gt;Inductive&lt;/span&gt; prod (A B : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;) : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt; :=
| &lt;span class=&quot;hljs-type&quot;&gt;pair&lt;/span&gt; : A -&amp;gt; B -&amp;gt; prod A B
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;An Equivalence for &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Algebraic structures come with &lt;em&gt;equations&lt;/em&gt; expected to be true.  This means
there is an implicit dependency which is —to my opinion— too easily overlooked:
the definition of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;=&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.3669em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. In Coq, &lt;code class=&quot;hljs language-coq&quot;&gt;=&lt;/code&gt; is a built-in relation that states
that two terms are “equal” if they can be reduced to the same “hierarchy” of
constructors. This is too strong in the general case, and in particular for our
study of algebraic structures of &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;&lt;/code&gt;. It is clear that, to Coq’s
opinion, &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mi&gt;β&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\alpha + \beta&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.05278em;&quot;&gt;β&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is not structurally &lt;em&gt;equal&lt;/em&gt; to &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;β&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\beta + \alpha&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.05278em;&quot;&gt;β&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, yet
we will have to prove they are “equivalent.”&lt;/p&gt;
&lt;h3&gt;Introducing &lt;code class=&quot;hljs language-coq&quot;&gt;type_equiv&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Since &lt;code class=&quot;hljs language-coq&quot;&gt;=&lt;/code&gt; for &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;&lt;/code&gt; is not suitable for reasoning about algebraic
datatypes, we introduce our own equivalence relation, denoted &lt;code class=&quot;hljs language-coq&quot;&gt;==&lt;/code&gt;.  We
say two types &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\alpha&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;β&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\beta&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.05278em;&quot;&gt;β&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; are equivalent up to an isomorphism
when for any term of type &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\alpha&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, there exists a counterpart term of type
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;β&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\beta&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.05278em;&quot;&gt;β&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and vice versa. In other words, &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\alpha&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;β&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\beta&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.05278em;&quot;&gt;β&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; are equivalent if
we can exhibit two functions &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;f&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.10764em;&quot;&gt;f&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;g&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; such that:&lt;/p&gt;
&lt;p class=&quot;katex-block&quot;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;∀&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo&gt;:&lt;/mo&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mtext&gt;&amp;nbsp;&lt;/mtext&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\forall (x : α),\ x = g(f(x))
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∀&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.10764em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;katex-block&quot;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;∀&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo&gt;:&lt;/mo&gt;&lt;mi&gt;β&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mtext&gt;&amp;nbsp;&lt;/mtext&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\forall (y : β),\ y = f(g(y))
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∀&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.05278em;&quot;&gt;β&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.10764em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;This translates into the following inductive type.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Reserved&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Notation&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;x == y&quot;&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;at&lt;/span&gt; level &lt;span class=&quot;hljs-number&quot;&gt;72&lt;/span&gt;).

&lt;span class=&quot;hljs-keyword&quot;&gt;Inductive&lt;/span&gt; type_equiv (α β : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;) : &lt;span class=&quot;hljs-keyword&quot;&gt;Prop&lt;/span&gt; :=
| &lt;span class=&quot;hljs-type&quot;&gt;mk_type_equiv&lt;/span&gt; (f : α -&amp;gt; β) (g : β -&amp;gt; α)
                (equ1 : &lt;span class=&quot;hljs-keyword&quot;&gt;forall&lt;/span&gt; (x : α), x = g (f x))
                (equ2 : &lt;span class=&quot;hljs-keyword&quot;&gt;forall&lt;/span&gt; (y : β), y = f (g y))
  : α == β
&lt;span class=&quot;hljs-keyword&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;x == y&quot;&lt;/span&gt; := (type_equiv x y).
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As mentioned earlier, we prove two types are equivalent by exhibiting
two functions, and proving these functions satisfy two properties. We
introduce a &lt;code class=&quot;hljs&quot;&gt;Ltac&lt;/code&gt; notation to that end.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Tactic&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Notation&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;equiv&quot;&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;with&quot;&lt;/span&gt; uconstr(f) &lt;span class=&quot;hljs-string&quot;&gt;&quot;and&quot;&lt;/span&gt; uconstr(g)
  := &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; (mk_type_equiv f g).
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The tactic &lt;code class=&quot;hljs language-coq&quot;&gt;equiv &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt; f and g&lt;/code&gt; will turn a goal of the form &lt;code class=&quot;hljs language-coq&quot;&gt;α == β&lt;/code&gt; into two subgoals to prove &lt;code class=&quot;hljs&quot;&gt;f&lt;/code&gt; and &lt;code class=&quot;hljs&quot;&gt;g&lt;/code&gt; form an isomorphism.&lt;/p&gt;
&lt;h3&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;type_equiv&lt;/code&gt; is an Equivalence&lt;/h3&gt;
&lt;p&gt;We can prove it by demonstrating it is&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Reflexive,&lt;/li&gt;
&lt;li&gt;Symmetric, and&lt;/li&gt;
&lt;li&gt;Transitive.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;type_equiv&lt;/code&gt; is reflexive&lt;/h4&gt;
&lt;p&gt;This proof is straightforward. A type &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\alpha&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is equivalent to itself because:&lt;/p&gt;
&lt;p class=&quot;katex-block&quot;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;∀&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo&gt;:&lt;/mo&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mtext&gt;&amp;nbsp;&lt;/mtext&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\forall (x : α),\ x = id(id(x))
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∀&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Lemma&lt;/span&gt; type_equiv_refl (α : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;) : α == α.
&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;.
  now equiv &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt; (@id α) and (@id α).
&lt;span class=&quot;hljs-keyword&quot;&gt;Qed&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;type_equiv&lt;/code&gt; is symmetric&lt;/h4&gt;
&lt;p&gt;If &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;β&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\alpha = \beta&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.05278em;&quot;&gt;β&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, then we know there exists two functions &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;f&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.10764em;&quot;&gt;f&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;g&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; which
satisfy the expected properties. We can “swap” them to prove that &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;β&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\beta ==
\alpha&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.05278em;&quot;&gt;β&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Lemma&lt;/span&gt; type_equiv_sym {α β} (equ : α == β) : β == α.
&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;.
  &lt;span class=&quot;hljs-built_in&quot;&gt;destruct&lt;/span&gt; equ &lt;span class=&quot;hljs-built_in&quot;&gt;as&lt;/span&gt; [f g equ1 equ2].
  now equiv &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt; g and f.
&lt;span class=&quot;hljs-keyword&quot;&gt;Qed&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;type_equiv&lt;/code&gt; is transitive&lt;/h4&gt;
&lt;p&gt;If &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;β&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\alpha = \beta&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.05278em;&quot;&gt;β&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, we know there exists two functions &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;f_\alpha&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.10764em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.1076em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;β&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;g_\beta&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7167em;vertical-align:-0.2861em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.05278em;&quot;&gt;β&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2861em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; which satisfy the expected properties of &lt;code class=&quot;hljs language-coq&quot;&gt;type_equiv&lt;/code&gt;.
Similarly, because &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;β&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;γ&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\beta = \gamma&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.05278em;&quot;&gt;β&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.05556em;&quot;&gt;γ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;,
we know there exists two additional functions &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mi&gt;β&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;f_\beta&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.9805em;vertical-align:-0.2861em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.10764em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.1076em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.05278em;&quot;&gt;β&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2861em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;γ&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;g_\gamma&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7167em;vertical-align:-0.2861em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.05556em;&quot;&gt;γ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2861em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. We can
compose these functions together to prove &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;γ&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\alpha = \gamma&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.05556em;&quot;&gt;γ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;As a reminder, composing two functions &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;f&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.10764em;&quot;&gt;f&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;g&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; (denoted by &lt;code class=&quot;hljs language-coq&quot;&gt;f &amp;gt;&amp;gt;&amp;gt; g&lt;/code&gt;
thereafter) consists in using the result of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;f&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.10764em;&quot;&gt;f&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; as the input of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;g&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Infix&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;&amp;gt;&amp;gt;&amp;gt;&quot;&lt;/span&gt; := (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; f g x =&amp;gt; g (f x)) (&lt;span class=&quot;hljs-built_in&quot;&gt;at&lt;/span&gt; level &lt;span class=&quot;hljs-number&quot;&gt;70&lt;/span&gt;).

&lt;span class=&quot;hljs-keyword&quot;&gt;Lemma&lt;/span&gt; type_equiv_trans {α β γ} (equ1 : α == β) (equ2 : β == γ)
  : α == γ.
&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;.
  &lt;span class=&quot;hljs-built_in&quot;&gt;destruct&lt;/span&gt; equ1 &lt;span class=&quot;hljs-built_in&quot;&gt;as&lt;/span&gt; [fα gβ equαβ equβα],
           equ2 &lt;span class=&quot;hljs-built_in&quot;&gt;as&lt;/span&gt; [fβ gγ equβγ equγβ].
  equiv &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt; (fα &amp;gt;&amp;gt;&amp;gt; fβ) and (gγ &amp;gt;&amp;gt;&amp;gt; gβ).
  + &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; x.
    &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; &amp;lt;- equβγ.
    now &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; &amp;lt;- equαβ.
  + &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; x.
    &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; &amp;lt;- equβα.
    now &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; &amp;lt;- equγβ.
&lt;span class=&quot;hljs-keyword&quot;&gt;Qed&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;The Coq standard library introduces the &lt;code class=&quot;hljs language-coq&quot;&gt;Equivalence&lt;/code&gt; type class. We can
provide an instance of this type class for &lt;code class=&quot;hljs language-coq&quot;&gt;type_equiv&lt;/code&gt;, using the three
lemmas we have proven in this section.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;#[&lt;span class=&quot;hljs-built_in&quot;&gt;refine&lt;/span&gt;]
&lt;span class=&quot;hljs-keyword&quot;&gt;Instance&lt;/span&gt; type_equiv_Equivalence : Equivalence type_equiv :=
  {}.

&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;.
  + &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; x.
    &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; type_equiv_refl.
  + &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; x y.
    &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; type_equiv_sym.
  + &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; x y z.
    &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; type_equiv_trans.
&lt;span class=&quot;hljs-keyword&quot;&gt;Qed&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Examples&lt;/h3&gt;
&lt;h4&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;list&lt;/code&gt;’s canonical form&lt;/h4&gt;
&lt;p&gt;We now come back to our initial example, given in the introduction of this
write-up. We can prove our assertion, that is &lt;code class=&quot;hljs language-coq&quot;&gt;list α == unit + α * list α&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Lemma&lt;/span&gt; list_equiv (α : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;)
  : list α == unit + α * list α.

&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;.
  equiv &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; x =&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; x &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
                       | &lt;span class=&quot;hljs-type&quot;&gt;[] =&amp;gt; inl&lt;/span&gt; tt
                       | &lt;span class=&quot;hljs-type&quot;&gt;x&lt;/span&gt; :: rst =&amp;gt; inr (x, rst)
                       &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;)
         and (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; x =&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; x &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
                       | &lt;span class=&quot;hljs-type&quot;&gt;inl&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; =&amp;gt; []
                       | &lt;span class=&quot;hljs-type&quot;&gt;inr&lt;/span&gt; (x, rst) =&amp;gt; x :: rst
                       &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;).
  + now &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; [| &lt;span class=&quot;hljs-type&quot;&gt;x&lt;/span&gt; rst].
  + now &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; [[] | &lt;span class=&quot;hljs-type&quot;&gt;[x&lt;/span&gt; rst]].
&lt;span class=&quot;hljs-keyword&quot;&gt;Qed&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;list&lt;/code&gt; is a morphism&lt;/h4&gt;
&lt;p&gt;This means that if &lt;code class=&quot;hljs language-coq&quot;&gt;α == β&lt;/code&gt;, then &lt;code class=&quot;hljs language-coq&quot;&gt;list α == list β&lt;/code&gt;. We prove this
by defining an instance of the &lt;code class=&quot;hljs language-coq&quot;&gt;Proper&lt;/code&gt; type class.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Instance&lt;/span&gt; list_Proper
  : Proper (type_equiv ==&amp;gt; type_equiv) list.

&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;.
  add_morphism_tactic.
  &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; α β [f g equαβ equβα].
  equiv &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt; (map f) and (map g).
  all: &lt;span class=&quot;hljs-built_in&quot;&gt;setoid_rewrite&lt;/span&gt; map_map; &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; l.
  + &lt;span class=&quot;hljs-built_in&quot;&gt;replace&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; x : α =&amp;gt; g (f x))
       &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt; (@id α).
    ++ &lt;span class=&quot;hljs-built_in&quot;&gt;symmetry&lt;/span&gt;; &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; map_id.
    ++ &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; functional_extensionality.
       &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; equαβ.
  + &lt;span class=&quot;hljs-built_in&quot;&gt;replace&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; x : β =&amp;gt; f (g x))
       &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt; (@id β).
    ++ &lt;span class=&quot;hljs-built_in&quot;&gt;symmetry&lt;/span&gt;; &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; map_id.
    ++ &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; functional_extensionality.
       &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; equβα.
&lt;span class=&quot;hljs-keyword&quot;&gt;Qed&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The use of the &lt;code class=&quot;hljs language-coq&quot;&gt;Proper&lt;/code&gt; type class allows for leveraging hypotheses of
the form &lt;code class=&quot;hljs language-coq&quot;&gt;α == β&lt;/code&gt; with the &lt;code class=&quot;hljs&quot;&gt;rewrite&lt;/code&gt; tactic. I personally consider
providing instances of &lt;code class=&quot;hljs language-coq&quot;&gt;Proper&lt;/code&gt; whenever it is possible to be a good
practice, and would encourage any Coq programmers to do so.&lt;/p&gt;
&lt;h4&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;nat&lt;/code&gt; is a special purpose &lt;code class=&quot;hljs&quot;&gt;list&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;Did you notice? Now, using &lt;code class=&quot;hljs language-coq&quot;&gt;type_equiv&lt;/code&gt;, we can prove it!&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Lemma&lt;/span&gt; nat_and_list : nat == list unit.
&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;.
  equiv &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;fix&lt;/span&gt; to_list n :=
                &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; n &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
                | &lt;span class=&quot;hljs-type&quot;&gt;S&lt;/span&gt; m =&amp;gt; tt :: to_list m
                | &lt;span class=&quot;hljs-type&quot;&gt;_&lt;/span&gt; =&amp;gt; []
                &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;)
         and (&lt;span class=&quot;hljs-built_in&quot;&gt;fix&lt;/span&gt; of_list l :=
                &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; l &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
                | &lt;span class=&quot;hljs-type&quot;&gt;_&lt;/span&gt; :: rst =&amp;gt; S (of_list rst)
                | &lt;span class=&quot;hljs-type&quot;&gt;_&lt;/span&gt; =&amp;gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;).
  + &lt;span class=&quot;hljs-built_in&quot;&gt;induction&lt;/span&gt; x; &lt;span class=&quot;hljs-built_in&quot;&gt;auto&lt;/span&gt;.
  + &lt;span class=&quot;hljs-built_in&quot;&gt;induction&lt;/span&gt; y; &lt;span class=&quot;hljs-built_in&quot;&gt;auto&lt;/span&gt;.
    &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; &amp;lt;- IHy.
    now &lt;span class=&quot;hljs-built_in&quot;&gt;destruct&lt;/span&gt; a.
&lt;span class=&quot;hljs-keyword&quot;&gt;Qed&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Non-empty lists&lt;/h4&gt;
&lt;p&gt;We can introduce a variant of &lt;code class=&quot;hljs language-coq&quot;&gt;list&lt;/code&gt; which contains at least one element
by modifying the &lt;code class=&quot;hljs language-coq&quot;&gt;nil&lt;/code&gt; constructor so that it takes one argument instead
of none.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Inductive&lt;/span&gt; non_empty_list (α : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;) :=
| &lt;span class=&quot;hljs-type&quot;&gt;ne_cons&lt;/span&gt; : α -&amp;gt; non_empty_list α -&amp;gt; non_empty_list α
| &lt;span class=&quot;hljs-type&quot;&gt;ne_singleton&lt;/span&gt; : α -&amp;gt; non_empty_list α.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can demonstrate the relation between &lt;code class=&quot;hljs language-coq&quot;&gt;list&lt;/code&gt; and
&lt;code class=&quot;hljs language-coq&quot;&gt;non_empty_list&lt;/code&gt;, which reveals an alternative implementation of
&lt;code class=&quot;hljs language-coq&quot;&gt;non_empty_list&lt;/code&gt;. More precisely, we can prove that &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;forall&lt;/span&gt; (α : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;), non_empty_list α == α * list α&lt;/code&gt;. It is a bit more cumbersome, but not that
much. We first define the conversion functions, then prove they satisfy the
properties expected by &lt;code class=&quot;hljs language-coq&quot;&gt;type_equiv&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Fixpoint&lt;/span&gt; non_empty_list_of_list {α} (x : α) (l : list α)
  : non_empty_list α :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; l &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;y&lt;/span&gt; :: rst =&amp;gt; ne_cons x (non_empty_list_of_list y rst)
  | &lt;span class=&quot;hljs-type&quot;&gt;[] =&amp;gt; ne_singleton&lt;/span&gt; x
  &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;.

#[local]
&lt;span class=&quot;hljs-keyword&quot;&gt;Fixpoint&lt;/span&gt; list_of_non_empty_list {α} (l : non_empty_list α)
  : list α :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; l &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;ne_cons&lt;/span&gt; x rst =&amp;gt; x :: list_of_non_empty_list rst
  | &lt;span class=&quot;hljs-type&quot;&gt;ne_singleton&lt;/span&gt; x =&amp;gt; [x]
  &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;.

&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; list_of_non_empty_list {α} (l : non_empty_list α)
  : α * list α :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; l &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;ne_singleton&lt;/span&gt; x =&amp;gt; (x, [])
  | &lt;span class=&quot;hljs-type&quot;&gt;ne_cons&lt;/span&gt; x rst =&amp;gt; (x, list_of_non_empty_list rst)
  &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;.

&lt;span class=&quot;hljs-keyword&quot;&gt;Lemma&lt;/span&gt; ne_list_list_equiv (α : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;)
  : non_empty_list α == α * list α.

&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;.
  equiv &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt; list_of_non_empty_list
         and (prod_curry non_empty_list_of_list).
  + &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; [x rst|&lt;span class=&quot;hljs-type&quot;&gt;x&lt;/span&gt;]; &lt;span class=&quot;hljs-built_in&quot;&gt;auto&lt;/span&gt;.
    &lt;span class=&quot;hljs-built_in&quot;&gt;cbn&lt;/span&gt;.
    &lt;span class=&quot;hljs-built_in&quot;&gt;revert&lt;/span&gt; x.
    &lt;span class=&quot;hljs-built_in&quot;&gt;induction&lt;/span&gt; rst; &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; x; &lt;span class=&quot;hljs-built_in&quot;&gt;auto&lt;/span&gt;.
    &lt;span class=&quot;hljs-built_in&quot;&gt;cbn&lt;/span&gt;; now &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; IHrst.
  + &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; [x rst].
    &lt;span class=&quot;hljs-built_in&quot;&gt;cbn&lt;/span&gt;.
    &lt;span class=&quot;hljs-built_in&quot;&gt;destruct&lt;/span&gt; rst; &lt;span class=&quot;hljs-built_in&quot;&gt;auto&lt;/span&gt;.
    &lt;span class=&quot;hljs-built_in&quot;&gt;change&lt;/span&gt; (non_empty_list_of_list x (α&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; :: rst))
      &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt; (ne_cons x (non_empty_list_of_list α&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; rst)).
    &lt;span class=&quot;hljs-built_in&quot;&gt;replace&lt;/span&gt; (α&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; :: rst)
      &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt; (list_of_non_empty_list
              (non_empty_list_of_list α&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; rst)); &lt;span class=&quot;hljs-built_in&quot;&gt;auto&lt;/span&gt;.
    &lt;span class=&quot;hljs-built_in&quot;&gt;revert&lt;/span&gt; α&lt;span class=&quot;hljs-number&quot;&gt;0.&lt;/span&gt;
    &lt;span class=&quot;hljs-built_in&quot;&gt;induction&lt;/span&gt; rst; &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; y; [ &lt;span class=&quot;hljs-built_in&quot;&gt;reflexivity&lt;/span&gt; | &lt;span class=&quot;hljs-type&quot;&gt;cbn&lt;/span&gt; ].
    now &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; IHrst.
&lt;span class=&quot;hljs-keyword&quot;&gt;Qed&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;The &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;sum&lt;/span&gt;&lt;/code&gt; Operator&lt;/h2&gt;
&lt;h3&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;sum&lt;/span&gt;&lt;/code&gt; Is a Morphism&lt;/h3&gt;
&lt;p&gt;To prove this, we compose together the functions whose existence is implied by
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msup&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;mo mathvariant=&quot;normal&quot; lspace=&quot;0em&quot; rspace=&quot;0em&quot;&gt;′&lt;/mo&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\alpha = \alpha&apos;&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7519em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.7519em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;′&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;β&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msup&gt;&lt;mi&gt;β&lt;/mi&gt;&lt;mo mathvariant=&quot;normal&quot; lspace=&quot;0em&quot; rspace=&quot;0em&quot;&gt;′&lt;/mo&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\beta = \beta&apos;&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.05278em;&quot;&gt;β&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.9463em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.05278em;&quot;&gt;β&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.7519em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;′&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. To that end, we introduce the
auxiliary function &lt;code class=&quot;hljs language-coq&quot;&gt;lr_map&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; lr_map_sum {α β α&apos; β&apos;} (f : α -&amp;gt; α&apos;) (g : β -&amp;gt; β&apos;)
    (x : α + β)
  : α&apos; + β&apos; :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; x &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;inl&lt;/span&gt; x =&amp;gt; inl (f x)
  | &lt;span class=&quot;hljs-type&quot;&gt;inr&lt;/span&gt; y =&amp;gt; inr (g y)
  &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we prove &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;sum&lt;/span&gt;&lt;/code&gt; is a morphism by defining a &lt;code class=&quot;hljs language-coq&quot;&gt;Proper&lt;/code&gt; instance.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Instance&lt;/span&gt; sum_Proper
  : Proper (type_equiv ==&amp;gt; type_equiv ==&amp;gt; type_equiv) &lt;span class=&quot;hljs-built_in&quot;&gt;sum&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;.
  add_morphism_tactic.
  &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; α α&apos; [fα gα&apos; equαα&apos; equα&apos;α]
         β β&apos; [fβ gβ&apos; equββ&apos; equβ&apos;β].
  equiv &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt; (lr_map_sum fα fβ)
         and (lr_map_sum gα&apos; gβ&apos;).
  + &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; [x|&lt;span class=&quot;hljs-type&quot;&gt;y&lt;/span&gt;]; &lt;span class=&quot;hljs-built_in&quot;&gt;cbn&lt;/span&gt;.
    ++ now &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; &amp;lt;- equαα&apos;.
    ++ now &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; &amp;lt;- equββ&apos;.
  + &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; [x|&lt;span class=&quot;hljs-type&quot;&gt;y&lt;/span&gt;]; &lt;span class=&quot;hljs-built_in&quot;&gt;cbn&lt;/span&gt;.
    ++ now &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; &amp;lt;- equα&apos;α.
    ++ now &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; &amp;lt;- equβ&apos;β.
&lt;span class=&quot;hljs-keyword&quot;&gt;Qed&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;sum&lt;/span&gt;&lt;/code&gt; Is Commutative&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; sum_invert {α β} (x : α + β) : β + α :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; x &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;inl&lt;/span&gt; x =&amp;gt; inr x
  | &lt;span class=&quot;hljs-type&quot;&gt;inr&lt;/span&gt; x =&amp;gt; inl x
  &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;.

&lt;span class=&quot;hljs-keyword&quot;&gt;Lemma&lt;/span&gt; sum_com {α β} : α + β == β + α.
&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;.
  equiv &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt; sum_invert and sum_invert;
    now &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; [x|&lt;span class=&quot;hljs-type&quot;&gt;x&lt;/span&gt;].
&lt;span class=&quot;hljs-keyword&quot;&gt;Qed&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;sum&lt;/span&gt;&lt;/code&gt; Is Associative&lt;/h3&gt;
&lt;p&gt;The associativity of &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;sum&lt;/span&gt;&lt;/code&gt; is straightforward to prove, and should not
pose a particular challenge to prospective readers&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;If we assume that this article is well written, that is. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Lemma&lt;/span&gt; sum_assoc {α β γ} : α + β + γ == α + (β + γ).
&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;.
  equiv &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; x =&amp;gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; x &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
                | &lt;span class=&quot;hljs-type&quot;&gt;inl&lt;/span&gt; (inl x) =&amp;gt; inl x
                | &lt;span class=&quot;hljs-type&quot;&gt;inl&lt;/span&gt; (inr x) =&amp;gt; inr (inl x)
                | &lt;span class=&quot;hljs-type&quot;&gt;inr&lt;/span&gt; x =&amp;gt; inr (inr x)
                &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;)
         and (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; x =&amp;gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; x &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
                | &lt;span class=&quot;hljs-type&quot;&gt;inl&lt;/span&gt; x =&amp;gt; inl (inl x)
                | &lt;span class=&quot;hljs-type&quot;&gt;inr&lt;/span&gt; (inl x) =&amp;gt; inl (inr x)
                | &lt;span class=&quot;hljs-type&quot;&gt;inr&lt;/span&gt; (inr x) =&amp;gt; inr x
                &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;).
  + now &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; [[x|&lt;span class=&quot;hljs-type&quot;&gt;x&lt;/span&gt;]|&lt;span class=&quot;hljs-type&quot;&gt;x&lt;/span&gt;].
  + now &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; [x|&lt;span class=&quot;hljs-type&quot;&gt;[x&lt;/span&gt;|&lt;span class=&quot;hljs-type&quot;&gt;x&lt;/span&gt;]].
&lt;span class=&quot;hljs-keyword&quot;&gt;Qed&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;sum&lt;/span&gt;&lt;/code&gt; Has A Neutral Element&lt;/h3&gt;
&lt;p&gt;We need to find a type &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;e&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; such that &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\alpha + e = \alpha&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; for any type
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\alpha&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; (similarly to &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mn&gt;0&lt;/mn&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;x + 0 = x&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; for any natural number &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;x&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;).&lt;/p&gt;
&lt;p&gt;Any empty type (that is, a type with no term such as &lt;code class=&quot;hljs language-coq&quot;&gt;False&lt;/code&gt;) can act as
the natural element of &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;&lt;/code&gt;. As a reminder, empty types in Coq are
defined with the following syntax&lt;label for=&quot;fn2&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn2&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Note that &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Inductive&lt;/span&gt; empty.&lt;/code&gt; is erroneous.&lt;/span&gt;
&lt;span class=&quot;footnote-p&quot;&gt;When the &lt;code class=&quot;hljs language-coq&quot;&gt;:=&lt;/code&gt; is omitted, Coq defines an inductive type with one
constructor, making such a type equivalent to &lt;code class=&quot;hljs language-coq&quot;&gt;unit&lt;/code&gt;, not
&lt;code class=&quot;hljs language-coq&quot;&gt;False&lt;/code&gt;. &lt;/span&gt;
&lt;/span&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Inductive&lt;/span&gt; empty := .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From a high-level perspective, &lt;code class=&quot;hljs language-coq&quot;&gt;empty&lt;/code&gt; being the neutral element of
&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;sum&lt;/span&gt;&lt;/code&gt; makes sense. Because we cannot construct a term of type &lt;code class=&quot;hljs language-coq&quot;&gt;empty&lt;/code&gt;,
then &lt;code class=&quot;hljs language-coq&quot;&gt;α + empty&lt;/code&gt; contains exactly the same numbers of terms as &lt;code class=&quot;hljs language-coq&quot;&gt;α&lt;/code&gt;.
This is the intuition. Now, how can we convince Coq that our intuition is
correct? Just like before, by providing two functions of types:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;α -&amp;gt; α + empty&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;α + empty -&amp;gt; α&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first function is &lt;code class=&quot;hljs language-coq&quot;&gt;inl&lt;/code&gt;, that is one of the constructors of
&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;sum&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The second function is trickier to write in Coq, because it comes down to
writing a function of type is &lt;code class=&quot;hljs language-coq&quot;&gt;empty -&amp;gt; α&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; from_empty {α} : empty -&amp;gt; α :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; x =&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; x &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is the exact same trick that allows Coq to encode proofs by
contradiction.&lt;/p&gt;
&lt;p&gt;If we combine &lt;code class=&quot;hljs language-coq&quot;&gt;from_empty&lt;/code&gt; with the generic function&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; unwrap_left_or {α β}
    (f : β -&amp;gt; α) (x : α + β)
  : α :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; x &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;inl&lt;/span&gt; x =&amp;gt; x
  | &lt;span class=&quot;hljs-type&quot;&gt;inr&lt;/span&gt; x =&amp;gt; f x
  &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we have everything to prove that &lt;code class=&quot;hljs language-coq&quot;&gt;α == α + empty&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Lemma&lt;/span&gt; sum_neutral (α : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;) : α == α + empty.
&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;.
  equiv &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt; inl and (unwrap_left_or from_empty);
    &lt;span class=&quot;hljs-built_in&quot;&gt;auto&lt;/span&gt;.
  now &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; [x|&lt;span class=&quot;hljs-type&quot;&gt;x&lt;/span&gt;].
&lt;span class=&quot;hljs-keyword&quot;&gt;Qed&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;The &lt;code class=&quot;hljs language-coq&quot;&gt;prod&lt;/code&gt; Operator&lt;/h2&gt;
&lt;p&gt;This is very similar to what we have just proven for &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;sum&lt;/span&gt;&lt;/code&gt;, so expect
less text for this section.&lt;/p&gt;
&lt;h3&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;prod&lt;/code&gt; Is A Morphism&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; lr_map_prod {α α&apos; β β&apos;}
    (f : α -&amp;gt; α&apos;) (g : β -&amp;gt; β&apos;)
  : α * β -&amp;gt; α&apos; * β&apos; :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; x =&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; x &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt; (x, y) =&amp;gt; (f x, g y) &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;.

&lt;span class=&quot;hljs-keyword&quot;&gt;Instance&lt;/span&gt; prod_Proper
  : Proper (type_equiv ==&amp;gt; type_equiv ==&amp;gt; type_equiv) prod.

&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;.
  add_morphism_tactic.
  &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; α α&apos; [fα gα&apos; equαα&apos; equα&apos;α]
         β β&apos; [fβ gβ&apos; equββ&apos; equβ&apos;β].
  equiv &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt; (lr_map_prod fα fβ)
         and (lr_map_prod gα&apos; gβ&apos;).
  + &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; [x y]; &lt;span class=&quot;hljs-built_in&quot;&gt;cbn&lt;/span&gt;.
    &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; &amp;lt;- equαα&apos;.
    now &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; &amp;lt;- equββ&apos;.
  + &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; [x y]; &lt;span class=&quot;hljs-built_in&quot;&gt;cbn&lt;/span&gt;.
    &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; &amp;lt;- equα&apos;α.
    now &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; &amp;lt;- equβ&apos;β.
&lt;span class=&quot;hljs-keyword&quot;&gt;Qed&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;prod&lt;/code&gt; Is Commutative&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; prod_invert {α β} (x : α * β) : β * α :=
  (snd x, fst x).

&lt;span class=&quot;hljs-keyword&quot;&gt;Lemma&lt;/span&gt; prod_com {α β} : α * β == β * α.

&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;.
  equiv &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt; prod_invert and prod_invert;
    now &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; [x y].
&lt;span class=&quot;hljs-keyword&quot;&gt;Qed&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;prod&lt;/code&gt; Is Associative&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Lemma&lt;/span&gt; prod_assoc {α β γ}
  : α * β * γ == α * (β * γ).

&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;.
  equiv &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; x =&amp;gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; x &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
                | &lt;span class=&quot;hljs-type&quot;&gt;((x&lt;/span&gt;, y), z) =&amp;gt; (x, (y, z))
                &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;)
         and (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; x =&amp;gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; x &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
                | &lt;span class=&quot;hljs-type&quot;&gt;(x&lt;/span&gt;, (y, z)) =&amp;gt; ((x, y), z)
                &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;).
  + now &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; [[x y] z].
  + now &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; [x [y z]].
&lt;span class=&quot;hljs-keyword&quot;&gt;Qed&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;prod&lt;/code&gt; Has A Neutral Element&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Lemma&lt;/span&gt; prod_neutral (α : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;) : α * unit == α.

&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;.
  equiv &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt; fst and ((flip pair) tt).
  + now &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; [x []].
  + now &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;Qed&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;prod&lt;/code&gt; Has An Absorbing Element *)&lt;/h3&gt;
&lt;p&gt;And this absorbing element is &lt;code class=&quot;hljs language-coq&quot;&gt;empty&lt;/code&gt;, just like the absorbing element of
the multiplication of natural numbers is &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;0&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;0&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; (that is, the neutral element of
the addition).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Lemma&lt;/span&gt; prod_absord (α : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;) : α * empty == empty.
&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;.
  equiv &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt; (snd &amp;gt;&amp;gt;&amp;gt; from_empty)
         and (from_empty).
  + &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; [&lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; []].
  + &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; [].
&lt;span class=&quot;hljs-keyword&quot;&gt;Qed&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;prod&lt;/code&gt; And &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;sum&lt;/span&gt;&lt;/code&gt; Distributivity&lt;/h2&gt;
&lt;p&gt;Finally, we can prove the distributivity property of &lt;code class=&quot;hljs language-coq&quot;&gt;prod&lt;/code&gt; and
&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;sum&lt;/span&gt;&lt;/code&gt; using a similar approach to prove the associativity of &lt;code class=&quot;hljs language-coq&quot;&gt;prod&lt;/code&gt;
and &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;sum&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Lemma&lt;/span&gt; prod_sum_distr (α β γ : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;)
  : α * (β + γ) == α * β + α * γ.
&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;.
  equiv &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; x =&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; x &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
                       | &lt;span class=&quot;hljs-type&quot;&gt;(x&lt;/span&gt;, inr y) =&amp;gt; inr (x, y)
                       | &lt;span class=&quot;hljs-type&quot;&gt;(x&lt;/span&gt;, inl y) =&amp;gt; inl (x, y)
                       &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;)
         and (&lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; x =&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; x &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
                       | &lt;span class=&quot;hljs-type&quot;&gt;inr&lt;/span&gt; (x, y) =&amp;gt; (x, inr y)
                       | &lt;span class=&quot;hljs-type&quot;&gt;inl&lt;/span&gt; (x, y) =&amp;gt; (x, inl y)
                       &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;).
  + now &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; [x [y | &lt;span class=&quot;hljs-type&quot;&gt;y&lt;/span&gt;]].
  + now &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; [[x y] | &lt;span class=&quot;hljs-type&quot;&gt;[x&lt;/span&gt; y]].
&lt;span class=&quot;hljs-keyword&quot;&gt;Qed&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Bonus: Algebraic Datatypes and Metaprogramming&lt;/h2&gt;
&lt;p&gt;Algebraic datatypes are very suitable for generating functions, as demonstrated
by the automatic deriving of typeclass in Haskell or trait in Rust. Because a
datatype can be expressed in terms of &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;sum&lt;/span&gt;&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;prod&lt;/code&gt;, you just
have to know how to deal with these two constructions to start metaprogramming.&lt;/p&gt;
&lt;p&gt;We can take the example of the &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;fold&lt;/span&gt;&lt;/code&gt; functions. A &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;fold&lt;/span&gt;&lt;/code&gt; function
is a function which takes a container as its argument, and iterates over the
values of that container in order to compute a result.&lt;/p&gt;
&lt;p&gt;We introduce &lt;code class=&quot;hljs language-coq&quot;&gt;fold_type INPUT CANON_FORM OUTPUT&lt;/code&gt;, a tactic to compute the
type of the fold function of the type &lt;code class=&quot;hljs&quot;&gt;INPUT&lt;/code&gt;, whose “canonical form” (in terms
of &lt;code class=&quot;hljs language-coq&quot;&gt;prod&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;sum&lt;/span&gt;&lt;/code&gt;) is &lt;code class=&quot;hljs&quot;&gt;CANON_FORM&lt;/code&gt; and whose result type is
&lt;code class=&quot;hljs&quot;&gt;OUTPUT&lt;/code&gt;. Interested readers have to be familiar with &lt;code class=&quot;hljs&quot;&gt;Ltac&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Ltac&lt;/span&gt; fold_args b a r :=
  lazymatch a &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;unit&lt;/span&gt; =&amp;gt;
    &lt;span class=&quot;hljs-built_in&quot;&gt;exact&lt;/span&gt; r
  | &lt;span class=&quot;hljs-type&quot;&gt;b&lt;/span&gt; =&amp;gt;
    &lt;span class=&quot;hljs-built_in&quot;&gt;exact&lt;/span&gt; (r -&amp;gt; r)
  | &lt;span class=&quot;hljs-type&quot;&gt;(?c&lt;/span&gt; + ?d)%type =&amp;gt;
    &lt;span class=&quot;hljs-built_in&quot;&gt;exact&lt;/span&gt; (ltac:(fold_args b c r) * ltac:(fold_args b d r))%type
  | &lt;span class=&quot;hljs-type&quot;&gt;(b&lt;/span&gt; * ?c)%type =&amp;gt;
    &lt;span class=&quot;hljs-built_in&quot;&gt;exact&lt;/span&gt; (r -&amp;gt; ltac:(fold_args b c r))
  | &lt;span class=&quot;hljs-type&quot;&gt;(?c&lt;/span&gt; * ?d)%type =&amp;gt;
    &lt;span class=&quot;hljs-built_in&quot;&gt;exact&lt;/span&gt; (c -&amp;gt; ltac:(fold_args b d r))
  | &lt;span class=&quot;hljs-type&quot;&gt;?a&lt;/span&gt; =&amp;gt;
    &lt;span class=&quot;hljs-built_in&quot;&gt;exact&lt;/span&gt; (a -&amp;gt; r)
  &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;.

&lt;span class=&quot;hljs-keyword&quot;&gt;Ltac&lt;/span&gt; currying a :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; a &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;?a&lt;/span&gt; * ?b -&amp;gt; ?c =&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;exact&lt;/span&gt; (a -&amp;gt; ltac:(currying (b -&amp;gt; c)))
  | &lt;span class=&quot;hljs-type&quot;&gt;?a&lt;/span&gt; =&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;exact&lt;/span&gt; a
  &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;.

&lt;span class=&quot;hljs-keyword&quot;&gt;Ltac&lt;/span&gt; fold_type b a r :=
  &lt;span class=&quot;hljs-built_in&quot;&gt;exact&lt;/span&gt; (ltac:(currying (ltac:(fold_args b a r) -&amp;gt; b -&amp;gt; r))).
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We use it to compute the type of a &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;fold&lt;/span&gt;&lt;/code&gt; function for &lt;code class=&quot;hljs language-coq&quot;&gt;list&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; fold_list_type (α β : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;) : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt; :=
  ltac:(fold_type (list α) (unit + α * list α)%type β).
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;fold_list_type =
  &lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; α β : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt; =&amp;gt; β -&amp;gt; (α -&amp;gt; β -&amp;gt; β) -&amp;gt; list α -&amp;gt; β
     : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is exactly what you could have expected (as match the type of
&lt;code class=&quot;hljs language-coq&quot;&gt;fold_right&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Generating the body of the function is possible in theory, but probably not in
&lt;code class=&quot;hljs&quot;&gt;Ltac&lt;/code&gt; without modifying a bit &lt;code class=&quot;hljs language-coq&quot;&gt;type_equiv&lt;/code&gt;. This could be a nice
use case for &lt;a href=&quot;https://github.com/MetaCoq/metacoq&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;MetaCoq&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; though.&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>A Study of Clight and its Semantics</title>
      <link>https://soap.coffee/~lthms/posts/ClightIntroduction.html</link>
      <guid>https://soap.coffee/~lthms/posts/ClightIntroduction.html</guid>
      <pubDate>March 20, 2020</pubDate>
      <description>
        
        &lt;h1&gt;A Study of Clight and its Semantics&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/coq.html&quot; class=&quot;tag hover-periwinkle&quot; marked=&quot;&quot;&gt;coq&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;CompCert is a certified C compiler which comes with a proof of semantics
preservation. What this means is the following: the semantics of the C code you
write is preserved by CompCert compilation passes up to the generated machine
code.&lt;/p&gt;
&lt;p&gt;I had been interested in CompCert for quite some times, and ultimately
challenged myself to study Clight and its semantics. This write-up is the
result of this challenge, written as I was progressing.&lt;/p&gt;
&lt;h2&gt;Installing CompCert&lt;/h2&gt;
&lt;p&gt;CompCert has been added to &lt;code class=&quot;hljs&quot;&gt;opam&lt;/code&gt;, and as a consequence can be very easily
used as a library for other Coq developments. A typical use case is for a
project to produce Clight (the high-level AST of CompCert), and to benefit
from CompCert proofs after that.&lt;/p&gt;
&lt;p&gt;Installing CompCert is as easy as&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;opam install coq-compcert
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;More precisely, this article uses &lt;code class=&quot;hljs&quot;&gt;coq-compcert.3.8&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Once &lt;code class=&quot;hljs&quot;&gt;opam&lt;/code&gt; terminates, the &lt;code class=&quot;hljs&quot;&gt;compcert&lt;/code&gt; namespace becomes available. In
addition, several binaries are now available if you have correctly set your
&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$PATH&lt;/span&gt;&lt;/code&gt; environment variable. For instance, &lt;code class=&quot;hljs&quot;&gt;clightgen&lt;/code&gt; takes a C file
as an argument, and generates a Coq file which contains the Clight generated by
CompCert.&lt;/p&gt;
&lt;h2&gt;Problem Statement&lt;/h2&gt;
&lt;p&gt;Our goal for this first write-up is to prove that the C function&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-c&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; x, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; y)&lt;/span&gt; {
    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; x + y;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;returns the expected result, that is &lt;code class=&quot;hljs language-c&quot;&gt;x + y&lt;/code&gt;. The &lt;code class=&quot;hljs&quot;&gt;clightgen&lt;/code&gt; tool
generates (among other things) the following AST&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;It has been modified in order to improve its readability. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;From&lt;/span&gt; compcert &lt;span class=&quot;hljs-keyword&quot;&gt;Require&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Import&lt;/span&gt; Clight Ctypes Clightdefs AST
                             Coqlib Cop.

&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; _x : &lt;span class=&quot;hljs-keyword&quot;&gt;ident&lt;/span&gt; := &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;%positive.
&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; _y : &lt;span class=&quot;hljs-keyword&quot;&gt;ident&lt;/span&gt; := &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;%positive.

&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; f_add : function :=
  {| &lt;span class=&quot;hljs-type&quot;&gt;fn_return&lt;/span&gt; := tint
   ; fn_callconv := cc_default
   ; fn_params := [(_x, tint); (_y, tint)]
   ; fn_vars := []
   ; fn_temps := []
   ; fn_body := Sreturn
                  (Some (Ebinop Oadd
                                (Etempvar _x tint)
                                (Etempvar _y tint)
                                tint))
  |&lt;span class=&quot;hljs-type&quot;&gt;}.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The fields of the &lt;code class=&quot;hljs language-coq&quot;&gt;function&lt;/code&gt; type are pretty self-explanatory (as it is
often the case in CompCert’s ASTs as far as I can tell for now).&lt;/p&gt;
&lt;p&gt;Identifiers in Clight are (&lt;code class=&quot;hljs language-coq&quot;&gt;positive&lt;/code&gt;) indices.  The &lt;code class=&quot;hljs&quot;&gt;fn_body&lt;/code&gt; field is of
type &lt;code class=&quot;hljs language-coq&quot;&gt;statement&lt;/code&gt;, with the particular constructor &lt;code class=&quot;hljs language-coq&quot;&gt;Sreturn&lt;/code&gt; whose argument
is of type &lt;code class=&quot;hljs language-coq&quot;&gt;option expr&lt;/code&gt;, and &lt;code class=&quot;hljs language-coq&quot;&gt;statement&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;expr&lt;/code&gt; look like the two main
types to study.  The predicates &lt;code class=&quot;hljs language-coq&quot;&gt;step1&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;step2&lt;/code&gt; allow for reasoning
about the execution of a &lt;code class=&quot;hljs language-coq&quot;&gt;function&lt;/code&gt;, step-by-step (hence the name). It
appears that &lt;code class=&quot;hljs&quot;&gt;clightgen&lt;/code&gt; generates Clight terms using the function call
convention encoded by &lt;code class=&quot;hljs language-coq&quot;&gt;step2&lt;/code&gt;.  To reason about a complete execution, it
appears that we can use &lt;code class=&quot;hljs language-coq&quot;&gt;star&lt;/code&gt; (from the &lt;code class=&quot;hljs language-coq&quot;&gt;Smallstep&lt;/code&gt; module) which is
basically a trace of &lt;code class=&quot;hljs language-coq&quot;&gt;step&lt;/code&gt;. These semantics are defined as predicates (that
is, they live in &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Prop&lt;/span&gt;&lt;/code&gt;). They allow for reasoning about
state transformation, where a state is either&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A function call, with a given list of arguments and a continuation&lt;/li&gt;
&lt;li&gt;A function return, with a result and a continuation&lt;/li&gt;
&lt;li&gt;A &lt;code class=&quot;hljs language-coq&quot;&gt;statement&lt;/code&gt; execution within a &lt;code class=&quot;hljs language-coq&quot;&gt;function&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We import several CompCert modules to manipulate &lt;em&gt;values&lt;/em&gt; (in our case,
bounded integers).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;From&lt;/span&gt; compcert &lt;span class=&quot;hljs-keyword&quot;&gt;Require&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Import&lt;/span&gt; Values Integers.
&lt;span class=&quot;hljs-keyword&quot;&gt;Import&lt;/span&gt; Int.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Putting everything together, the lemma we want to prove about &lt;code class=&quot;hljs language-coq&quot;&gt;f_add&lt;/code&gt; is
the following.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Lemma&lt;/span&gt; f_add_spec (env : genv)
    (t : Events.trace)
    (m m&apos; : Memory.Mem.mem)
    (v : val) (x y z : int)
    (trace : Smallstep.star step2 env
               (Callstate (Ctypes.Internal f_add)
                          [Vint x; Vint y]
                          Kstop
                          m)
               t
               (Returnstate (Vint z) Kstop m&apos;))
  : z = add x y.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Proof Walkthrough&lt;/h2&gt;
&lt;p&gt;We introduce a custom &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;inversion&lt;/span&gt;&lt;/code&gt; tactic which does some clean-up in
addition to just perform the inversion.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Ltac&lt;/span&gt; smart_inv H :=
  &lt;span class=&quot;hljs-built_in&quot;&gt;inversion&lt;/span&gt; H; &lt;span class=&quot;hljs-built_in&quot;&gt;subst&lt;/span&gt;; &lt;span class=&quot;hljs-built_in&quot;&gt;cbn&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt; *; &lt;span class=&quot;hljs-built_in&quot;&gt;clear&lt;/span&gt; H.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can now try to prove our lemma.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We first destruct &lt;code class=&quot;hljs language-coq&quot;&gt;trace&lt;/code&gt;, and we rename the generated hypothesis in order
to improve the readability of these notes.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;  smart_inv trace.
  &lt;span class=&quot;hljs-built_in&quot;&gt;rename&lt;/span&gt; H into Hstep.
  &lt;span class=&quot;hljs-built_in&quot;&gt;rename&lt;/span&gt; H0 into Hstar.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This generates two hypotheses.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;Hstep : step1
          env
          (Callstate (Ctypes.Internal f_add)
                     [Vint x; Vint y]
                     Kstop
                     m)
          t1
          s2
Hstar : Smallstep.star
          step2
          env
          s2
          t2
          (Returnstate (Vint z) Kstop m&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In other words, to “go” from a &lt;code class=&quot;hljs language-coq&quot;&gt;Callstate&lt;/code&gt; of &lt;code class=&quot;hljs language-coq&quot;&gt;f_add&lt;/code&gt; to a
&lt;code class=&quot;hljs language-coq&quot;&gt;Returnstate&lt;/code&gt;, there is a first step from a &lt;code class=&quot;hljs language-coq&quot;&gt;Callstate&lt;/code&gt; to a state
&lt;code class=&quot;hljs language-coq&quot;&gt;s2&lt;/code&gt;, then a succession of steps to go from &lt;code class=&quot;hljs language-coq&quot;&gt;s2&lt;/code&gt; to a
&lt;code class=&quot;hljs language-coq&quot;&gt;Returnstate&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We consider the single &lt;code class=&quot;hljs language-coq&quot;&gt;step&lt;/code&gt;, in order to determine the actual value of
&lt;code class=&quot;hljs language-coq&quot;&gt;s2&lt;/code&gt; (among other things). To do that, we use &lt;code class=&quot;hljs language-coq&quot;&gt;smart_inv&lt;/code&gt; on
&lt;code class=&quot;hljs language-coq&quot;&gt;Hstep&lt;/code&gt;, and again perform some renaming.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;  smart_inv Hstep.
  &lt;span class=&quot;hljs-built_in&quot;&gt;rename&lt;/span&gt; le into tmp_env.
  &lt;span class=&quot;hljs-built_in&quot;&gt;rename&lt;/span&gt; e into c_env.
  &lt;span class=&quot;hljs-built_in&quot;&gt;rename&lt;/span&gt; H5 into f_entry.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This produces two effects. First, a new hypothesis is added to the context.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;f_entry : function_entry1
            env
            f_add
            [Vint x; Vint y]
            m
            c_env
            tmp_env
            m1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, the &lt;code class=&quot;hljs language-coq&quot;&gt;Hstar&lt;/code&gt; hypothesis has been updated, because we now have a more
precise value of &lt;code class=&quot;hljs language-coq&quot;&gt;s2&lt;/code&gt;. More precisely, &lt;code class=&quot;hljs language-coq&quot;&gt;s2&lt;/code&gt; has become&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;State
  f_add
  (Sreturn
    (Some (Ebinop Oadd
                  (Etempvar _x tint)
                  (Etempvar _y tint)
                  tint)))
  Kstop
  c_env
  tmp_env
  m1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using the same approach as before, we can uncover the next step.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;  smart_inv Hstar.
  &lt;span class=&quot;hljs-built_in&quot;&gt;rename&lt;/span&gt; H into Hstep.
  &lt;span class=&quot;hljs-built_in&quot;&gt;rename&lt;/span&gt; H0 into Hstar.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The resulting hypotheses are&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;Hstep : step2 env
          (State
             f_add
             (Sreturn
               (Some
                 (Ebinop Oadd
                 (Etempvar _x tint)
                 (Etempvar _y tint)
                 tint)))
             Kstop c_env tmp_env m1) t1 s2
Hstar : Smallstep.star
          step2
          env
          s2
          t0
          (Returnstate (Vint z) Kstop m&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An inversion of &lt;code class=&quot;hljs language-coq&quot;&gt;Hstep&lt;/code&gt; can be used to learn more about its resulting
state… So let’s do just that.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;  smart_inv Hstep.
  &lt;span class=&quot;hljs-built_in&quot;&gt;rename&lt;/span&gt; H7 into ev.
  &lt;span class=&quot;hljs-built_in&quot;&gt;rename&lt;/span&gt; v0 into res.
  &lt;span class=&quot;hljs-built_in&quot;&gt;rename&lt;/span&gt; H8 into res_equ.
  &lt;span class=&quot;hljs-built_in&quot;&gt;rename&lt;/span&gt; H9 into mem_equ.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The generated hypotheses have become&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;res : val
ev : eval_expr env c_env tmp_env m1
       (Ebinop Oadd
               (Etempvar _x tint)
               (Etempvar _y tint)
               tint)
       res
res_equ : sem_cast res tint tint m1 = Some v&apos;
mem_equ : Memory.Mem.free_list m1
                               (blocks_of_env env c_env)
            = Some m&apos;0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our understanding of these hypotheses is the following&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The expression &lt;code class=&quot;hljs language-coq&quot;&gt;_x + _y&lt;/code&gt; is evaluated using the &lt;code class=&quot;hljs language-coq&quot;&gt;c_env&lt;/code&gt;
environment (and we know thanks to &lt;code class=&quot;hljs language-coq&quot;&gt;binding&lt;/code&gt; the value of &lt;code class=&quot;hljs language-coq&quot;&gt;_x&lt;/code&gt;
and &lt;code class=&quot;hljs language-coq&quot;&gt;_y&lt;/code&gt;), and its result is stored in &lt;code class=&quot;hljs language-coq&quot;&gt;res&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;res&lt;/code&gt; is cast into a &lt;code class=&quot;hljs language-coq&quot;&gt;tint&lt;/code&gt; value, and acts as the result of
&lt;code class=&quot;hljs language-coq&quot;&gt;f_add&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code class=&quot;hljs language-coq&quot;&gt;Hstar&lt;/code&gt; hypothesis is now interesting&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;Hstar : Smallstep.star
          step2 env
          (Returnstate v&apos; Kstop m&apos;0) t0
          (Returnstate (Vint z) Kstop m&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is clear that we are at the end of the execution of &lt;code class=&quot;hljs language-coq&quot;&gt;f_add&lt;/code&gt; (even if
Coq generates two subgoals, the second one is not relevant and easy to
discard).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;  smart_inv Hstar; [| &lt;span class=&quot;hljs-type&quot;&gt;smart_inv&lt;/span&gt; H ].
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We are making good progress here, and we can focus our attention on the &lt;code class=&quot;hljs language-coq&quot;&gt;ev&lt;/code&gt;
hypothesis, which concerns the evaluation of the &lt;code class=&quot;hljs language-coq&quot;&gt;_x + _y&lt;/code&gt; expression. We can
simplify it a bit further.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;  smart_inv ev; [| &lt;span class=&quot;hljs-type&quot;&gt;smart_inv&lt;/span&gt; H].
  &lt;span class=&quot;hljs-built_in&quot;&gt;rename&lt;/span&gt; H4 into fetch_x.
  &lt;span class=&quot;hljs-built_in&quot;&gt;rename&lt;/span&gt; H5 into fetch_y.
  &lt;span class=&quot;hljs-built_in&quot;&gt;rename&lt;/span&gt; H6 into add_op.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In a short-term, the hypotheses &lt;code class=&quot;hljs language-coq&quot;&gt;fetch_x&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;fetch_y&lt;/code&gt; are the
most important.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;fetch_x : eval_expr env c_env tmp_env m1 (Etempvar _x tint) v1
fetch_y : eval_expr env c_env tmp_env m1 (Etempvar _y tint) v2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The current challenge we face is to prove that we know their value.  At this
point, we can have a look at &lt;code class=&quot;hljs language-coq&quot;&gt;f_entry&lt;/code&gt;. This is starting to look
familiar: &lt;code class=&quot;hljs language-coq&quot;&gt;smart_inv&lt;/code&gt;, then renaming, etc.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;  smart_inv f_entry.
  &lt;span class=&quot;hljs-built_in&quot;&gt;clear&lt;/span&gt; H.
  &lt;span class=&quot;hljs-built_in&quot;&gt;clear&lt;/span&gt; H0.
  &lt;span class=&quot;hljs-built_in&quot;&gt;clear&lt;/span&gt; H1.
  smart_inv H3; &lt;span class=&quot;hljs-built_in&quot;&gt;subst&lt;/span&gt;.
  &lt;span class=&quot;hljs-built_in&quot;&gt;rename&lt;/span&gt; H2 into allocs.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We are almost done. Let’s simplify as much as possible &lt;code class=&quot;hljs language-coq&quot;&gt;fetch_x&lt;/code&gt; and
&lt;code class=&quot;hljs language-coq&quot;&gt;fetch_y&lt;/code&gt;. Each time, the &lt;code class=&quot;hljs language-coq&quot;&gt;smart_inv&lt;/code&gt; tactic generates two subgoals,
but only the first one is relevant. The second one is not, and can be
discarded.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;  smart_inv fetch_x; [| &lt;span class=&quot;hljs-type&quot;&gt;inversion&lt;/span&gt; H].
  smart_inv H2.
  smart_inv fetch_y; [| &lt;span class=&quot;hljs-type&quot;&gt;inversion&lt;/span&gt; H].
  smart_inv H2.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We now know the values of the operands of &lt;code class=&quot;hljs language-coq&quot;&gt;add&lt;/code&gt;. The two relevant
hypotheses that we need to consider next are &lt;code class=&quot;hljs language-coq&quot;&gt;add_op&lt;/code&gt; and
&lt;code class=&quot;hljs language-coq&quot;&gt;res_equ&lt;/code&gt;. They are easy to read.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;add_op : sem_binarith
           (fun (_ : signedness) (n1 n2 : Integers.int)
              =&amp;gt; Some (Vint (add n1 n2)))
           (fun (_ : signedness) (n1 n2 : int64)
              =&amp;gt; Some (Vlong (Int64.add n1 n2)))
           (fun n1 n2 : Floats.float
              =&amp;gt; Some (Vfloat (Floats.Float.add n1 n2)))
           (fun n1 n2 : Floats.float32
              =&amp;gt; Some (Vsingle (Floats.Float32.add n1 n2)))
           v1 tint v2 tint m1 = Some res
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;add_op&lt;/code&gt; is the addition of &lt;code class=&quot;hljs language-coq&quot;&gt;Vint x&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;Vint y&lt;/code&gt;, and its
result is &lt;code class=&quot;hljs language-coq&quot;&gt;res&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;res_equ : sem_cast res tint tint m1 = Some (Vint z)
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;res_equ&lt;/code&gt; is the equation which says that the result of &lt;code class=&quot;hljs language-coq&quot;&gt;f_add&lt;/code&gt; is &lt;code class=&quot;hljs language-coq&quot;&gt;res&lt;/code&gt;,
after it has been cast as a &lt;code class=&quot;hljs language-coq&quot;&gt;tint&lt;/code&gt; value.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We can simplify &lt;code class=&quot;hljs language-coq&quot;&gt;add_op&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;res_equ&lt;/code&gt;, and this allows us to
conclude.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;  smart_inv add_op.
  smart_inv res_equ.
  &lt;span class=&quot;hljs-built_in&quot;&gt;reflexivity&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;Qed&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The definitions of Clight are straightforward, and the &lt;a href=&quot;http://compcert.inria.fr/doc/&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;CompCert
documentation&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; is very pleasant to
read. Understanding Clight and its semantics can be very interesting if you
are working on a language that you want to translate into machine code.
However, proving some functional properties of a given C snippet using only CompCert
can quickly become cumbersome. From this perspective, the
&lt;a href=&quot;https://github.com/PrincetonUniversity/VST&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;VST&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; project is very interesting,
as its main purpose is to provide tools to reason about Clight programs more
easily.&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>Release of colorless-themes-0.2</title>
      <link>https://soap.coffee/~lthms/posts/ColorlessThemes-0.2.html</link>
      <guid>https://soap.coffee/~lthms/posts/ColorlessThemes-0.2.html</guid>
      <pubDate>February 15, 2020</pubDate>
      <description>
        
        &lt;h1&gt;Release of &lt;code class=&quot;hljs&quot;&gt;colorless-themes-0.2&lt;/code&gt;&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/releases.html&quot; class=&quot;tag hover-lavender&quot; marked=&quot;&quot;&gt;releases&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://git.sr.ht/~lthms/colorless-themes.el/refs/0.2&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;I have tagged and released a new version of
&lt;code class=&quot;hljs&quot;&gt;colorless-themes&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;.
The motivation behind modifying the version number is an important breaking
change regarding how the &lt;code class=&quot;hljs language-lisp&quot;&gt;colorless-themes-make&lt;/code&gt; macro shall be used.&lt;/p&gt;
&lt;p&gt;Before &lt;code class=&quot;hljs&quot;&gt;0.2&lt;/code&gt;, the macro was calling &lt;code class=&quot;hljs language-lisp&quot;&gt;deftheme&lt;/code&gt; and
&lt;code class=&quot;hljs language-lisp&quot;&gt;provide-theme&lt;/code&gt; itself. In practices, it meant the actual themes were
not using these two functions themselves. It was working great in isolation,
but it turns out many tools such as &lt;code class=&quot;hljs language-lisp&quot;&gt;use-package&lt;/code&gt; or &lt;a href=&quot;https://peach-melpa.org&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;Peach
Melpa&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; (an auto-generated Emacs themes gallery) are
relying on the presence of these functions to decide whether a file provides a
theme or not. As of now, &lt;code class=&quot;hljs&quot;&gt;nordless-theme&lt;/code&gt; and &lt;code class=&quot;hljs&quot;&gt;lavenderless-theme&lt;/code&gt; have been
updated accordingly, and &lt;a href=&quot;https://peach-melpa.org/themes/lavenderless-theme/variants/lavenderless&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;they appear on Peach
Melpa&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;.
Their loading can also be deferred using the &lt;code class=&quot;hljs language-lisp&quot;&gt;:defer&lt;/code&gt; keyword of the
&lt;code class=&quot;hljs language-lisp&quot;&gt;use-package&lt;/code&gt; macro.&lt;/p&gt;
&lt;p&gt;if you happen to be a user of &lt;code class=&quot;hljs&quot;&gt;colorless-themes&lt;/code&gt;, feel free to shoot an email!
I would love to hear about your experience using a mostly colorless theme.&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>A Literate Toolchain To Build This Website</title>
      <link>https://soap.coffee/~lthms/posts/CleopatraV1.html</link>
      <guid>https://soap.coffee/~lthms/posts/CleopatraV1.html</guid>
      <pubDate>February 4, 2020</pubDate>
      <description>
        
        &lt;h1&gt;A Literate Toolchain To Build This Website&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/meta.html&quot; class=&quot;tag hover-sky&quot; marked=&quot;&quot;&gt;meta&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/literate-programming.html&quot; class=&quot;tag hover-lemon&quot; marked=&quot;&quot;&gt;literate-programming&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/emacs.html&quot; class=&quot;tag hover-sky&quot; marked=&quot;&quot;&gt;emacs&lt;/a&gt; &lt;/div&gt;
&lt;div class=&quot;markdown-alert markdown-alert-important&quot;&gt;&lt;p class=&quot;markdown-alert-title&quot;&gt;&lt;svg class=&quot;octicon octicon-report mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v9.5A1.75 1.75 0 0 1 14.25 13H8.06l-2.573 2.573A1.458 1.458 0 0 1 3 14.543V13H1.75A1.75 1.75 0 0 1 0 11.25Zm1.75-.25a.25.25 0 0 0-.25.25v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25Zm7 2.25v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 9a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;Important&lt;/p&gt;&lt;p&gt;What you are reading is actually the rendered version of a Markdown document
that was manually “translated” from the Org original document, named
&lt;code class=&quot;hljs&quot;&gt;Bootstrap.org&lt;/code&gt;. &lt;code class=&quot;hljs&quot;&gt;Bootstrap.org&lt;/code&gt; was probably complete gibberish for anyone
who isn’t me. This version was actually heavily reworked to try to fix that.&lt;/p&gt;
&lt;p&gt;In any case, the tool-suite described here has not been used to generate this
website for a while now.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;A literate program is a particular type of software program where code is not
directly written in source files, but rather in a text document as code
snippets. In essence, literate programming allows for writing in the same place
both the software program and its technical documentation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;hljs&quot;&gt;cleopatra&lt;/code&gt;&lt;/strong&gt; is a “literate toolchain” I have implemented to build this
website, and you are currently reading it&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;This sentence was true when this article was published, but things
have changed since then. &lt;/span&gt;
&lt;/span&gt;. That is, &lt;strong&gt;&lt;code class=&quot;hljs&quot;&gt;cleopatra&lt;/code&gt;&lt;/strong&gt; is
both the build system and an article of this website! To achieve this,
&lt;strong&gt;&lt;code class=&quot;hljs&quot;&gt;cleopatra&lt;/code&gt;&lt;/strong&gt; has been written as a collection of org files which can be
either “tangled” using &lt;a href=&quot;https://orgmode.org/worg/org-contrib/babel/&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;Babel&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; or
“exported” as a HTML document. Tangling here refers to extract marked code
blocks into files.&lt;/p&gt;
&lt;p&gt;The page you are currently reading is &lt;strong&gt;&lt;code class=&quot;hljs&quot;&gt;cleopatra&lt;/code&gt;&lt;/strong&gt; entry point. Its
primary purpose is to define two Makefiles —&lt;code class=&quot;hljs&quot;&gt;makefile&lt;/code&gt; and &lt;code class=&quot;hljs&quot;&gt;bootstrap.mk&lt;/code&gt;—
and the necessary emacs-lisp script to tangle this document.&lt;/p&gt;
&lt;p&gt;On the one hand, &lt;code class=&quot;hljs&quot;&gt;makefile&lt;/code&gt; is the main entrypoint of &lt;strong&gt;&lt;code class=&quot;hljs&quot;&gt;cleopatra&lt;/code&gt;&lt;/strong&gt;. It
serves two purposes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It initiates a few global variables, and&lt;/li&gt;
&lt;li&gt;It provides a rule to tangle this document, that is to update itself and
&lt;code class=&quot;hljs&quot;&gt;bootstrap.mk&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;On the other hand, &lt;code class=&quot;hljs&quot;&gt;bootstrap.mk&lt;/code&gt; is used to declare the various “generation
processes” used to generate this website.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;hljs&quot;&gt;makefile&lt;/code&gt; and the emacs-lisp scripts are versioned, because they are necessary
to bootstrap &lt;strong&gt;&lt;code class=&quot;hljs&quot;&gt;cleopatra&lt;/code&gt;&lt;/strong&gt;; but since they are also defined in this document,
it means &lt;strong&gt;&lt;code class=&quot;hljs&quot;&gt;cleopatra&lt;/code&gt;&lt;/strong&gt; can update itself, in some sense. This is to be kept in mind
when modifying this document to hastily.&lt;/p&gt;
&lt;h2&gt;Global Constants and Variables&lt;/h2&gt;
&lt;p&gt;First, &lt;code class=&quot;hljs&quot;&gt;makefile&lt;/code&gt; defines several global “constants”&lt;label for=&quot;fn2&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn2&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;As far as I know, &lt;code class=&quot;hljs&quot;&gt;make&lt;/code&gt; does not support true &lt;em&gt;constant&lt;/em&gt; values,
It is assumed generation processes will not modify them. &lt;/span&gt;
&lt;/span&gt;. In a nutshell,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$ROOT&lt;/span&gt;&lt;/code&gt;  tells Emacs where the root of your website sources is, so
that tangled output filenames can be given relative to it rather than the org
files.  So for instance, the &lt;code class=&quot;hljs&quot;&gt;block_src&lt;/code&gt; tangle parameter for &lt;code class=&quot;hljs&quot;&gt;Makefile&lt;/code&gt;
looks like &lt;code class=&quot;hljs language-lisp&quot;&gt;:tangle Makefile&lt;/code&gt;, instead of &lt;code class=&quot;hljs language-lisp&quot;&gt;:tangle ../../Makefile&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$CLEODIR&lt;/span&gt;&lt;/code&gt; tells &lt;strong&gt;&lt;code class=&quot;hljs&quot;&gt;cleopatra&lt;/code&gt;&lt;/strong&gt; where its sources live. If you place
it inside the &lt;code class=&quot;hljs&quot;&gt;site/&lt;/code&gt; directory (as it is intended), and you enable the use
of &lt;code class=&quot;hljs&quot;&gt;org&lt;/code&gt; files to author your contents, then &lt;strong&gt;&lt;code class=&quot;hljs&quot;&gt;cleopatra&lt;/code&gt;&lt;/strong&gt; documents will
be part of your website. If you don’t want that, just move the directory
outside the &lt;code class=&quot;hljs&quot;&gt;site/&lt;/code&gt; directory, and update the &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$CLEODIR&lt;/span&gt;&lt;/code&gt; variable
accordingly.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For this website, these constants are defined as follows&lt;label for=&quot;fn3&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn3&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I will use a comment in the first line to recall to which file a
given block code is expected to be tangled. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-makefile&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# makefile:&lt;/span&gt;
ROOT := &lt;span class=&quot;hljs-variable&quot;&gt;$(&lt;span class=&quot;hljs-built_in&quot;&gt;shell&lt;/span&gt; pwd)&lt;/span&gt;
CLEODIR := site/cleopatra
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We then introduce two variables to list the output of the generation processes,
with two purposes in mind: keeping the &lt;code class=&quot;hljs&quot;&gt;.gitignore&lt;/code&gt; up-to-date automatically,
and providing rules to remove them.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$ARTIFACTS&lt;/span&gt;&lt;/code&gt; lists the short-term artifacts which can be removed
frequently without too much hassle. They will be removed by &lt;code class=&quot;hljs&quot;&gt;make clean&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$CONFIGURE&lt;/span&gt;&lt;/code&gt; lists the long-term artifacts whose generation can be
time consuming. They will only be removed by&lt;code class=&quot;hljs&quot;&gt;~make cleanall&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-makefile&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# makefile:&lt;/span&gt;
ARTIFACTS := build.log
CONFIGURE :=

clean :
	@rm -rf ${ARTIFACTS}

cleanall : clean
	@rm -rf ${CONFIGURE}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Generation processes can declare new build outputs using the &lt;code class=&quot;hljs&quot;&gt;+=&lt;/code&gt; assignement
operators. Using another operator will likely provoke an undesirable result.&lt;/p&gt;
&lt;h2&gt;Tangling Org Documents&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;hljs&quot;&gt;cleopatra&lt;/code&gt;&lt;/strong&gt; is a literate program implemented with Org mode, an Emacs major
editing mode. We provide the necessary bits to easily tangle Org documents.&lt;/p&gt;
&lt;p&gt;The configuration of Babel is done using an emacs lisp script called
&lt;code class=&quot;hljs&quot;&gt;tangle-org.el&lt;/code&gt; whose status is similar to &lt;code class=&quot;hljs&quot;&gt;Makefile&lt;/code&gt;. It is part of the
bootstrap process, and therefore lives “outside” of &lt;strong&gt;&lt;code class=&quot;hljs&quot;&gt;cleopatra&lt;/code&gt;&lt;/strong&gt; (it is not
deleted with &lt;code class=&quot;hljs&quot;&gt;make clean&lt;/code&gt; for instance).  However, it is overwritten when this
file is tangled. If you try to modify it and find that &lt;strong&gt;&lt;code class=&quot;hljs&quot;&gt;cleopatra&lt;/code&gt;&lt;/strong&gt; does not
work properly, you should restore it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-lisp&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;;;; tangle-org.el:&lt;/span&gt;
(&lt;span class=&quot;hljs-name&quot;&gt;require&lt;/span&gt; &apos;org)
(&lt;span class=&quot;hljs-name&quot;&gt;cd&lt;/span&gt; (&lt;span class=&quot;hljs-name&quot;&gt;getenv&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;ROOT&quot;&lt;/span&gt;))
(&lt;span class=&quot;hljs-name&quot;&gt;setq&lt;/span&gt; org-confirm-babel-evaluate &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;)
(&lt;span class=&quot;hljs-name&quot;&gt;setq&lt;/span&gt; org-src-preserve-indentation &lt;span class=&quot;hljs-literal&quot;&gt;t&lt;/span&gt;)
(&lt;span class=&quot;hljs-name&quot;&gt;add-to-list&lt;/span&gt; &apos;org-babel-default-header-args
             &apos;(&lt;span class=&quot;hljs-symbol&quot;&gt;:mkdirp&lt;/span&gt; . &lt;span class=&quot;hljs-string&quot;&gt;&quot;yes&quot;&lt;/span&gt;))
(&lt;span class=&quot;hljs-name&quot;&gt;org-babel-do-load-languages&lt;/span&gt;
 &apos;org-babel-load-languages
 &apos;((shell . &lt;span class=&quot;hljs-literal&quot;&gt;t&lt;/span&gt;)))
(&lt;span class=&quot;hljs-name&quot;&gt;org-babel-tangle&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We define variables that ensure that the &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$ROOT&lt;/span&gt;&lt;/code&gt; environment variable is
set and &lt;code class=&quot;hljs&quot;&gt;tangle-org.el&lt;/code&gt; is loaded when using Emacs.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-makefile&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# makefile:&lt;/span&gt;
EMACSBIN := emacs
EMACS := ROOT=&lt;span class=&quot;hljs-string&quot;&gt;&quot;${ROOT}&quot;&lt;/span&gt; ${EMACSBIN}
TANGLE := --batch \
          --load=&lt;span class=&quot;hljs-string&quot;&gt;&quot;${ROOT}/scripts/tangle-org.el&quot;&lt;/span&gt; \
          2&amp;gt;&amp;gt; build.log
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, we introduce a &lt;a href=&quot;https://www.gnu.org/software/make/manual/html_node/Canned-Recipes.html#Canned-Recipes&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;canned
recipe&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;
to seamlessly tangle a given file&lt;label for=&quot;fn4&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn4&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;It was the first time I had used canned recipes, and I don’t think I
had the opportunity to re-use it ever again. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-makefile&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# makefile:&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;define&lt;/span&gt; emacs-tangle =
echo &lt;span class=&quot;hljs-string&quot;&gt;&quot;  tangle  &lt;span class=&quot;hljs-variable&quot;&gt;$&amp;lt;&lt;/span&gt;&quot;&lt;/span&gt;
${EMACS} &lt;span class=&quot;hljs-variable&quot;&gt;$&amp;lt;&lt;/span&gt; ${TANGLE}
&lt;span class=&quot;hljs-keyword&quot;&gt;endef&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Updating &lt;code class=&quot;hljs&quot;&gt;.gitignore&lt;/code&gt; Automatically&lt;/h2&gt;
&lt;p&gt;Assuming each generation process correctly defines its &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$ARTIFACTS&lt;/span&gt;&lt;/code&gt;
and &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$CONFIGURE&lt;/span&gt;&lt;/code&gt; variables, we have all the information we need to
update &lt;code class=&quot;hljs&quot;&gt;.gitignore&lt;/code&gt; automatically.&lt;/p&gt;
&lt;p&gt;This is done by adding markers in &lt;code class=&quot;hljs&quot;&gt;.gitignore&lt;/code&gt; to define a region under the
control of &lt;strong&gt;&lt;code class=&quot;hljs&quot;&gt;cleopatra&lt;/code&gt;&lt;/strong&gt;, and writing a script to update said region after
each build.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# update-gitignore.sh:&lt;/span&gt;
BEGIN_MARKER=&lt;span class=&quot;hljs-string&quot;&gt;&quot;# begin generated files&quot;&lt;/span&gt;
END_MARKER=&lt;span class=&quot;hljs-string&quot;&gt;&quot;# begin generated files&quot;&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# remove the previous list of generated files to ignore&lt;/span&gt;
sed -i -e &lt;span class=&quot;hljs-string&quot;&gt;&quot;/&lt;span class=&quot;hljs-variable&quot;&gt;${BEGIN_MARKER}&lt;/span&gt;/,/&lt;span class=&quot;hljs-variable&quot;&gt;${END_MARKER}&lt;/span&gt;/d&quot;&lt;/span&gt; .gitignore
&lt;span class=&quot;hljs-comment&quot;&gt;# remove trailing empty lines&lt;/span&gt;
sed -i -e :a -e &lt;span class=&quot;hljs-string&quot;&gt;&apos;/^\n*$/{$d;N;};/\n$/ba&apos;&lt;/span&gt; .gitignore

&lt;span class=&quot;hljs-comment&quot;&gt;# output the list of files to ignore&lt;/span&gt;
&lt;span class=&quot;hljs-built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt; &amp;gt;&amp;gt; .gitignore
&lt;span class=&quot;hljs-built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;${BEGIN_MARKER}&lt;/span&gt; &amp;gt;&amp;gt; .gitignore
&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; f &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$@&lt;/span&gt;; &lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;hljs-built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-variable&quot;&gt;${f}&lt;/span&gt;&quot;&lt;/span&gt; &amp;gt;&amp;gt; .gitignore
&lt;span class=&quot;hljs-keyword&quot;&gt;done&lt;/span&gt;
&lt;span class=&quot;hljs-built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;${END_MARKER}&lt;/span&gt; &amp;gt;&amp;gt; .gitignore
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code class=&quot;hljs&quot;&gt;ignore&lt;/code&gt; rule of &lt;code class=&quot;hljs&quot;&gt;makefile&lt;/code&gt; is defined as follows.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-makefile&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# makefile:&lt;/span&gt;
ignore :
	@echo &lt;span class=&quot;hljs-string&quot;&gt;&quot;  update  gitignore&quot;&lt;/span&gt;
	@scripts/update-gitignore.sh \
	   ${ARTIFACTS} \
	   ${CONFIGURE}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Bootstrapping&lt;/h2&gt;
&lt;p&gt;The core purpose of &lt;code class=&quot;hljs&quot;&gt;makefile&lt;/code&gt; remains to bootstrap the chain of generation
processes. This chain is divided into three stages: &lt;code class=&quot;hljs&quot;&gt;prebuild&lt;/code&gt;, &lt;code class=&quot;hljs&quot;&gt;build&lt;/code&gt;, and
&lt;code class=&quot;hljs&quot;&gt;postbuild&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This translates as follows in &lt;code class=&quot;hljs&quot;&gt;makefile&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-makefile&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# makefile:&lt;/span&gt;
default : postbuild ignore

init :
	@rm -f build.log

prebuild : init

build : prebuild

postbuild : build

.PHONY : init prebuild build postbuild ignore
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;em&gt;generation process&lt;/em&gt; in &lt;strong&gt;&lt;code class=&quot;hljs&quot;&gt;cleopatra&lt;/code&gt;&lt;/strong&gt; is a Makefile which provides rules for
these three stages, along with the utilities used by these rules. More
precisely, a generation process &lt;code class=&quot;hljs&quot;&gt;proc&lt;/code&gt; is defined in &lt;code class=&quot;hljs&quot;&gt;proc.mk&lt;/code&gt;. The rules of
&lt;code class=&quot;hljs&quot;&gt;proc.mk&lt;/code&gt; for each stage are expected to be prefixed by &lt;code class=&quot;hljs&quot;&gt;proc-&lt;/code&gt;, &lt;em&gt;e.g.&lt;/em&gt;,
&lt;code class=&quot;hljs&quot;&gt;proc-prebuild&lt;/code&gt; for the &lt;code class=&quot;hljs&quot;&gt;prebuild&lt;/code&gt; stage.&lt;/p&gt;
&lt;p&gt;Eventually, the following dependencies are expected between within the chain of
generation processes for every generation process.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-makefile&quot;&gt;prebuild : proc-prebuild
build : proc-build
postbuild : proc-postbuild

proc-build : proc-prebuild
proc-postbuild : proc build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;hljs&quot;&gt;cleopatra&lt;/code&gt;&lt;/strong&gt; is a literate toolchain whose main purpose is to allow me to
turn the scripts I wrote to generate my website into blogposts of said website.
As such, it allows me to implement the generation processes using Org mode,
which means that before being able to start generating HTML files,
&lt;strong&gt;&lt;code class=&quot;hljs&quot;&gt;cleopatra&lt;/code&gt;&lt;/strong&gt; has to tangle the generation processes.&lt;/p&gt;
&lt;p&gt;To achieve this, &lt;strong&gt;&lt;code class=&quot;hljs&quot;&gt;cleopatra&lt;/code&gt;&lt;/strong&gt; relies on a particular behavior of &lt;code class=&quot;hljs&quot;&gt;make&lt;/code&gt;
regarding the &lt;code class=&quot;hljs&quot;&gt;include&lt;/code&gt; directive. If there exists a rule to generate a
Makefile used as an operand of &lt;code class=&quot;hljs&quot;&gt;include&lt;/code&gt;, &lt;code class=&quot;hljs&quot;&gt;make&lt;/code&gt; will use this rule to update
(if necessary) said Makefile before actually including it.&lt;/p&gt;
&lt;p&gt;Therefore, the rules of the following form achieve our ambition of extensibility.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-makefile&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;include&lt;/span&gt; ${PROC}.mk

prebuild : ${PROC}-prebuild
build : ${PROC}-build
postbuild : ${PROC}-postbuild

${PROC}-prebuild : ${PROC}.mk ${AUX}
${PROC}-build : ${PROC}-prebuild
${PROC}-postbuild : ${PROC}-build

${PROC}.mk ${AUX} &amp;amp;:\
   ${CLEODIR}/${IN}
	@$(emacs-tangle)

CONFIGURE += ${PROC}.mk ${AUX}

.PHONY : ${PROC}-prebuild \
         ${PROC}-build \
         ${PROC}-postbuild
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;where&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$IN&lt;/span&gt;&lt;/code&gt; is the Org document which contains the generation process code&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$PROC&lt;/span&gt;&lt;/code&gt; is the name of the generation process&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$AUX&lt;/span&gt;&lt;/code&gt; lists the utilities of the generation process tangled from
&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$IN&lt;/span&gt;&lt;/code&gt; with &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$PROC&lt;/span&gt;.mk&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We use &lt;code class=&quot;hljs&quot;&gt;&amp;amp;:&lt;/code&gt; is used in place of &lt;code class=&quot;hljs&quot;&gt;:&lt;/code&gt; to separate the target from its
dependencies in the “tangle rule.”&lt;label for=&quot;fn5&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn5&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Yet another obscure Makefile trick I have never encountered again. &lt;/span&gt;
&lt;/span&gt; This tells &lt;code class=&quot;hljs&quot;&gt;make&lt;/code&gt; that the recipe of this
rule generates all these files.&lt;/p&gt;
&lt;p&gt;Rather than writing these rules manually for each generation process we want to
define, we rely on to &lt;a href=&quot;https://orgmode.org/worg/org-tutorials/org-latex-export.html&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;noweb of
Babel&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. We call
&lt;code class=&quot;hljs&quot;&gt;extends&lt;/code&gt; the primitive to generate new generation processes.&lt;/p&gt;
&lt;p&gt;We derive the rule to tangle &lt;code class=&quot;hljs&quot;&gt;bootstrap.mk&lt;/code&gt; using &lt;code class=&quot;hljs&quot;&gt;extends&lt;/code&gt;, using the following Org mode syntax.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;#+BEGIN_SRC makefile :noweb yes
# makefile:
&amp;lt;&amp;lt;extends(IN=&quot;Bootstrap.org&quot;, PROC=&quot;bootstrap&quot;, AUX=&quot;scripts/update-gitignore.sh&quot;)&amp;gt;&amp;gt;
#+END_SRC
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which gives the following result.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-makefile&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;include&lt;/span&gt; bootstrap.mk

prebuild : bootstrap-prebuild
build : bootstrap-build
postbuild : bootstrap-postbuild

bootstrap-prebuild : bootstrap.mk scripts/update-gitignore.sh
bootstrap-build : bootstrap-prebuild
bootstrap-postbuild : bootstrap-build

bootstrap.mk scripts/update-gitignore.sh &amp;amp;:\
   ${CLEODIR}/Bootstrap.org
	@$(emacs-tangle)

CONFIGURE += bootstrap.mk scripts/update-gitignore.sh

.PHONY : bootstrap-prebuild \
         bootstrap-build \
         bootstrap-postbuild
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These are the last lines of &lt;code class=&quot;hljs&quot;&gt;makefile&lt;/code&gt;. The rest of the generation processes will be
declared in &lt;code class=&quot;hljs&quot;&gt;bootstrap.mk&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Generation Processes&lt;/h2&gt;
&lt;p&gt;In this section, we construct &lt;code class=&quot;hljs&quot;&gt;bootstrap.mk&lt;/code&gt; by enumerating the generation
processes that are currently used to generate the website you are reading.&lt;/p&gt;
&lt;p&gt;We recall that each generation process shall&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Define &lt;code class=&quot;hljs&quot;&gt;proc-prebuild&lt;/code&gt;, &lt;code class=&quot;hljs&quot;&gt;proc-build&lt;/code&gt;, and &lt;code class=&quot;hljs&quot;&gt;proc-postbuild&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Declare dependencies between stages of generation processes&lt;/li&gt;
&lt;li&gt;Declare build outputs (see &lt;code class=&quot;hljs&quot;&gt;ARTIFACTS&lt;/code&gt; and &lt;code class=&quot;hljs&quot;&gt;CONFIGURE&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Theming and Templating&lt;/h3&gt;
&lt;p&gt;The
&lt;a href=&quot;https://src.soap.coffee/soap.coffee/lthms.git/tree/site/cleopatra/Theme.org?id=9329e9883a52eb95c0803a46560c396d149ef2c6&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;theme&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;
generation process controls the general appearance of the website. More
precisely, it introduces the main template used by &lt;code class=&quot;hljs&quot;&gt;soupault&lt;/code&gt;
(&lt;code class=&quot;hljs&quot;&gt;main/templates.html&lt;/code&gt;), and the main SASS sheet used by this template.&lt;/p&gt;
&lt;p&gt;If a generation process produces a set of styles within a specific SASS files,
the current approach is&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;To make this file a dependency of &lt;code class=&quot;hljs&quot;&gt;theme-build&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;To modify &lt;code class=&quot;hljs&quot;&gt;style/main.sass&lt;/code&gt; in &lt;code class=&quot;hljs&quot;&gt;theme&lt;/code&gt;
to import this file&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Eventually, the second step will be automated, but, in the meantime,
this customization is mandatory.&lt;/p&gt;
&lt;h3&gt;Configuring Soupault&lt;/h3&gt;
&lt;p&gt;The
&lt;a href=&quot;https://src.soap.coffee/soap.coffee/lthms.git/tree/site/cleopatra/Soupault.org?id=9329e9883a52eb95c0803a46560c396d149ef2c6&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;soupault&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;
generation configures and run &lt;code class=&quot;hljs&quot;&gt;soupault&lt;/code&gt;, in order to generate a static
website.&lt;/p&gt;
&lt;p&gt;If a generation process &lt;code class=&quot;hljs&quot;&gt;proc&lt;/code&gt; produces files that will eventually be
integrated to your website, its &lt;code class=&quot;hljs&quot;&gt;proc-build&lt;/code&gt; recipe needs to be executed
&lt;em&gt;before&lt;/em&gt; the &lt;code class=&quot;hljs&quot;&gt;soupault-build&lt;/code&gt; recipe. This can be enforced by making the
dependency explicit to &lt;code class=&quot;hljs&quot;&gt;make&lt;/code&gt;, &lt;em&gt;i.e.&lt;/em&gt;,&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-makefile&quot;&gt;soupault-build : proc-build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Eventually, generation processes shall be allowed to produce specific &lt;code class=&quot;hljs&quot;&gt;soupault&lt;/code&gt;
widgets to be integrated into &lt;code class=&quot;hljs&quot;&gt;soupault.conf&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Authoring Contents&lt;/h3&gt;
&lt;p&gt;The fact that &lt;strong&gt;&lt;code class=&quot;hljs&quot;&gt;cleopatra&lt;/code&gt;&lt;/strong&gt; is a literate program which gradually generates
itself was not intended: it is a consequence of my desire to be able to easily
use whatever format I so desire for writing my contents, and Org documents in
particular.&lt;/p&gt;
&lt;p&gt;In the present website, contents can be written in the following format:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;HTML Files:&lt;/strong&gt; This requires no particular set-up, since HTML is the &lt;em&gt;lingua
franca&lt;/em&gt; of &lt;code class=&quot;hljs&quot;&gt;soupault&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Regular Coq files:&lt;/strong&gt; Coq is a system which allows writing machine-checked
proofs, and it comes with a source “prettifier” called &lt;code class=&quot;hljs&quot;&gt;coqdoc&lt;/code&gt;. &lt;a href=&quot;https://src.soap.coffee/soap.coffee/lthms.git/tree/site/cleopatra/Contents/Coq.org?id=9329e9883a52eb95c0803a46560c396d149ef2c6&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;Learn more
about the generation process for Coq
files&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Org documents:&lt;/strong&gt; Emacs comes with a powerful editing mode called &lt;a href=&quot;https://orgmode.org/&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;Org
mode&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, and Org documents are really pleasant to work
with. &lt;a href=&quot;https://src.soap.coffee/soap.coffee/lthms.git/tree/site/cleopatra/Contents/Org.org?id=9329e9883a52eb95c0803a46560c396d149ef2c6&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;Learn more about the generation process for Org
documents&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>I am no longer a PhD. student</title>
      <link>https://soap.coffee/~lthms/posts/EndOfPhd.html</link>
      <guid>https://soap.coffee/~lthms/posts/EndOfPhd.html</guid>
      <pubDate>January 15, 2019</pubDate>
      <description>
        
        &lt;h1&gt;I am no longer a PhD. student&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/research.html&quot; class=&quot;tag hover-sky&quot; marked=&quot;&quot;&gt;research&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;It has been a long journey —4 years, 10 days— but I have completed my PhD on
October 25, 2018. The exact title of my PhD thesis is “&lt;a href=&quot;https://inria.hal.science/tel-01989940v2/file/2018_LETAN_archivage.pdf&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;&lt;em&gt;Specifying and
Verifying Hardware-based Security Enforcement
Mechanisms&lt;/em&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;”.&lt;/p&gt;
&lt;h2&gt;Abstract&lt;/h2&gt;
&lt;p&gt;In this thesis, we consider a class of security enforcement mechanisms we
called &lt;em&gt;Hardware-based Security Enforcement&lt;/em&gt; (HSE). In such mechanisms, some
trusted software components rely on the underlying hardware architecture to
constrain the execution of untrusted software components with respect to
targeted security policies. For instance, an operating system which configures
page tables to isolate userland applications implements a HSE mechanism.&lt;/p&gt;
&lt;p&gt;For a HSE mechanism to correctly enforce a targeted security policy, it
requires both hardware and trusted software components to play their parts.
During the past decades, several vulnerability disclosures have defeated HSE
mechanisms. We focus on the vulnerabilities that are the result of errors at
the specification level, rather than implementation errors. In some critical
vulnerabilities, the attacker makes a legitimate use of one hardware component
to circumvent the HSE mechanism provided by another one. For instance, cache
poisoning attacks leverage inconsistencies between cache and DRAM’s access
control mechanisms. We call this class of attacks, where an attacker leverages
inconsistencies in hardware specifications, &lt;em&gt;compositional attacks&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Our goal is to explore approaches to specify and verify HSE mechanisms using
formal methods that would benefit both hardware designers and software
developers. Firstly, a formal specification of HSE mechanisms can be leveraged
as a foundation for a systematic approach to verify hardware specifications, in
the hope of uncovering potential compositional attacks ahead of time. Secondly,
it provides unambiguous specifications to software developers, in the form of a
list of requirements.&lt;/p&gt;
&lt;p&gt;Our contribution is two-fold:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We propose a theory of HSE mechanisms against hardware architecture models.
This theory can be used to specify and verify such mechanisms. To evaluate
our approach, we propose a minimal model for a single core x86-based
computing platform. We use it to specify and verify the HSE mechanism
provided by Intel to isolate the code executed while the CPU is in System
Management Mode (SMM), a highly privileged execution mode of x86
microprocessors. We have written machine-checked proofs in the Coq proof
assistant to that end.&lt;/li&gt;
&lt;li&gt;We propose a novel approach inspired by algebraic effects to enable modular
verification of complex systems made of interconnected components as a first
step towards addressing the challenge posed by the scale of the x86 hardware
architecture. This approach is not specific to hardware models, and could
also be leveraged to reason about the composition of software components as
well. In addition, we have implemented our approach in the Coq theorem
prover, and the resulting framework takes advantage of Coq proof automation
features to provide general-purpose facilities to reason about components
interactions.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Publications&lt;/h2&gt;
&lt;p&gt;If you are interested, you can have a look at the paper I wrote during my PhD:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://inria.hal.science/hal-01361422v1/file/speccert-fm2016.pdf&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;SpecCert: Specifying and Verifying Hardware-based Security Enforcement
Mechanisms&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;,
with Pierre Chifflier, Guillame Hiet and Benjamin Morin, at Formal Methods
2016&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://inria.hal.science/hal-01799712v1/file/main.pdf&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;Modular Verification of Programs with Effects and Effect Handlers in
Coq&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, with Yann
Régis-Gianas, Pierre Chifflier and Guillaume Hiet, at Formal Methods 2018&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can also have a look at the Coq frameworks I have published:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lthms/speccert&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;SpecCert on Github&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; (CeCILL-B)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lthms/FreeSpec&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;FreeSpec on Github&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; (MPL-2.0)&lt;/li&gt;
&lt;/ul&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>Discovering Common Lisp with trivial-gamekit</title>
      <link>https://soap.coffee/~lthms/posts/DiscoveringCommonLisp.html</link>
      <guid>https://soap.coffee/~lthms/posts/DiscoveringCommonLisp.html</guid>
      <pubDate>June 17, 2018</pubDate>
      <description>
        
        &lt;h1&gt;Discovering Common Lisp with &lt;code class=&quot;hljs&quot;&gt;trivial-gamekit&lt;/code&gt;&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/lisp.html&quot; class=&quot;tag hover-mint&quot; marked=&quot;&quot;&gt;lisp&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;I always wanted to learn some Lisp dialect. In the meantime,
&lt;a href=&quot;https://github.com/lkn-org/lykan&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;lykan&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; —my Slayers Online clone— begins to
take shape. So, of course, my brain got an idea: &lt;em&gt;why not writing a client for
lykan in some Lisp dialect?&lt;/em&gt;&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Spoiler alert: this wasn’t the most efficient approach for the lykan
project. But it was fun. &lt;/span&gt;
&lt;/span&gt; I asked on
&lt;a href=&quot;https://mastodon.social/@lthms/100135240390747697&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;Mastodon&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; if there were
good game engines for Lisp, and someone told me about
&lt;a href=&quot;https://github.com/borodust/trivial-gamekit&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;trivial-gamekit&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I have no idea if I will manage to implement a decent client using
trivial-gamekit, but why not trying? This article is the first of a series
about my experiments, discoveries and difficulties. The complete project
detailed in this article is available &lt;a href=&quot;https://gist.github.com/lthms/9833f4851843119c966917775b4c4180&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;as a
gist&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Common Lisp, Quicklisp and &lt;code class=&quot;hljs&quot;&gt;trivial-gamekit&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The trivial-gamekit
&lt;a href=&quot;https://borodust.github.io/projects/trivial-gamekit/&quot; class=&quot;hover-lemon&quot; marked=&quot;&quot;&gt;website&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; lists several
requirements. Two are related to Lisp:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Quicklisp&lt;/li&gt;
&lt;li&gt;SBCL or CCL&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href=&quot;https://quicklisp.org/beta&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;Quicklisp&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; is an experimental package manager for
Lisp projects, while SBCL and CCL are two Lisp implementations. I had already
installed &lt;a href=&quot;https://www.archlinux.org/packages/?name=clisp&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;Clisp&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, and it took
me quite some time to understand my mistake. Fortunately,
&lt;a href=&quot;https://www.archlinux.org/packages/?name=sbcl&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;SBCL&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; is also packaged in
ArchLinux.&lt;/p&gt;
&lt;p&gt;With a compatible Lisp implementation, installing Quicklisp as a user is
straightforward. Following the website instructions is enough. At the end of
the process, you will have a new directory &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;${HOME}&lt;/span&gt;/quicklisp&lt;/code&gt;&lt;label for=&quot;fn2&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn2&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;The purpose of this directory is similar to the &lt;a href=&quot;https://github.com/golang/go/wiki/SettingGOPATH&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;Go
workspace&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Quicklisp is not a native feature of SBCL, and requires a small bit of
configurations to be made available automatically. You have to create a file
&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;${HOME}&lt;/span&gt;/.sbclrc&lt;/code&gt;, with the following content:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-lisp&quot;&gt;(&lt;span class=&quot;hljs-name&quot;&gt;load&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;~/quicklisp/setup&quot;&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is one final step to be able to use &lt;code class=&quot;hljs&quot;&gt;trivial-gamekit&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;sbcl --&lt;span class=&quot;hljs-built_in&quot;&gt;eval&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&apos;(ql-dist:install-dist &quot;http://bodge.borodust.org/dist/org.borodust.bodge.txt&quot;)&apos;&lt;/span&gt; \
     --quit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As of June 2018, Quicklisp &lt;a href=&quot;https://github.com/quicklisp/quicklisp-client/issues/167&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;does not support
HTTPS&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Introducing Lysk&lt;/h2&gt;
&lt;h3&gt;Packaging&lt;/h3&gt;
&lt;p&gt;The first thing I search for when I learn a new language is how projects are
organized. From this perspective, &lt;code class=&quot;hljs&quot;&gt;trivial-gamekit&lt;/code&gt; pointed me directly to
Quicklisp&lt;/p&gt;
&lt;p&gt;Creating a new Quicklisp project is straightforward. From my understanding, new
Quicklisp projects have to be located inside
&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;${HOME}&lt;/span&gt;/quicklisp/local-projects&lt;/code&gt;. I am not particularly happy with
this, but it is not really important.&lt;/p&gt;
&lt;p&gt;The current code name of my Lisp game client is lysk.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;mkdir&lt;/span&gt; ~/quicklisp/local-projects/lysk
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Quicklisp packages (systems?) are defined through &lt;code class=&quot;hljs&quot;&gt;asd&lt;/code&gt; files.
I have firstly created &lt;code class=&quot;hljs&quot;&gt;lysk.asd&lt;/code&gt; as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-lisp&quot;&gt;(&lt;span class=&quot;hljs-name&quot;&gt;asdf&lt;/span&gt;&lt;span class=&quot;hljs-symbol&quot;&gt;:defsystem&lt;/span&gt; lysk
  &lt;span class=&quot;hljs-symbol&quot;&gt;:description&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;Lykan Game Client&quot;&lt;/span&gt;
  &lt;span class=&quot;hljs-symbol&quot;&gt;:author&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;lthms&quot;&lt;/span&gt;
  &lt;span class=&quot;hljs-symbol&quot;&gt;:license&lt;/span&gt;  &lt;span class=&quot;hljs-string&quot;&gt;&quot;GPLv3&quot;&lt;/span&gt;
  &lt;span class=&quot;hljs-symbol&quot;&gt;:version&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;0.0.1&quot;&lt;/span&gt;
  &lt;span class=&quot;hljs-symbol&quot;&gt;:serial&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;t&lt;/span&gt;
  &lt;span class=&quot;hljs-symbol&quot;&gt;:depends-on&lt;/span&gt; (&lt;span class=&quot;hljs-name&quot;&gt;trivial-gamekit&lt;/span&gt;)
  &lt;span class=&quot;hljs-symbol&quot;&gt;:components&lt;/span&gt; ((&lt;span class=&quot;hljs-symbol&quot;&gt;:file&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;package&quot;&lt;/span&gt;)
               (&lt;span class=&quot;hljs-symbol&quot;&gt;:file&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;lysk&quot;&lt;/span&gt;)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code class=&quot;hljs language-lisp&quot;&gt;:serial &lt;span class=&quot;hljs-literal&quot;&gt;t&lt;/span&gt;&lt;/code&gt; means that the files detailed in the &lt;code class=&quot;hljs language-lisp&quot;&gt;components&lt;/code&gt;
field depends on the previous ones. That is, &lt;code class=&quot;hljs&quot;&gt;lysk.lisp&lt;/code&gt; depends on
&lt;code class=&quot;hljs&quot;&gt;package.lisp&lt;/code&gt; in this case. It is possible to manage files dependencies
manually, with the following syntax:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-lisp&quot;&gt;(&lt;span class=&quot;hljs-symbol&quot;&gt;:file&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;seconds&quot;&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;:depends-on&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;first&quot;&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I have declared only one dependency: &lt;code class=&quot;hljs&quot;&gt;trivial-gamekit&lt;/code&gt;. That way, Quicklisp
will load it for us.&lt;/p&gt;
&lt;p&gt;The first “true” Lisp file we define in our skeleton is &lt;code class=&quot;hljs&quot;&gt;package.lisp&lt;/code&gt;.
Here is its content:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-lisp&quot;&gt;(&lt;span class=&quot;hljs-name&quot;&gt;defpackage&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;:lysk&lt;/span&gt;
  (&lt;span class=&quot;hljs-symbol&quot;&gt;:use&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;:cl&lt;/span&gt;)
  (&lt;span class=&quot;hljs-symbol&quot;&gt;:export&lt;/span&gt; run app))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Basically, this means we use two symbols, &lt;code class=&quot;hljs language-lisp&quot;&gt;run&lt;/code&gt; and &lt;code class=&quot;hljs language-lisp&quot;&gt;app&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;A Game Client&lt;/h3&gt;
&lt;p&gt;The &lt;code class=&quot;hljs&quot;&gt;lysk.lisp&lt;/code&gt; file contains the program in itself. My first goal was to
obtain the following program: at startup, it shall create a new window in
fullscreen, and exit when users release the left button of their mouse. It is
worth mentioning that I had to report &lt;a href=&quot;https://github.com/borodust/trivial-gamekit/issues/30&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;an issue to the &lt;code class=&quot;hljs&quot;&gt;trivial-gamekit&lt;/code&gt;
upstream&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; in order to
make my program work as expected.&lt;/p&gt;
&lt;p&gt;While it may sound scary —it suggests &lt;code class=&quot;hljs&quot;&gt;trivial-gamekit&lt;/code&gt; is a relatively young
project— the author has implemented a fix in less than an hour! He also took
the time to answer many questions I had when I joined the &lt;code class=&quot;hljs&quot;&gt;#lispgames&lt;/code&gt; Freenode
channel.&lt;/p&gt;
&lt;p&gt;Before going any further, let’s have a look at the complete file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-lisp&quot;&gt;(&lt;span class=&quot;hljs-name&quot;&gt;cl&lt;/span&gt;&lt;span class=&quot;hljs-symbol&quot;&gt;:in-package&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;:lysk&lt;/span&gt;)

(&lt;span class=&quot;hljs-name&quot;&gt;gamekit&lt;/span&gt;&lt;span class=&quot;hljs-symbol&quot;&gt;:defgame&lt;/span&gt; app () ()
                 (&lt;span class=&quot;hljs-symbol&quot;&gt;:fullscreen-p&lt;/span&gt; &apos;t))

(&lt;span class=&quot;hljs-name&quot;&gt;defmethod&lt;/span&gt; gamekit&lt;span class=&quot;hljs-symbol&quot;&gt;:post-initialize&lt;/span&gt; ((&lt;span class=&quot;hljs-name&quot;&gt;app&lt;/span&gt; app))
  (&lt;span class=&quot;hljs-name&quot;&gt;gamekit&lt;/span&gt;&lt;span class=&quot;hljs-symbol&quot;&gt;:bind-button&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;:mouse-left&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;:released&lt;/span&gt;
                       (&lt;span class=&quot;hljs-name&quot;&gt;lambda&lt;/span&gt; () (&lt;span class=&quot;hljs-name&quot;&gt;gamekit&lt;/span&gt;&lt;span class=&quot;hljs-symbol&quot;&gt;:stop&lt;/span&gt;))))

(&lt;span class=&quot;hljs-name&quot;&gt;defun&lt;/span&gt; run ()
  (&lt;span class=&quot;hljs-name&quot;&gt;gamekit&lt;/span&gt;&lt;span class=&quot;hljs-symbol&quot;&gt;:start&lt;/span&gt; &apos;app))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first line is some kind of header, to tell Lisp the owner of the file.&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;hljs language-lisp&quot;&gt;gamekit:defgame&lt;/code&gt; function allows for creating a new game
application (called &lt;code class=&quot;hljs language-lisp&quot;&gt;app&lt;/code&gt; in our case). I ask for a fullscreen window
with &lt;code class=&quot;hljs language-lisp&quot;&gt;:fullscreen-p&lt;/code&gt;. Then, we use the &lt;code class=&quot;hljs language-lisp&quot;&gt;gamekit:post-initialize&lt;/code&gt;
hook to bind a handler to the release of the left button of our mouse. This
handler is a simple call to &lt;code class=&quot;hljs language-lisp&quot;&gt;gamekit:stop&lt;/code&gt;. Finally, we define a new
function &lt;code class=&quot;hljs language-lisp&quot;&gt;run&lt;/code&gt; which only starts our application.&lt;/p&gt;
&lt;p&gt;Pretty straightforward!&lt;/p&gt;
&lt;h3&gt;Running our Program&lt;/h3&gt;
&lt;p&gt;To “play” our game, we can start the SBCL REPL.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;sbcl --&lt;span class=&quot;hljs-built_in&quot;&gt;eval&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&apos;(ql:quickload :lysk)&apos;&lt;/span&gt; --&lt;span class=&quot;hljs-built_in&quot;&gt;eval&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&apos;(lysk:run)&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;A Standalone Executable&lt;/h3&gt;
&lt;p&gt;It looks like empower a REPL-driven development. That being said, once the
development is finished, I don&apos;t think I will have a lot of success if I ask my
future players to start SBCL to enjoy my game. Fortunately, &lt;code class=&quot;hljs&quot;&gt;trivial-gamekit&lt;/code&gt;
provides a dedicated function to bundle the game as a standalone executable.&lt;/p&gt;
&lt;p&gt;Following the advice of the &lt;a href=&quot;https://github.com/borodust&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;&lt;strong&gt;@borodust&lt;/strong&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; —the
&lt;code class=&quot;hljs&quot;&gt;trivial-gamekit&lt;/code&gt; author— I created a second package to that end. First, we
need to edit the &lt;code class=&quot;hljs&quot;&gt;lysk.asd&lt;/code&gt; file to detail a second package:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-lisp&quot;&gt;(&lt;span class=&quot;hljs-name&quot;&gt;asdf&lt;/span&gt;&lt;span class=&quot;hljs-symbol&quot;&gt;:defsystem&lt;/span&gt; lysk/bundle
  &lt;span class=&quot;hljs-symbol&quot;&gt;:description&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;Bundle the Lykan Game Client&quot;&lt;/span&gt;
  &lt;span class=&quot;hljs-symbol&quot;&gt;:author&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;lthms&quot;&lt;/span&gt;
  &lt;span class=&quot;hljs-symbol&quot;&gt;:license&lt;/span&gt;  &lt;span class=&quot;hljs-string&quot;&gt;&quot;GPLv3&quot;&lt;/span&gt;
  &lt;span class=&quot;hljs-symbol&quot;&gt;:version&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;0.0.1&quot;&lt;/span&gt;
  &lt;span class=&quot;hljs-symbol&quot;&gt;:serial&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;t&lt;/span&gt;
  &lt;span class=&quot;hljs-symbol&quot;&gt;:depends-on&lt;/span&gt; (&lt;span class=&quot;hljs-name&quot;&gt;trivial-gamekit/distribution&lt;/span&gt; lysk)
  &lt;span class=&quot;hljs-symbol&quot;&gt;:components&lt;/span&gt; ((&lt;span class=&quot;hljs-symbol&quot;&gt;:file&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;bundle&quot;&lt;/span&gt;)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This second package depends on lysk (our game client) and
trivial-gamekit/distribution. The latter provides the &lt;code class=&quot;hljs language-lisp&quot;&gt;deliver&lt;/code&gt;
function, and we use it in the &lt;code class=&quot;hljs&quot;&gt;bundle.lisp&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-lisp&quot;&gt;(&lt;span class=&quot;hljs-name&quot;&gt;cl&lt;/span&gt;&lt;span class=&quot;hljs-symbol&quot;&gt;:defpackage&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;:lysk&lt;/span&gt;.bundle
  (&lt;span class=&quot;hljs-symbol&quot;&gt;:use&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;:cl&lt;/span&gt;)
  (&lt;span class=&quot;hljs-symbol&quot;&gt;:export&lt;/span&gt; deliver))

(&lt;span class=&quot;hljs-name&quot;&gt;cl&lt;/span&gt;&lt;span class=&quot;hljs-symbol&quot;&gt;:in-package&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;:lysk&lt;/span&gt;.bundle)

(&lt;span class=&quot;hljs-name&quot;&gt;defun&lt;/span&gt; deliver ()
  (&lt;span class=&quot;hljs-name&quot;&gt;gamekit&lt;/span&gt;.distribution&lt;span class=&quot;hljs-symbol&quot;&gt;:deliver&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;:lysk&lt;/span&gt; &apos;lysk&lt;span class=&quot;hljs-symbol&quot;&gt;:app&lt;/span&gt;))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To bundle the game, we can use SBCL from our command line interface.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;sbcl --&lt;span class=&quot;hljs-built_in&quot;&gt;eval&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;(ql:quickload :lysk/bundle)&quot;&lt;/span&gt; \
     --&lt;span class=&quot;hljs-built_in&quot;&gt;eval&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;(lysk.bundle:deliver)&quot;&lt;/span&gt; \
     --quit
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Objectively, there is not much in this article. However, because I am totally
new to Lisp, it took me quite some time to get these few lines of code to work
together. All being told I think this constitutes a good &lt;code class=&quot;hljs&quot;&gt;trivial-gamekit&lt;/code&gt;
skeleton. Do not hesitate to use it this way.&lt;/p&gt;
&lt;p&gt;Thanks again to &lt;a href=&quot;https://github.com/borodust&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;&lt;strong&gt;@borodust&lt;/strong&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, for your time and
all your answers!&lt;/p&gt;
&lt;h2&gt;Appendix: a Makefile&lt;/h2&gt;
&lt;p&gt;I like Makefile, so here is one to &lt;code class=&quot;hljs language-lisp&quot;&gt;run&lt;/code&gt; the game directly, or
&lt;code class=&quot;hljs language-lisp&quot;&gt;bundle&lt;/code&gt; it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-makefile&quot;&gt;&lt;span class=&quot;hljs-section&quot;&gt;run:&lt;/span&gt;
        @sbcl --eval &lt;span class=&quot;hljs-string&quot;&gt;&quot;(ql:quickload :lysk)&quot;&lt;/span&gt; \
              --eval &lt;span class=&quot;hljs-string&quot;&gt;&quot;(lysk:run)&quot;&lt;/span&gt;

&lt;span class=&quot;hljs-section&quot;&gt;bundle:&lt;/span&gt;
        @echo -en &lt;span class=&quot;hljs-string&quot;&gt;&quot;[ ] Remove old build&quot;&lt;/span&gt;
        @rm -rf build/
        @echo -e &lt;span class=&quot;hljs-string&quot;&gt;&quot;\r[*] Remove old build&quot;&lt;/span&gt;
        @echo &lt;span class=&quot;hljs-string&quot;&gt;&quot;[ ] Building&quot;&lt;/span&gt;
        @sbcl --eval &lt;span class=&quot;hljs-string&quot;&gt;&quot;(ql:quickload :lysk/bundle)&quot;&lt;/span&gt; \
              --eval &lt;span class=&quot;hljs-string&quot;&gt;&quot;(lysk.bundle:deliver)&quot;&lt;/span&gt; \
              --quit
        @echo &lt;span class=&quot;hljs-string&quot;&gt;&quot;[*] Building&quot;&lt;/span&gt;

&lt;span class=&quot;hljs-meta&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;.PHONY&lt;/span&gt;: bundle run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>Extensible Type-Safe Error Handling in Haskell</title>
      <link>https://soap.coffee/~lthms/posts/ExtensibleTypeSafeErrorHandling.html</link>
      <guid>https://soap.coffee/~lthms/posts/ExtensibleTypeSafeErrorHandling.html</guid>
      <pubDate>February 4, 2018</pubDate>
      <description>
        
        &lt;h1&gt;Extensible Type-Safe Error Handling in Haskell&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/haskell.html&quot; class=&quot;tag hover-coral&quot; marked=&quot;&quot;&gt;haskell&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;A colleague of mine introduced me to the benefits of
&lt;a href=&quot;https://crates.io/crates/error-chain&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs&quot;&gt;error-chain&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, a crate which aims to
implement “&lt;em&gt;consistent error handling&lt;/em&gt;” for Rust. I found the overall design
pretty convincing, and in his use case, the crate really makes error handling
clearer and flexible. I knew &lt;a href=&quot;https://pijul.org&quot; class=&quot;hover-periwinkle&quot; marked=&quot;&quot;&gt;Pijul&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; was also using
&lt;code class=&quot;hljs&quot;&gt;error-chain&lt;/code&gt; at that time, but I never had the opportunity to dig more into it.&lt;/p&gt;
&lt;p&gt;At the same time, I have read quite a lot about &lt;em&gt;extensible effects&lt;/em&gt; in
Functional Programming, for an academic article I have submitted to &lt;a href=&quot;http://www.fm2018.org&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;Formal
Methods 2018&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;The odds were in my favor: the aforementioned academic article has
been accepted. &lt;/span&gt;
&lt;/span&gt;. In particular, the
&lt;a href=&quot;https://hackage.haskell.org/package/freer&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;freer&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; package provides a very nice
API to define monadic functions which may use well-identified effects. For
instance, we can imagine that &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Console&lt;/span&gt;&lt;/code&gt; identifies the functions
which may print to and read from the standard output. A function
&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;askPassword&lt;/span&gt;&lt;/code&gt; which displays a prompt and get the user password would
have this type signature:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;askPassword&lt;/span&gt; :: &lt;span class=&quot;hljs-type&quot;&gt;Member&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;Console&lt;/span&gt; r =&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;Eff&lt;/span&gt; r ()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Compared to &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;IO&lt;/span&gt;&lt;/code&gt;, &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Eff&lt;/span&gt;&lt;/code&gt; allows for meaningful type
signatures. It becomes easier to reason about function composition, and you
know that a given function which lacks a given effect in its type signature
will not be able to use them. As a predictable drawback, &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Eff&lt;/span&gt;&lt;/code&gt; can
become burdensome to use.&lt;/p&gt;
&lt;p&gt;Basically, when my colleague showed me his Rust project and how he was using
&lt;code class=&quot;hljs&quot;&gt;error-chain&lt;/code&gt;, the question popped out. &lt;em&gt;Can we use an approach similar to
&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Eff&lt;/span&gt;&lt;/code&gt; to implement a Haskell-flavored &lt;code class=&quot;hljs&quot;&gt;error-chain&lt;/code&gt;?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Spoiler alert: the answer is yes. In this post, I will dive into the resulting
API, leaving for another time the details of the underlying implementation&lt;label for=&quot;fn2&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn2&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;For once, I wanted to write about the &lt;em&gt;result&lt;/em&gt; of a project, instead of
&lt;em&gt;how it is implemented&lt;/em&gt;. &lt;/span&gt;
&lt;/span&gt;.
Believe me, there is plenty to say. If you want to have a look already, the
current implementation can be found on
&lt;a href=&quot;https://github.com/lthms/chain&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;GitHub&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In this article, I will use several “advanced” GHC pragmas. I will not explain
each of them, but I will &lt;em&gt;try&lt;/em&gt; to give some pointers for the reader who wants
to learn more.&lt;/p&gt;
&lt;h2&gt;State of the Art&lt;/h2&gt;
&lt;p&gt;This is not an academic publication, and my goal was primarily to explore the
arcane of the Haskell type system, so I might have skipped the proper study of
the state of the art. That being said, I have written programs in Rust and
Haskell before.&lt;/p&gt;
&lt;h3&gt;Starting Point&lt;/h3&gt;
&lt;p&gt;In Rust, &lt;code class=&quot;hljs language-rust&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Result&lt;/span&gt;&amp;lt;T, E&amp;gt;&lt;/code&gt; is the counterpart of &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Either&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;E&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;T&lt;/span&gt;&lt;/code&gt; in
Haskell&lt;label for=&quot;fn3&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn3&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I wonder if they deliberately choose to swap the two type arguments. &lt;/span&gt;
&lt;/span&gt;. You can use it to model to wrap either the result of a
function (&lt;code class=&quot;hljs&quot;&gt;T&lt;/code&gt;) or an error encountered during this computation (~E~). Both
&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Either&lt;/span&gt;&lt;/code&gt; and &lt;code class=&quot;hljs language-rust&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Result&lt;/span&gt;&lt;/code&gt; are used in order to achieve the same
end, that is writing functions which might fail.&lt;/p&gt;
&lt;p&gt;On the one hand, &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Either&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;E&lt;/span&gt;&lt;/code&gt; is a monad. It works exactly as
&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Maybe&lt;/span&gt;&lt;/code&gt; (returning an error acts as a shortcut for the rest of the
function), but gives you the ability to specify &lt;em&gt;why&lt;/em&gt; the function has failed.
To deal with effects, the &lt;code class=&quot;hljs&quot;&gt;mtl&lt;/code&gt; package provides &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;EitherT&lt;/span&gt;&lt;/code&gt;, a
transformer version of &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Either&lt;/span&gt;&lt;/code&gt; to be used in a monad stack.&lt;/p&gt;
&lt;p&gt;On the other hand, the Rust language provides the &lt;code class=&quot;hljs language-rust&quot;&gt;?&lt;/code&gt; syntactic sugar,
to achieve the same thing. That is, both languages provide you the means to
write potentially failing functions without the need to care locally about
failure. If your function &lt;code class=&quot;hljs&quot;&gt;f&lt;/code&gt; uses a function &lt;code class=&quot;hljs&quot;&gt;g&lt;/code&gt; which might fail, and want to
fail yourself if &lt;code class=&quot;hljs&quot;&gt;f&lt;/code&gt; fails, it becomes trivial.&lt;/p&gt;
&lt;p&gt;Out of the box, neither &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;EitherT&lt;/span&gt;&lt;/code&gt; nor &lt;code class=&quot;hljs language-rust&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Result&lt;/span&gt;&lt;/code&gt; is extensible.
The functions must use the exact same &lt;code class=&quot;hljs&quot;&gt;E&lt;/code&gt;, or errors must be converted
manually.&lt;/p&gt;
&lt;h3&gt;Handling Errors in Rust&lt;/h3&gt;
&lt;p&gt;Rust and the &lt;code class=&quot;hljs&quot;&gt;error-chain&lt;/code&gt; crate provide several means to overcome this
limitation. In particular, it has the &lt;code class=&quot;hljs language-rust&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;Into&lt;/span&gt;&lt;/code&gt; and &lt;code class=&quot;hljs language-rust&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;From&lt;/span&gt;&lt;/code&gt; traits to
ease the conversion from one error to another. Among other things, the
&lt;code class=&quot;hljs&quot;&gt;error-chain&lt;/code&gt; crate provides a macro to easily define a wrapper around many
errors types, basically your own and the one defined by the crates you are
using.&lt;/p&gt;
&lt;p&gt;I see several drawbacks to this approach. First, it is extensible if you take
the time to modify the wrapper type each time you want to consider a new error
type. Second, either you can either use one error type or every error
type.&lt;/p&gt;
&lt;p&gt;However, the &lt;code class=&quot;hljs&quot;&gt;error-chain&lt;/code&gt; package provides a way to solve a very annoying
limitation of &lt;code class=&quot;hljs language-rust&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Result&lt;/span&gt;&lt;/code&gt; and &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Either&lt;/span&gt;&lt;/code&gt;. When you “catch” an
error, after a given function returns its result, it can be hard to determine
from where the error is coming from. Imagine you are parsing a very complicated
source file, and the error you get is &lt;code class=&quot;hljs language-rust&quot;&gt;SyntaxError&lt;/code&gt; with no additional
context. How would you feel?&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;hljs&quot;&gt;error-chain&lt;/code&gt; solves this by providing an API to construct a chain of errors,
rather than a single value.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-rust&quot;&gt;&lt;span class=&quot;hljs-title function_ invoke__&quot;&gt;my_function&lt;/span&gt;().&lt;span class=&quot;hljs-title function_ invoke__&quot;&gt;chain_err&lt;/span&gt;(|| &lt;span class=&quot;hljs-string&quot;&gt;&quot;a message with some context&quot;&lt;/span&gt;)?;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code class=&quot;hljs&quot;&gt;chain_err&lt;/code&gt; function makes it easier to replace a given error in its
context, leading to be able to write more meaningful error messages for
instance.&lt;/p&gt;
&lt;h2&gt;The &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt;&lt;/code&gt; Monad&lt;/h2&gt;
&lt;p&gt;The &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt;&lt;/code&gt; is an attempt to bring together the extensible power of
&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Eff&lt;/span&gt;&lt;/code&gt; and the chaining of errors of &lt;code class=&quot;hljs&quot;&gt;chain_err&lt;/code&gt;. I will admit that,
for the latter, the current implementation of &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt;&lt;/code&gt; is probably
less powerful, but to be honest I mostly cared about the “extensible” thing, so
it is not very surprising.&lt;/p&gt;
&lt;p&gt;This monad is an alternative to neither Monad Stacks a la mtl nor to the
&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Eff&lt;/span&gt;&lt;/code&gt; monad. In its current state, it aims to be a more powerful and
flexible version of &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;EitherT&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Parameters&lt;/h3&gt;
&lt;p&gt;As often in Haskell, the &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt;&lt;/code&gt; monad can be parameterized in
several ways.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt; msg (&lt;span class=&quot;hljs-title&quot;&gt;err&lt;/span&gt; :: [*]) m a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;msg&lt;/span&gt;&lt;/code&gt; is the type of messages you can stack to provide more context
to error handling&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;err&lt;/span&gt;&lt;/code&gt; is a &lt;em&gt;row of errors&lt;/em&gt;&lt;label for=&quot;fn4&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn4&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;You might have noticed &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;err&lt;/span&gt;&lt;/code&gt; is of kind &lt;code class=&quot;hljs language-haskell&quot;&gt;[*]&lt;/code&gt;. To write such a thing,
you will need the
&lt;a href=&quot;https://www.schoolofhaskell.com/user/konn/prove-your-haskell-for-great-safety/dependent-types-in-haskell&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;DataKinds&lt;/span&gt;&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;
GHC pragmas. &lt;/span&gt;
&lt;/span&gt;, it basically describes the set of
errors you will eventually have to handle&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;m&lt;/span&gt;&lt;/code&gt; is the underlying monad stack of your application, knowing that
&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt;&lt;/code&gt; is not intended to be stacked itself&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;a&lt;/span&gt;&lt;/code&gt; is the expected type of the computation result&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;achieve&lt;/span&gt;&lt;/code&gt; and &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;abort&lt;/span&gt;&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The two main monadic operations which comes with ~ResultT~ are ~achieve~ and
~abort~. The former allows for building the context, by stacking so-called
messages which describe what you want to do. The latter allows for bailing on a
computation and explaining why.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;achieve&lt;/span&gt; :: (&lt;span class=&quot;hljs-type&quot;&gt;Monad&lt;/span&gt; m)
        =&amp;gt; msg
        -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt; msg err m a
        -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt; msg err m a
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;achieve&lt;/span&gt;&lt;/code&gt; should be used for &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;do&lt;/span&gt;&lt;/code&gt; blocks. You can use
&lt;code class=&quot;hljs language-haskell&quot;&gt;&amp;lt;?&amp;gt;&lt;/code&gt; to attach a contextual message to a given computation.&lt;/p&gt;
&lt;p&gt;The type signature of &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;abort&lt;/span&gt;&lt;/code&gt; is also interesting, because it
introduces the &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Contains&lt;/span&gt;&lt;/code&gt; typeclass (e.g., it is equivalent to
&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Member&lt;/span&gt;&lt;/code&gt; for &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Eff&lt;/span&gt;&lt;/code&gt;).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;abort&lt;/span&gt; :: (&lt;span class=&quot;hljs-type&quot;&gt;Contains&lt;/span&gt; err e, &lt;span class=&quot;hljs-type&quot;&gt;Monad&lt;/span&gt; m)
      =&amp;gt; e
      -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt; msg err m a
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This reads as follows: “&lt;em&gt;you can abort with an error of type &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;e&lt;/span&gt;&lt;/code&gt; if
and only if the row of errors &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;err&lt;/span&gt;&lt;/code&gt; contains the type
&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;e&lt;/span&gt;&lt;/code&gt;.&lt;/em&gt;”&lt;/p&gt;
&lt;p&gt;For instance, imagine we have an error type &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;FileError&lt;/span&gt;&lt;/code&gt; to describe
filesystem-related errors. Then, we can imagine the following function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;readContent&lt;/span&gt; :: (&lt;span class=&quot;hljs-type&quot;&gt;Contains&lt;/span&gt; err &lt;span class=&quot;hljs-type&quot;&gt;FileError&lt;/span&gt;, &lt;span class=&quot;hljs-type&quot;&gt;MonadIO&lt;/span&gt; m)
            =&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;FilePath&lt;/span&gt;
            -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt; msg err m &lt;span class=&quot;hljs-type&quot;&gt;String&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We could leverage this function in a given project, for instance, to read its
configuration files (for the sake of the example, it has several configuration
files). This function can use its own type to describe ill-formed description
(&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;ConfigurationError&lt;/span&gt;&lt;/code&gt;).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;parseConfiguration&lt;/span&gt; :: (&lt;span class=&quot;hljs-type&quot;&gt;Contains&lt;/span&gt; err &lt;span class=&quot;hljs-type&quot;&gt;ConfigurationError&lt;/span&gt;, &lt;span class=&quot;hljs-type&quot;&gt;MonadIO&lt;/span&gt; m)
                   =&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;String&lt;/span&gt;
                   -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;String&lt;/span&gt;
                   -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt; msg err m &lt;span class=&quot;hljs-type&quot;&gt;Configuration&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To avoid repeating &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Contains&lt;/span&gt;&lt;/code&gt; when the row of errors needs to
contains several elements, we introduce &lt;code class=&quot;hljs language-haskell&quot;&gt;:&amp;lt;&lt;/code&gt;&lt;label for=&quot;fn5&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn5&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;If you are confused by &lt;code class=&quot;hljs language-haskell&quot;&gt;:&amp;lt;&lt;/code&gt;, it is probably because you were
not aware that the
&lt;a href=&quot;https://ocharles.org.uk/blog/posts/2014-12-08-type-operators.html&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;TypeOperators&lt;/span&gt;&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;
GHC pragma was a thing. &lt;/span&gt;
&lt;/span&gt; (read &lt;em&gt;subset or
equal&lt;/em&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;getConfig&lt;/span&gt; :: ( &apos;[&lt;span class=&quot;hljs-type&quot;&gt;FileError&lt;/span&gt;, &lt;span class=&quot;hljs-type&quot;&gt;ConfigurationError&lt;/span&gt;] :&amp;lt; err
             , &lt;span class=&quot;hljs-type&quot;&gt;MonadIO&lt;/span&gt; m)
             =&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;String&lt;/span&gt; err m &lt;span class=&quot;hljs-type&quot;&gt;Configuration&lt;/span&gt;
&lt;span class=&quot;hljs-title&quot;&gt;getConfig&lt;/span&gt; = &lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt;
  achieve &lt;span class=&quot;hljs-string&quot;&gt;&quot;get configuration from ~/.myapp directory&quot;&lt;/span&gt; $ &lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt;
    f1 &amp;lt;- readContent &lt;span class=&quot;hljs-string&quot;&gt;&quot;~/.myapp/init.conf&quot;&lt;/span&gt;
              &amp;lt;?&amp;gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;fetch the main configuration&quot;&lt;/span&gt;
    f2 &amp;lt;- readContent &lt;span class=&quot;hljs-string&quot;&gt;&quot;~/.myapp/net.conf&quot;&lt;/span&gt;
              &amp;lt;?&amp;gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;fetch the net-related configuration&quot;&lt;/span&gt;

    parseConfiguration f1 f2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You might see, now, why I say ~ResultT~ is extensible. You can use two functions
with totally unrelated errors, as long as the caller advertises that with
~Contains~ or ~:&amp;lt;~.&lt;/p&gt;
&lt;h3&gt;Recovering by Handling Errors&lt;/h3&gt;
&lt;p&gt;Monads are traps, you can only escape them by playing with their
rules. &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt;&lt;/code&gt; comes with &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;runResultT&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;runResultT&lt;/span&gt; :: &lt;span class=&quot;hljs-type&quot;&gt;Monad&lt;/span&gt; m =&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt; msg &apos;[] m a -&amp;gt; m a
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This might be surprising: we can only escape out from the &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt;&lt;/code&gt;
if we do not use &lt;em&gt;any errors at all&lt;/em&gt;. That is, &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt;&lt;/code&gt; forces us to
handle errors before calling &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;runResultT&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt;&lt;/code&gt; provides several functions prefixed by &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;recover&lt;/span&gt;&lt;/code&gt;.
Their type signatures can be a little confusing, so we will dive into the
simpler one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;recover&lt;/span&gt; :: &lt;span class=&quot;hljs-keyword&quot;&gt;forall&lt;/span&gt; e m msg err a.
           (&lt;span class=&quot;hljs-type&quot;&gt;Monad&lt;/span&gt; m)
        =&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt; msg (e &apos;: err) m a
        -&amp;gt; (e -&amp;gt; [msg] -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt; msg err m a)
        -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt; msg err m a
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;recover&lt;/span&gt;&lt;/code&gt; allows for &lt;em&gt;removing&lt;/em&gt; an error type from the row of errors,
To do that, it requires to provide an error handler to determine what to do
with the error raised during the computation and the stack of messages at that
time. Using &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;recover&lt;/span&gt;&lt;/code&gt;, a function may use more errors than advertised
in its type signature, but we know by construction that in such a case, it
handles these errors so that it is transparent for the function user. The type
of the handler is &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;e&lt;/span&gt; -&amp;gt; [msg] -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt; msg err m a&lt;/code&gt;, which means
the handler &lt;em&gt;can raise errors if required&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;recoverWhile&lt;/span&gt; msg&lt;/code&gt; is basically a synonym for &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;achieve&lt;/span&gt; msg $ recover&lt;/code&gt;. &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;recoverMany&lt;/span&gt;&lt;/code&gt; allows for doing the same with a
row of errors, by providing as many functions as required. Finally,
&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;recoverManyWith&lt;/span&gt;&lt;/code&gt; simplifies &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;recoverMany&lt;/span&gt;&lt;/code&gt;: you can provide
only one function tied to a given typeclass, on the condition that the handling
errors implement this typeclass.&lt;/p&gt;
&lt;p&gt;Using &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;recover&lt;/span&gt;&lt;/code&gt; and its siblings often require to help a bit the
Haskell type system, especially if we use lambdas to define the error handlers.
Doing that is usually achieved with the &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Proxy&lt;/span&gt; a&lt;/code&gt; dataype (where
&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;a&lt;/span&gt;&lt;/code&gt; is a phantom type). I would rather use the
&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;TypeApplications&lt;/span&gt;&lt;/code&gt; pragma&lt;label for=&quot;fn6&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn6&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;The
&lt;a href=&quot;https://medium.com/@zyxoas/abusing-haskell-dependent-types-to-make-redis-queues-safer-cc31db943b6c&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;TypeApplications&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;
pragmas is probably one of my favorites.&lt;/span&gt;
&lt;span class=&quot;footnote-p&quot;&gt;When I use it, it feels almost like if I were writing a Coq document. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;recoverManyWith&lt;/span&gt; @[&lt;span class=&quot;hljs-type&quot;&gt;FileError&lt;/span&gt;, &lt;span class=&quot;hljs-type&quot;&gt;NetworkError&lt;/span&gt;] @&lt;span class=&quot;hljs-type&quot;&gt;DescriptiveError&lt;/span&gt;
    (&lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt; x &amp;lt;- readFromFile f
        y &amp;lt;- readFromNetwork socket
        printToStd x y)
    printErrorAndStack
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;DecriptiveError&lt;/span&gt;&lt;/code&gt; typeclass can be seen as a dedicated
&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Show&lt;/span&gt;&lt;/code&gt;, to give textual representation of errors. It is inspired by
the macros of &lt;code class=&quot;hljs&quot;&gt;error_chain&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We can start from an empty row of errors, and allows ourselves to
use more errors thanks to the &lt;code class=&quot;hljs&quot;&gt;recover*&lt;/code&gt; functions.&lt;/p&gt;
&lt;h2&gt;&lt;code class=&quot;hljs&quot;&gt;cat&lt;/code&gt; in Haskell using &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt;&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt;&lt;/code&gt; only cares about error handling. The rest of the work is up
to the underlying monad &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;m&lt;/span&gt;&lt;/code&gt;. That being said, nothing forbids us to
provide fine-grained API, &lt;em&gt;e.g.&lt;/em&gt;, for Filesystem-related functions. From an
error handling perspective, the functions provided by &lt;code class=&quot;hljs&quot;&gt;Prelude&lt;/code&gt; (the standard
library of Haskell) are pretty poor, and the documentation is not really
precise regarding the kind of error we can encounter while using it.&lt;/p&gt;
&lt;p&gt;In this section, I will show you how we can leverage &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt;&lt;/code&gt; to
&lt;strong&gt;(i)&lt;/strong&gt; define an error-centric API for basic file management functions and
&lt;strong&gt;(ii)&lt;/strong&gt; use this API to implement a &lt;code class=&quot;hljs&quot;&gt;cat&lt;/code&gt;-like program which read a file and
print its content in the standard output.&lt;/p&gt;
&lt;h3&gt;(A Lot Of) Error Types&lt;/h3&gt;
&lt;p&gt;We could have one sum type to describe in the same place all the errors we can
find, and later use the pattern matching feature of Haskell to determine which
one has been raised. The thing is, this is already the job done by the row of
errors of ~ResultT~. Besides, this means that we could raise an error for being
not able to write something into a file in a function which /opens/ a file.&lt;/p&gt;
&lt;p&gt;Because ~ResultT~ is intended to be extensible, we should rather define several
types, so we can have a fine-grained row of errors. Of course, too many types
will become burdensome, so this is yet another time where we need to find the
right balance.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;AlreadyInUse&lt;/span&gt; = &lt;span class=&quot;hljs-type&quot;&gt;AlreadyInUse&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;FilePath&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;DoesNotExist&lt;/span&gt; = &lt;span class=&quot;hljs-type&quot;&gt;DoesNotExist&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;FilePath&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;AccessDeny&lt;/span&gt; = &lt;span class=&quot;hljs-type&quot;&gt;AccessDeny&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;FilePath&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;IO&lt;/span&gt;.&lt;span class=&quot;hljs-type&quot;&gt;IOMode&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;EoF&lt;/span&gt; = &lt;span class=&quot;hljs-type&quot;&gt;EoF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;IllegalOperation&lt;/span&gt; = &lt;span class=&quot;hljs-type&quot;&gt;IllegalRead&lt;/span&gt; | &lt;span class=&quot;hljs-type&quot;&gt;IllegalWrite&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To be honest, this is a bit too much for the real life, but we are in a blog post
here, so we should embrace the potential of &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Filesystem API&lt;/h3&gt;
&lt;p&gt;By reading the
&lt;a href=&quot;https://hackage.haskell.org/package/base-4.9.1.0/docs/System-IO.html&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;System&lt;/span&gt;.&lt;span class=&quot;hljs-type&quot;&gt;IO&lt;/span&gt;&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;
documentation, we can infer what our functions type signatures should look
like. I will not discuss their actual implementation in this article, as this
requires me to explain how &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;IO&lt;/span&gt;&lt;/code&gt; deals with errors itself (and this
article is already long enough to my taste). You can have a look at &lt;a href=&quot;https://gist.github.com/lthms/c669e68e284a056dc8c0c3546b4efe56&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;this
gist&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; if you
are interested.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;openFile&lt;/span&gt; :: ( &apos;[&lt;span class=&quot;hljs-type&quot;&gt;AlreadyInUse&lt;/span&gt;, &lt;span class=&quot;hljs-type&quot;&gt;DoesNotExist&lt;/span&gt;, &lt;span class=&quot;hljs-type&quot;&gt;AccessDeny&lt;/span&gt;] :&amp;lt; err
            , &lt;span class=&quot;hljs-type&quot;&gt;MonadIO&lt;/span&gt; m)
         =&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;FilePath&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;IOMode&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt; msg err m &lt;span class=&quot;hljs-type&quot;&gt;Handle&lt;/span&gt;

&lt;span class=&quot;hljs-title&quot;&gt;getLine&lt;/span&gt; :: (&apos;[&lt;span class=&quot;hljs-type&quot;&gt;IllegalOperation&lt;/span&gt;, &lt;span class=&quot;hljs-type&quot;&gt;EoF&lt;/span&gt;] :&amp;lt; err, &lt;span class=&quot;hljs-type&quot;&gt;MonadIO&lt;/span&gt; m)
        =&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;IO&lt;/span&gt;.&lt;span class=&quot;hljs-type&quot;&gt;Handle&lt;/span&gt;
        -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt; msg err m &lt;span class=&quot;hljs-type&quot;&gt;Text&lt;/span&gt;

&lt;span class=&quot;hljs-title&quot;&gt;closeFile&lt;/span&gt; :: (&lt;span class=&quot;hljs-type&quot;&gt;MonadIO&lt;/span&gt; m)
          =&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;IO&lt;/span&gt;.&lt;span class=&quot;hljs-type&quot;&gt;Handle&lt;/span&gt;
          -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt; msg err m ()
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Implementing &lt;code class=&quot;hljs&quot;&gt;cat&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;We can use the &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt;&lt;/code&gt; monad, its monadic operations and our
functions to deal with the file system in order to implement a &lt;code class=&quot;hljs&quot;&gt;cat&lt;/code&gt;-like
program. I tried to comment on the implementation to make it easier to follow.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;cat&lt;/span&gt; :: &lt;span class=&quot;hljs-type&quot;&gt;FilePath&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;String&lt;/span&gt; err &lt;span class=&quot;hljs-type&quot;&gt;IO&lt;/span&gt; ()
&lt;span class=&quot;hljs-title&quot;&gt;cat&lt;/span&gt; path =
  &lt;span class=&quot;hljs-comment&quot;&gt;-- We will try to open and read this file to mimic&lt;/span&gt;
  &lt;span class=&quot;hljs-comment&quot;&gt;-- `cat` behaviour.&lt;/span&gt;
  &lt;span class=&quot;hljs-comment&quot;&gt;-- We advertise that in case something goes wrong&lt;/span&gt;
  &lt;span class=&quot;hljs-comment&quot;&gt;-- the process.&lt;/span&gt;
  achieve (&lt;span class=&quot;hljs-string&quot;&gt;&quot;cat &quot;&lt;/span&gt; ++ path) $ &lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;hljs-comment&quot;&gt;-- We will recover from a potential error,&lt;/span&gt;
    &lt;span class=&quot;hljs-comment&quot;&gt;-- but we will abstract away the error using&lt;/span&gt;
    &lt;span class=&quot;hljs-comment&quot;&gt;-- the `DescriptiveError` typeclass. This way,&lt;/span&gt;
    &lt;span class=&quot;hljs-comment&quot;&gt;-- we do not need to give one handler by error&lt;/span&gt;
    &lt;span class=&quot;hljs-comment&quot;&gt;-- type.&lt;/span&gt;
    recoverManyWith @[&lt;span class=&quot;hljs-type&quot;&gt;Fs&lt;/span&gt;.&lt;span class=&quot;hljs-type&quot;&gt;AlreadyInUse&lt;/span&gt;, &lt;span class=&quot;hljs-type&quot;&gt;Fs&lt;/span&gt;.&lt;span class=&quot;hljs-type&quot;&gt;DoesNotExist&lt;/span&gt;, &lt;span class=&quot;hljs-type&quot;&gt;Fs&lt;/span&gt;.&lt;span class=&quot;hljs-type&quot;&gt;AccessDeny&lt;/span&gt;, &lt;span class=&quot;hljs-type&quot;&gt;Fs&lt;/span&gt;.&lt;span class=&quot;hljs-type&quot;&gt;IllegalOperation&lt;/span&gt;]
                    @(&lt;span class=&quot;hljs-type&quot;&gt;Fs&lt;/span&gt;.&lt;span class=&quot;hljs-type&quot;&gt;DescriptiveError&lt;/span&gt;)
      (&lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt; f &amp;lt;- &lt;span class=&quot;hljs-type&quot;&gt;Fs&lt;/span&gt;.openFile path &lt;span class=&quot;hljs-type&quot;&gt;Fs&lt;/span&gt;.&lt;span class=&quot;hljs-type&quot;&gt;ReadMode&lt;/span&gt;
          &lt;span class=&quot;hljs-comment&quot;&gt;-- `repeatUntil` works like `recover`, except&lt;/span&gt;
          &lt;span class=&quot;hljs-comment&quot;&gt;-- it repeats the computation until the error&lt;/span&gt;
          &lt;span class=&quot;hljs-comment&quot;&gt;-- actually happpens.&lt;/span&gt;
          &lt;span class=&quot;hljs-comment&quot;&gt;-- I could not have used `getLine` without&lt;/span&gt;
          &lt;span class=&quot;hljs-comment&quot;&gt;-- `repeatUntil` or `recover`, as it is not&lt;/span&gt;
          &lt;span class=&quot;hljs-comment&quot;&gt;-- in the row of errors allowed by&lt;/span&gt;
          &lt;span class=&quot;hljs-comment&quot;&gt;-- `recoverManyWith`.&lt;/span&gt;
          repeatUntil @(&lt;span class=&quot;hljs-type&quot;&gt;Fs&lt;/span&gt;.&lt;span class=&quot;hljs-type&quot;&gt;EoF&lt;/span&gt;)
              (&lt;span class=&quot;hljs-type&quot;&gt;Fs&lt;/span&gt;.getLine f &amp;gt;&amp;gt;= liftIO . print)
              (\_ _ -&amp;gt; liftIO $ putStrLn &lt;span class=&quot;hljs-string&quot;&gt;&quot;%EOF&quot;&lt;/span&gt;)
          closeFile f)
      printErrorAndStack
    &lt;span class=&quot;hljs-keyword&quot;&gt;where&lt;/span&gt;
      &lt;span class=&quot;hljs-comment&quot;&gt;-- Using the `DescriptiveError` typeclass, we&lt;/span&gt;
      &lt;span class=&quot;hljs-comment&quot;&gt;-- can print both the stack of Strings which form&lt;/span&gt;
      &lt;span class=&quot;hljs-comment&quot;&gt;-- the context, and the description of the generic&lt;/span&gt;
      &lt;span class=&quot;hljs-comment&quot;&gt;-- error.&lt;/span&gt;
      printErrorAndStack e ctx = &lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt;
        liftIO . putStrLn $ &lt;span class=&quot;hljs-type&quot;&gt;Fs&lt;/span&gt;.describe e
        liftIO $ putStrLn &lt;span class=&quot;hljs-string&quot;&gt;&quot;stack:&quot;&lt;/span&gt;
        liftIO $ print ctx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The type signature of &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;cat&lt;/span&gt;&lt;/code&gt; teaches us that this function handles any
error it might encounter. This means we can use it anywhere we want: both in
another computation inside &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt;&lt;/code&gt; which might raise errors
completely unrelated to the file system, or we can use it with
&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;runResultT&lt;/span&gt;&lt;/code&gt;, escaping the &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;ResultT&lt;/span&gt;&lt;/code&gt; monad (only to fall
into the &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;IO&lt;/span&gt;&lt;/code&gt; monad, but this is another story).&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>Monad Transformers are a Great Abstraction</title>
      <link>https://soap.coffee/~lthms/posts/MonadTransformers.html</link>
      <guid>https://soap.coffee/~lthms/posts/MonadTransformers.html</guid>
      <pubDate>July 15, 2017</pubDate>
      <description>
        
        &lt;h1&gt;Monad Transformers are a Great Abstraction&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/haskell.html&quot; class=&quot;tag hover-mint&quot; marked=&quot;&quot;&gt;haskell&lt;/a&gt; &lt;/div&gt;
&lt;div class=&quot;markdown-alert markdown-alert-caution&quot;&gt;&lt;p class=&quot;markdown-alert-title&quot;&gt;&lt;svg class=&quot;octicon octicon-stop mr-2&quot; viewbox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;Caution&lt;/p&gt;&lt;p&gt;Time has passed since the publication of this article. Whether or not I agree
with its conclusions is an open question. Monad Transformers are a great
abstraction, but nowadays I would most certainly choose another approach.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Monads are hard to get right. I think it took me around a year of Haskelling to
feel like I understood them. The reason is, to my opinion, there is not such
thing as &lt;em&gt;the&lt;/em&gt; Monad. It is even the contrary. When someone asks me how I would
define Monads in only a few words, I say monads are a convenient formalism to
chain specific computations. Once I’ve got that, I started noticing “monadic
construction” everywhere, from the Rust &lt;code class=&quot;hljs language-rust&quot;&gt;?&lt;/code&gt; operator to the &lt;a href=&quot;https://blog.drewolson.org/elixirs-secret-weapon/&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;Elixir
&lt;code class=&quot;hljs language-elixir&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;&lt;/code&gt; keyword&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Haskell often uses another concept above Monads: Monad Transformers. This allows
you to work not only with &lt;em&gt;one&lt;/em&gt; Monad, but rather a stack. Each Monad brings its
own properties and you can mix them into your very own one. That you can’t have
in Rust or Elixir, but it works great in Haskell. Unfortunately, it is not an
easy concept and it can be hard to understand. This article is not an attempt to
do so, but rather a postmortem review of one situation where I found them
extremely useful. If you think you have understood how they work, but don’t see
the point yet, you might find here a beginning of the answer.&lt;/p&gt;
&lt;p&gt;Recently, I ran into a very good example of why Monad Transformers worth it. I
have been working on a project called ogma for a couple years now. In a
nutshell, I want to build “a tool” to visualize in time and space a
storytelling. We are not here just yet, but, in the meantime, I have written a
software called &lt;code class=&quot;hljs&quot;&gt;celtchar&lt;/code&gt; to build a novel from a list of files. One of its
newest features is the choice of language, and by extension, the typographic
rules. This information is read from a configuration file very early in the
program flow. Unfortunately, its use comes much later, after several function
calls.&lt;/p&gt;
&lt;p&gt;In Haskell, you deal with that kind of challenge by relying on the Reader
Monad. It carries an environment in a transparent way. The only thing is, I was
already using the State Monad to carry the computation result. But that’s not an
issue with the Monad Transformers.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-diff&quot;&gt;&lt;span class=&quot;hljs-deletion&quot;&gt;-type Builder = StateT Text IO&lt;/span&gt;
&lt;span class=&quot;hljs-addition&quot;&gt;+type Builder = StateT Text (ReaderT Language IO)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you may have already understood, I wasn&apos;t using the “raw” &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;State&lt;/span&gt;&lt;/code&gt;
Monad, but rather the transformer version &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;StateT&lt;/span&gt;&lt;/code&gt;. The underlying
Monad was &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;IO&lt;/span&gt;&lt;/code&gt;, because I needed to be able to read some files from
the file system. By replacing &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;IO&lt;/span&gt;&lt;/code&gt; by &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;ReaderT&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;Language&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;IO&lt;/span&gt;&lt;/code&gt;,
I basically fixed my “carry the variable to the correct function call easily”
problem.&lt;/p&gt;
&lt;p&gt;Retrieving the chosen language is as simple as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;getLanguage&lt;/span&gt; :: &lt;span class=&quot;hljs-type&quot;&gt;Builder&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;Language&lt;/span&gt;
&lt;span class=&quot;hljs-title&quot;&gt;getLanguage&lt;/span&gt; = lift ask
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that was basically it.&lt;/p&gt;
&lt;p&gt;Now, my point is not that Monad Transformers are the ultimate beast we will have
to tame once and then everything will be shiny and easy&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;It is amusing to see Past Me being careful here. &lt;/span&gt;
&lt;/span&gt;. There are a lot of
other ways to achieve what I did with my &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Builder&lt;/span&gt;&lt;/code&gt; stack. For instance, in an
OO language, I probably would have to add a new class member to my &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Builder&lt;/span&gt;&lt;/code&gt;
class and I would have done basically the same thing.&lt;/p&gt;
&lt;p&gt;However, there is something I really like about this approach: the
&lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Builder&lt;/span&gt;&lt;/code&gt; type definition gives you a lot of useful information
already. Both the &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;State&lt;/span&gt;&lt;/code&gt; and &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Reader&lt;/span&gt;&lt;/code&gt; Monads have a
well-established semantics most Haskellers will understand in a glance. A bit
of documentation won’t hurt, but I suspect it is not as necessary as one could
expect. Moreover, the presence of the &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;IO&lt;/span&gt;&lt;/code&gt; Monad tells everyone using
the &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Builder&lt;/span&gt;&lt;/code&gt; Monad might cause I/O.&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>Rewriting in Coq</title>
      <link>https://soap.coffee/~lthms/posts/RewritingInCoq.html</link>
      <guid>https://soap.coffee/~lthms/posts/RewritingInCoq.html</guid>
      <pubDate>May 13, 2017</pubDate>
      <description>
        
        &lt;h1&gt;Rewriting in Coq&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/coq.html&quot; class=&quot;tag hover-lavender&quot; marked=&quot;&quot;&gt;coq&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;I have to confess something. In the codebase of SpecCert lies a shameful
secret, which takes the form of a set of unnecessary axioms.&lt;/p&gt;
&lt;p&gt;I thought I couldn’t avoid them at first, but it was before I heard about
“generalized rewriting,” setoids and morphisms.  Now, I know the truth, and I
will have to update SpecCert eventually. But, in the meantime, let me try to
explain how it is possible to rewrite a term in a proof using an ad hoc
equivalence relation and, when necessary, a proper morphism.&lt;/p&gt;
&lt;h2&gt;Case Study: Gate System&lt;/h2&gt;
&lt;p&gt;Now, why would anyone want such a thing as “generalized rewriting” when the
&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt;&lt;/code&gt; tactic works just fine.&lt;/p&gt;
&lt;p&gt;The thing is: it does not in some cases. To illustrate my statement, we will
consider the following definition of a gate in Coq:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Record&lt;/span&gt; Gate :=
  { open:           bool
  ; lock:           bool
  ; lock_is_close:  lock = true -&amp;gt; open = false
  }.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;According to this definition, a gate can be either open or closed. It can also
be locked, but if it is, it cannot be open at the same time. To express this
constraint, we embed the appropriate proposition inside the Record. By doing so,
we &lt;em&gt;know&lt;/em&gt; for sure that we will never meet an ill-formed &lt;code class=&quot;hljs language-coq&quot;&gt;Gate&lt;/code&gt; instance.
The Coq engine will prevent it, because to construct a gate, one will have to
prove the &lt;code class=&quot;hljs language-coq&quot;&gt;lock_is_close&lt;/code&gt; predicate holds.&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;hljs language-coq&quot;&gt;program&lt;/code&gt; attribute makes it easy to work with embedded proofs. For
instance, defining the ”open gate” is as easy as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Require&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Import&lt;/span&gt; Coq.&lt;span class=&quot;hljs-keyword&quot;&gt;Program&lt;/span&gt;.Tactics.

#[program]
&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; open_gate :=
  {| &lt;span class=&quot;hljs-type&quot;&gt;open&lt;/span&gt; := true
   ; lock := false
   |&lt;span class=&quot;hljs-type&quot;&gt;}.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Under the hood, &lt;code class=&quot;hljs language-coq&quot;&gt;program&lt;/code&gt; proves what needs to be proven, that is the
&lt;code class=&quot;hljs language-coq&quot;&gt;lock_is_close&lt;/code&gt; proposition. Just have a look at its output:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;open_gate has type-checked, generating 1 obligation(s)
Solving obligations automatically...
open_gate_obligation_1 is defined
No more obligations remaining
open_gate is defined
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this case, using &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Program&lt;/span&gt;&lt;/code&gt; is a bit like cracking a nut with a
sledgehammer. We can easily do it ourselves using the &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;refine&lt;/span&gt;&lt;/code&gt; tactic.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; open_gate&apos;: Gate.
  &lt;span class=&quot;hljs-built_in&quot;&gt;refine&lt;/span&gt; ({| &lt;span class=&quot;hljs-type&quot;&gt;open&lt;/span&gt; := true
           ; lock := false
          |&lt;span class=&quot;hljs-type&quot;&gt;}).
  intro&lt;/span&gt; Hfalse.
  &lt;span class=&quot;hljs-built_in&quot;&gt;discriminate&lt;/span&gt; Hfalse.
&lt;span class=&quot;hljs-keyword&quot;&gt;Defined&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;Gate&lt;/code&gt; Equality&lt;/h2&gt;
&lt;p&gt;What does it mean for two gates to be equal? Intuitively, we know they have to
share the same states (&lt;code class=&quot;hljs language-coq&quot;&gt;open&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;lock&lt;/code&gt; is our case).&lt;/p&gt;
&lt;h3&gt;Leibniz Equality Is Too Strong&lt;/h3&gt;
&lt;p&gt;When you write something like &lt;code class=&quot;hljs language-coq&quot;&gt;a = b&lt;/code&gt; in Coq, the &lt;code class=&quot;hljs language-coq&quot;&gt;=&lt;/code&gt; refers to the
&lt;code class=&quot;hljs language-coq&quot;&gt;eq&lt;/code&gt; function and this function relies on what is called the Leibniz Equality:
&lt;code class=&quot;hljs language-coq&quot;&gt;x&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;y&lt;/code&gt; are equal iff every property on &lt;code class=&quot;hljs language-coq&quot;&gt;A&lt;/code&gt; which is true
of &lt;code class=&quot;hljs language-coq&quot;&gt;x&lt;/code&gt; is also true of &lt;code class=&quot;hljs language-coq&quot;&gt;y&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As for myself, when I first started to write some Coq code, the
Leibniz Equality was not really something I cared about and I tried to
prove something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Lemma&lt;/span&gt; open_gates_are_equal (g g&apos;: Gate)
    (equ : open g = true) (equ&apos; : open g&apos; = true)
  : g = g&apos;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Basically, it means that if two doors are open, then they are equal. That made
sense to me, because by definition of &lt;code class=&quot;hljs language-coq&quot;&gt;Gate&lt;/code&gt;, a locked door is closed,
meaning an open door cannot be locked.&lt;/p&gt;
&lt;p&gt;Here is an attempt to prove the &lt;code class=&quot;hljs language-coq&quot;&gt;open_gates_are_equal&lt;/code&gt; lemma.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;.
  &lt;span class=&quot;hljs-built_in&quot;&gt;assert&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;forall&lt;/span&gt; g, open g = true -&amp;gt; lock g = false). {
    &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; [o l h] equo.
    &lt;span class=&quot;hljs-built_in&quot;&gt;cbn&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt; *.
    &lt;span class=&quot;hljs-built_in&quot;&gt;case_eq&lt;/span&gt; l; &lt;span class=&quot;hljs-built_in&quot;&gt;auto&lt;/span&gt;.
    &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; equl.
    now &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; (h equl) &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt; equo.
  }
  &lt;span class=&quot;hljs-built_in&quot;&gt;assert&lt;/span&gt; (lock g = false) &lt;span class=&quot;hljs-built_in&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; (H &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; equ).
  &lt;span class=&quot;hljs-built_in&quot;&gt;assert&lt;/span&gt; (lock g&apos; = false) &lt;span class=&quot;hljs-built_in&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; (H &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; equ&apos;).
  &lt;span class=&quot;hljs-built_in&quot;&gt;destruct&lt;/span&gt; g; &lt;span class=&quot;hljs-built_in&quot;&gt;destruct&lt;/span&gt; g&apos;; &lt;span class=&quot;hljs-built_in&quot;&gt;cbn&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt; *; &lt;span class=&quot;hljs-built_in&quot;&gt;subst&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The term to prove is now:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;{| open := true; lock := false; lock_is_close := lock_is_close0 |} =
{| open := true; lock := false; lock_is_close := lock_is_close1 |}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The next tactic I wanted to use &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;reflexivity&lt;/span&gt;&lt;/code&gt;, because I&apos;d basically proven
&lt;code class=&quot;hljs language-coq&quot;&gt;open g = open g&apos;&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;lock g = lock g&apos;&lt;/code&gt;, which meets my definition of equality
at that time.&lt;/p&gt;
&lt;p&gt;Except Coq wouldn’t agree. See how it reacts:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;Unable to unify &quot;{| open := true; lock := false; lock_is_close := lock_is_close1 |}&quot;
  with &quot;{| open := true; lock := false; lock_is_close := lock_is_close0 |}&quot;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It cannot unify the two records. More precisely, it cannot unify
&lt;code class=&quot;hljs language-coq&quot;&gt;lock_is_close1&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;lock_is_close0&lt;/code&gt;. So we abort and try something
else.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Abort&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Ah-Hoc Equivalence Relation&lt;/h3&gt;
&lt;p&gt;This is a familiar pattern. Coq cannot guess what we have in mind. Giving a
formal definition of “our equality” is fortunately straightforward.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; gate_eq
           (g g&apos;: Gate)
  : &lt;span class=&quot;hljs-keyword&quot;&gt;Prop&lt;/span&gt; :=
  open g = open g&apos; /\ lock g = lock g&apos;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because “equality” means something very specific in Coq, we won&apos;t say “two
gates are equal” anymore, but “two gates are equivalent.” That is,
&lt;code class=&quot;hljs language-coq&quot;&gt;gate_eq&lt;/code&gt; is an equivalence relation. But “equivalence relation” is also
something very specific. For instance, such relation needs to be symmetric (&lt;code class=&quot;hljs language-coq&quot;&gt;R x y -&amp;gt; R y x&lt;/code&gt;), reflexive (&lt;code class=&quot;hljs language-coq&quot;&gt;R x x&lt;/code&gt;) and transitive (&lt;code class=&quot;hljs language-coq&quot;&gt;R x y -&amp;gt; R y z -&amp;gt; R x z&lt;/code&gt;).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Require&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Import&lt;/span&gt; Coq.&lt;span class=&quot;hljs-keyword&quot;&gt;Classes&lt;/span&gt;.Equivalence.

#[program]
&lt;span class=&quot;hljs-keyword&quot;&gt;Instance&lt;/span&gt; Gate_Equivalence
  : Equivalence gate_eq.

&lt;span class=&quot;hljs-keyword&quot;&gt;Next&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Obligation&lt;/span&gt;.
  &lt;span class=&quot;hljs-built_in&quot;&gt;split&lt;/span&gt;; &lt;span class=&quot;hljs-built_in&quot;&gt;reflexivity&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;Defined&lt;/span&gt;.

&lt;span class=&quot;hljs-keyword&quot;&gt;Next&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Obligation&lt;/span&gt;.
  &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; g g&apos; [Hop Hlo].
  &lt;span class=&quot;hljs-built_in&quot;&gt;symmetry&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt; Hop; &lt;span class=&quot;hljs-built_in&quot;&gt;symmetry&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt; Hlo.
  &lt;span class=&quot;hljs-built_in&quot;&gt;split&lt;/span&gt;; &lt;span class=&quot;hljs-built_in&quot;&gt;assumption&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;Defined&lt;/span&gt;.

&lt;span class=&quot;hljs-keyword&quot;&gt;Next&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Obligation&lt;/span&gt;.
  &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; g g&apos; g&apos;&apos; [Hop Hlo] [Hop&apos; Hlo&apos;].
  &lt;span class=&quot;hljs-built_in&quot;&gt;split&lt;/span&gt;.
  + &lt;span class=&quot;hljs-built_in&quot;&gt;transitivity&lt;/span&gt; (open g&apos;); [&lt;span class=&quot;hljs-built_in&quot;&gt;exact&lt;/span&gt; Hop|&lt;span class=&quot;hljs-type&quot;&gt;exact&lt;/span&gt; Hop&apos;].
  + &lt;span class=&quot;hljs-built_in&quot;&gt;transitivity&lt;/span&gt; (lock g&apos;); [&lt;span class=&quot;hljs-built_in&quot;&gt;exact&lt;/span&gt; Hlo|&lt;span class=&quot;hljs-type&quot;&gt;exact&lt;/span&gt; Hlo&apos;].
&lt;span class=&quot;hljs-keyword&quot;&gt;Defined&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Afterwards, the &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;symmetry&lt;/span&gt;&lt;/code&gt;, &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;reflexivity&lt;/span&gt;&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;transitivity&lt;/span&gt;&lt;/code&gt;
tactics also works with &lt;code class=&quot;hljs language-coq&quot;&gt;gate_eq&lt;/code&gt;, in addition to &lt;code class=&quot;hljs language-coq&quot;&gt;eq&lt;/code&gt;. We can try
again to prove the &lt;code class=&quot;hljs language-coq&quot;&gt;open_gate_are_the_same&lt;/code&gt; lemma and it will
work&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I know I should have proven an intermediate lemma to avoid code
duplication. Sorry about that, it hurts my eyes too. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Lemma&lt;/span&gt; open_gates_are_the_same:
  &lt;span class=&quot;hljs-keyword&quot;&gt;forall&lt;/span&gt; (g g&apos;: Gate),
    open g = true
    -&amp;gt; open g&apos; = true
    -&amp;gt; gate_eq g g&apos;.
&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;.
  &lt;span class=&quot;hljs-built_in&quot;&gt;induction&lt;/span&gt; g; &lt;span class=&quot;hljs-built_in&quot;&gt;induction&lt;/span&gt; g&apos;.
  &lt;span class=&quot;hljs-built_in&quot;&gt;cbn&lt;/span&gt;.
  &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; H0 H2.
  &lt;span class=&quot;hljs-built_in&quot;&gt;assert&lt;/span&gt; (lock0 = false).
  + &lt;span class=&quot;hljs-built_in&quot;&gt;case_eq&lt;/span&gt; lock0; [ &lt;span class=&quot;hljs-built_in&quot;&gt;intro&lt;/span&gt; H; &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; lock_is_close0 &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt; H;
                     &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; H0 &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt; H;
                     &lt;span class=&quot;hljs-built_in&quot;&gt;discriminate&lt;/span&gt; H
                   | &lt;span class=&quot;hljs-type&quot;&gt;reflexivity&lt;/span&gt;
                   ].
  + &lt;span class=&quot;hljs-built_in&quot;&gt;assert&lt;/span&gt; (lock1 = false).
    * &lt;span class=&quot;hljs-built_in&quot;&gt;case_eq&lt;/span&gt; lock1; [ &lt;span class=&quot;hljs-built_in&quot;&gt;intro&lt;/span&gt; H&apos;; &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; lock_is_close1 &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt; H&apos;;
                       &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; H2 &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt; H&apos;;
                       &lt;span class=&quot;hljs-built_in&quot;&gt;discriminate&lt;/span&gt; H&apos;
                     | &lt;span class=&quot;hljs-type&quot;&gt;reflexivity&lt;/span&gt;
                     ].
    * &lt;span class=&quot;hljs-built_in&quot;&gt;subst&lt;/span&gt;.
      &lt;span class=&quot;hljs-built_in&quot;&gt;split&lt;/span&gt;; &lt;span class=&quot;hljs-built_in&quot;&gt;reflexivity&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;Qed&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Equivalence Relations and Rewriting&lt;/h2&gt;
&lt;p&gt;So here we are, with our ad hoc definition of gate equivalence. We can use
&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;symmetry&lt;/span&gt;&lt;/code&gt;, &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;reflexivity&lt;/span&gt;&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;transitivity&lt;/span&gt;&lt;/code&gt; along with
&lt;code class=&quot;hljs language-coq&quot;&gt;gate_eq&lt;/code&gt; and it works fine because we have told Coq &lt;code class=&quot;hljs language-coq&quot;&gt;gate_eq&lt;/code&gt; is
indeed an equivalence relation for &lt;code class=&quot;hljs language-coq&quot;&gt;Gate&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Can we do better? Can we actually use &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt;&lt;/code&gt; to replace an occurrence
of &lt;code class=&quot;hljs language-coq&quot;&gt;g&lt;/code&gt; by an occurrence of &lt;code class=&quot;hljs language-coq&quot;&gt;g’&lt;/code&gt; as long as we can prove that
&lt;code class=&quot;hljs language-coq&quot;&gt;gate_eq g g’&lt;/code&gt;? The answer is “yes”, but it will not come for free.&lt;/p&gt;
&lt;p&gt;Before moving forward, just consider the following function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Require&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Import&lt;/span&gt; Coq.Bool.Bool.

&lt;span class=&quot;hljs-keyword&quot;&gt;Program&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; try_open
        (g: Gate)
  : Gate :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; eqb (lock g) false
  &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt; {| &lt;span class=&quot;hljs-type&quot;&gt;lock&lt;/span&gt; := false
        ; open := true
       |&lt;span class=&quot;hljs-type&quot;&gt;}
  else&lt;/span&gt; g.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It takes a gate as an argument and returns a new gate. If the former is not
locked, the latter is open. Otherwise the argument is returned as is.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Lemma&lt;/span&gt; gate_eq_try_open_eq
  : &lt;span class=&quot;hljs-keyword&quot;&gt;forall&lt;/span&gt; (g g&apos;: Gate),
    gate_eq g g&apos;
    -&amp;gt; gate_eq (try_open g) (try_open g&apos;).
&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;.
  &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; g g&apos; Heq.
&lt;span class=&quot;hljs-keyword&quot;&gt;Abort&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What we could have wanted to do is: &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; Heq&lt;/code&gt;. Indeed, &lt;code class=&quot;hljs language-coq&quot;&gt;g&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;g’&lt;/code&gt;
“are the same” (&lt;code class=&quot;hljs language-coq&quot;&gt;gate_eq g g’&lt;/code&gt;), so, &lt;em&gt;of course&lt;/em&gt;, the results of &lt;code class=&quot;hljs language-coq&quot;&gt;try_open g&lt;/code&gt; and
&lt;code class=&quot;hljs language-coq&quot;&gt;try_open g’&lt;/code&gt; have to be the same. Except...&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;Error: Tactic failure: setoid rewrite failed: Unable to satisfy the following constraints:
UNDEFINED EVARS:
 ?X49==[g g&apos; Heq |- relation Gate] (internal placeholder) {?r}
 ?X50==[g g&apos; Heq (do_subrelation:=Morphisms.do_subrelation)
         |- Morphisms.Proper (gate_eq ==&amp;gt; ?X49@{__:=g; __:=g&apos;; __:=Heq}) try_open] (internal placeholder) {?p}
 ?X52==[g g&apos; Heq |- relation Gate] (internal placeholder) {?r0}
 ?X53==[g g&apos; Heq (do_subrelation:=Morphisms.do_subrelation)
         |- Morphisms.Proper (?X49@{__:=g; __:=g&apos;; __:=Heq} ==&amp;gt; ?X52@{__:=g; __:=g&apos;; __:=Heq} ==&amp;gt; Basics.flip Basics.impl) eq]
         (internal placeholder) {?p0}
 ?X54==[g g&apos; Heq |- Morphisms.ProperProxy ?X52@{__:=g; __:=g&apos;; __:=Heq} (try_open g&apos;)] (internal placeholder) {?p1}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What Coq is trying to tell us here —in a very poor manner, I’d say— is actually
pretty simple. It cannot replace &lt;code class=&quot;hljs language-coq&quot;&gt;g&lt;/code&gt; by &lt;code class=&quot;hljs language-coq&quot;&gt;g’&lt;/code&gt; because it does not
know if two equivalent gates actually give the same result when passed as the
argument of &lt;code class=&quot;hljs language-coq&quot;&gt;try_open&lt;/code&gt;. This is actually what we want to prove, so we
cannot use &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt;&lt;/code&gt; just yet, because it needs this result so it can do
its magic. Chicken and egg problem.&lt;/p&gt;
&lt;p&gt;In other words, we are making the same mistake as before: not telling Coq what
it cannot guess by itself.&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt;&lt;/code&gt; tactic works out of the box with the Coq equality
(&lt;code class=&quot;hljs language-coq&quot;&gt;eq&lt;/code&gt;, or most likely &lt;code class=&quot;hljs language-coq&quot;&gt;=&lt;/code&gt;) because of the Leibniz Equality:
&lt;code class=&quot;hljs language-coq&quot;&gt;x&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;y&lt;/code&gt; are equal iff every property on &lt;code class=&quot;hljs language-coq&quot;&gt;A&lt;/code&gt; which is true
of &lt;code class=&quot;hljs language-coq&quot;&gt;x&lt;/code&gt; is also true of &lt;code class=&quot;hljs language-coq&quot;&gt;y&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This is a pretty strong property, and one that a lot of equivalence relations do not
have. Want an example? Consider the relation &lt;code class=&quot;hljs language-coq&quot;&gt;R&lt;/code&gt; over &lt;code class=&quot;hljs language-coq&quot;&gt;A&lt;/code&gt; such that
forall &lt;code class=&quot;hljs language-coq&quot;&gt;x&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;y&lt;/code&gt;, &lt;code class=&quot;hljs language-coq&quot;&gt;R x y&lt;/code&gt; holds true. Such a relation is
reflexive, symmetric and reflexive. Yet, there is very little chance that given
a function &lt;code class=&quot;hljs language-coq&quot;&gt;f : A -&amp;gt; B&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;R’&lt;/code&gt; an equivalence relation over
&lt;code class=&quot;hljs language-coq&quot;&gt;B&lt;/code&gt;, &lt;code class=&quot;hljs language-coq&quot;&gt;R x y -&amp;gt; R&apos; (f x) (f y)&lt;/code&gt;. Only if we have this property, we
would know that we could rewrite &lt;code class=&quot;hljs language-coq&quot;&gt;f x&lt;/code&gt; by &lt;code class=&quot;hljs language-coq&quot;&gt;f y&lt;/code&gt;, &lt;em&gt;e.g.&lt;/em&gt;, in &lt;code class=&quot;hljs language-coq&quot;&gt;R&apos; z (f x)&lt;/code&gt;. Indeed, by transitivity of &lt;code class=&quot;hljs language-coq&quot;&gt;R’&lt;/code&gt;, we can deduce &lt;code class=&quot;hljs language-coq&quot;&gt;R&apos; z (f y)&lt;/code&gt; from &lt;code class=&quot;hljs language-coq&quot;&gt;R&apos; z (f x)&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;R (f x) (f y)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If &lt;code class=&quot;hljs language-coq&quot;&gt;R x y -&amp;gt; R&apos; (f x) (f y)&lt;/code&gt;, then &lt;code class=&quot;hljs language-coq&quot;&gt;f&lt;/code&gt; is a morphism because it
preserves an equivalence relation.  In our previous case, &lt;code class=&quot;hljs language-coq&quot;&gt;A&lt;/code&gt; is
&lt;code class=&quot;hljs language-coq&quot;&gt;Gate&lt;/code&gt;, &lt;code class=&quot;hljs language-coq&quot;&gt;R&lt;/code&gt; is &lt;code class=&quot;hljs language-coq&quot;&gt;gate_eq&lt;/code&gt;, &lt;code class=&quot;hljs language-coq&quot;&gt;f&lt;/code&gt; is &lt;code class=&quot;hljs language-coq&quot;&gt;try_open&lt;/code&gt; and
therefore &lt;code class=&quot;hljs language-coq&quot;&gt;B&lt;/code&gt; is &lt;code class=&quot;hljs language-coq&quot;&gt;Gate&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;R’&lt;/code&gt; is &lt;code class=&quot;hljs language-coq&quot;&gt;gate_eq&lt;/code&gt;. To make
Coq aware that &lt;code class=&quot;hljs language-coq&quot;&gt;try_open&lt;/code&gt; is a morphism, we can use the following syntax:
*)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;#[local]
&lt;span class=&quot;hljs-keyword&quot;&gt;Open&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Scope&lt;/span&gt; signature_scope.

&lt;span class=&quot;hljs-keyword&quot;&gt;Require&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Import&lt;/span&gt; Coq.&lt;span class=&quot;hljs-keyword&quot;&gt;Classes&lt;/span&gt;.Morphisms.

#[program]
&lt;span class=&quot;hljs-keyword&quot;&gt;Instance&lt;/span&gt; try_open_Proper
  : Proper (gate_eq ==&amp;gt; gate_eq) try_open.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This notation is actually more generic because you can deal with functions that
take more than one argument. Hence, given &lt;code class=&quot;hljs language-coq&quot;&gt;g : A -&amp;gt; B -&amp;gt; C -&amp;gt; D&lt;/code&gt;,
&lt;code class=&quot;hljs language-coq&quot;&gt;R&lt;/code&gt; (respectively &lt;code class=&quot;hljs language-coq&quot;&gt;R’&lt;/code&gt;, &lt;code class=&quot;hljs language-coq&quot;&gt;R’’&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;R’’’&lt;/code&gt;) an equivalent
relation of &lt;code class=&quot;hljs language-coq&quot;&gt;A&lt;/code&gt; (respectively &lt;code class=&quot;hljs language-coq&quot;&gt;B&lt;/code&gt;, &lt;code class=&quot;hljs language-coq&quot;&gt;C&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;D&lt;/code&gt;), we can
prove &lt;code class=&quot;hljs language-coq&quot;&gt;f&lt;/code&gt; is a morphism as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Add&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Parametric&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Morphism&lt;/span&gt;: (g)
    &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt; signature (R) ==&amp;gt; (R&apos;) ==&amp;gt; (R&apos;&apos;) ==&amp;gt; (R&apos;&apos;&apos;)
      &lt;span class=&quot;hljs-built_in&quot;&gt;as&lt;/span&gt; &amp;lt;name&amp;gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Back to our &lt;code class=&quot;hljs language-coq&quot;&gt;try_open&lt;/code&gt; morphism. Coq needs you to prove the following
goal:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;1 subgoal, subgoal 1 (ID 50)

  ============================
  forall x y : Gate, gate_eq x y -&amp;gt; gate_eq (try_open x) (try_open y)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here is a way to prove that:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Next&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Obligation&lt;/span&gt;.
  &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; g g&apos; Heq.
  &lt;span class=&quot;hljs-built_in&quot;&gt;assert&lt;/span&gt; (gate_eq g g&apos;) &lt;span class=&quot;hljs-built_in&quot;&gt;as&lt;/span&gt; [Hop Hlo] &lt;span class=&quot;hljs-built_in&quot;&gt;by&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;exact&lt;/span&gt; Heq).
  &lt;span class=&quot;hljs-built_in&quot;&gt;unfold&lt;/span&gt; try_open.
  &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; &amp;lt;- Hlo.
  &lt;span class=&quot;hljs-built_in&quot;&gt;destruct&lt;/span&gt; (bool_dec (lock g) false) &lt;span class=&quot;hljs-built_in&quot;&gt;as&lt;/span&gt; [Hlock|&lt;span class=&quot;hljs-type&quot;&gt;Hnlock&lt;/span&gt;]; &lt;span class=&quot;hljs-built_in&quot;&gt;subst&lt;/span&gt;.
  + &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; Hlock.
    &lt;span class=&quot;hljs-built_in&quot;&gt;split&lt;/span&gt;; &lt;span class=&quot;hljs-built_in&quot;&gt;cbn&lt;/span&gt;; &lt;span class=&quot;hljs-built_in&quot;&gt;reflexivity&lt;/span&gt;.
  + &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; not_false_is_true &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt; Hnlock.
    &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; Hnlock.
    &lt;span class=&quot;hljs-built_in&quot;&gt;cbn&lt;/span&gt;.
    &lt;span class=&quot;hljs-built_in&quot;&gt;exact&lt;/span&gt; Heq.
&lt;span class=&quot;hljs-keyword&quot;&gt;Defined&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, back to our &lt;code class=&quot;hljs language-coq&quot;&gt;gate_eq_try_open_eq&lt;/code&gt;, we now can use &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt;&lt;/code&gt;
and &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;reflexivity&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Require&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Import&lt;/span&gt; Coq.Setoids.&lt;span class=&quot;hljs-keyword&quot;&gt;Setoid&lt;/span&gt;.

&lt;span class=&quot;hljs-keyword&quot;&gt;Lemma&lt;/span&gt; gate_eq_try_open_eq
  : &lt;span class=&quot;hljs-keyword&quot;&gt;forall&lt;/span&gt; (g g&apos;: Gate),
    gate_eq g g&apos;
    -&amp;gt; gate_eq (try_open g) (try_open g&apos;).
&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;.
  &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; g g&apos; Heq.
  &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; Heq.
  &lt;span class=&quot;hljs-built_in&quot;&gt;reflexivity&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;Qed&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We did it! We actually rewrite &lt;code class=&quot;hljs language-coq&quot;&gt;g&lt;/code&gt; as &lt;code class=&quot;hljs language-coq&quot;&gt;g’&lt;/code&gt;, even if we weren’t able
to prove &lt;code class=&quot;hljs language-coq&quot;&gt;g = g’&lt;/code&gt;.&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>Implementing Strongly-Specified Functions with the Program Framework</title>
      <link>https://soap.coffee/~lthms/posts/StronglySpecifiedFunctionsProgram.html</link>
      <guid>https://soap.coffee/~lthms/posts/StronglySpecifiedFunctionsProgram.html</guid>
      <pubDate>January 1, 2017</pubDate>
      <description>
        
        &lt;h1&gt;Implementing Strongly-Specified Functions with the &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Program&lt;/span&gt;&lt;/code&gt; Framework&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/coq.html&quot; class=&quot;tag hover-lemon&quot; marked=&quot;&quot;&gt;coq&lt;/a&gt; &lt;/div&gt;
&lt;h2&gt;The Theory&lt;/h2&gt;
&lt;p&gt;If I had to explain &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Program&lt;/span&gt;&lt;/code&gt;, I would say &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Program&lt;/span&gt;&lt;/code&gt; is the heir of
the &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;refine&lt;/span&gt;&lt;/code&gt; tactic. It gives you a convenient way to embed proofs within
functional programs that are supposed to fade away during code extraction.  But
what do I mean when I say &quot;embed proofs&quot; within functional programs? I found
two ways to do it.&lt;/p&gt;
&lt;h3&gt;Invariants&lt;/h3&gt;
&lt;p&gt;First, we can define a record with one or more fields of type
&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Prop&lt;/span&gt;&lt;/code&gt;. By doing so, we can constrain the values of other fields. Put
another way, we can specify invariant for our type. For instance, in
&lt;a href=&quot;https://github.com/lthms/SpecCert&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;SpecCert&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, I have defined the memory
controller&apos;s SMRAMC register as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Record&lt;/span&gt; SmramcRegister := {
  d_open: bool;
  d_lock: bool;
  lock_is_close: d_lock = true -&amp;gt; d_open = false;
}.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So &lt;code class=&quot;hljs language-coq&quot;&gt;lock_is_closed&lt;/code&gt; is an invariant I know each instance of
&lt;code class=&quot;hljs&quot;&gt;SmramcRegister&lt;/code&gt; will have to comply with, because every time I
will construct a new instance, I will have to prove
&lt;code class=&quot;hljs language-coq&quot;&gt;lock_is_closed&lt;/code&gt; holds true. For instance:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; lock (reg: SmramcRegister)
  : SmramcRegister.
  &lt;span class=&quot;hljs-built_in&quot;&gt;refine&lt;/span&gt; ({| &lt;span class=&quot;hljs-type&quot;&gt;d_open&lt;/span&gt; := false; d_lock := true |&lt;span class=&quot;hljs-type&quot;&gt;}).
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Coq leaves us this goal to prove.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;reg : SmramcRegister
============================
true = true -&amp;gt; false = false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This sound reasonable enough.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;.
  &lt;span class=&quot;hljs-built_in&quot;&gt;trivial&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;Defined&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We have seen in my previous article about strongly specified
functions that mixing proofs and regular terms may lead to
cumbersome code.&lt;/p&gt;
&lt;p&gt;From that perspective, &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Program&lt;/span&gt;&lt;/code&gt; helps. Indeed, the &lt;code class=&quot;hljs language-coq&quot;&gt;lock&lt;/code&gt; function
can also be defined as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;From&lt;/span&gt; Coq &lt;span class=&quot;hljs-keyword&quot;&gt;Require&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Import&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Program&lt;/span&gt;.

#[program]
&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; lock&apos; (reg: SmramcRegister)
  : SmramcRegister :=
  {| &lt;span class=&quot;hljs-type&quot;&gt;d_open&lt;/span&gt; := false
   ; d_lock := true
   |&lt;span class=&quot;hljs-type&quot;&gt;}.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Pre and Post Conditions&lt;/h3&gt;
&lt;p&gt;Another way to &quot;embed proofs in a program&quot; is by specifying pre-
and post-conditions for its component. In Coq, this is done using
sigma types.&lt;/p&gt;
&lt;p&gt;On the one hand, a precondition is a proposition a function input has to
satisfy in order for the function to be applied.  For instance, a precondition
for &lt;code class=&quot;hljs language-coq&quot;&gt;head : &lt;span class=&quot;hljs-keyword&quot;&gt;forall&lt;/span&gt; {a}, list a -&amp;gt; a&lt;/code&gt; the function that returns the first
element of a list &lt;code class=&quot;hljs language-coq&quot;&gt;l&lt;/code&gt; requires &lt;code class=&quot;hljs language-coq&quot;&gt;l&lt;/code&gt; to contain at least one element.
We can write that using a sigma-type. The type of &lt;code class=&quot;hljs language-coq&quot;&gt;head&lt;/code&gt; then becomes
&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;forall&lt;/span&gt; {a} (l: list a | &lt;span class=&quot;hljs-type&quot;&gt;l&lt;/span&gt; &amp;lt;&amp;gt; []) : a&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;On the other hand, a post condition is a proposition a function
output has to satisfy in order for the function to be correctly
implemented. In this way, &lt;code class=&quot;hljs&quot;&gt;head&lt;/code&gt; should in fact return the first
element of &lt;code class=&quot;hljs language-coq&quot;&gt;l&lt;/code&gt; and not something else.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Program&lt;/span&gt;&lt;/code&gt; makes writing this specification straightforward.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;#[program]
&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; head {a} (l : list a | &lt;span class=&quot;hljs-type&quot;&gt;l&lt;/span&gt; &amp;lt;&amp;gt; [])
  : { x : a | &lt;span class=&quot;hljs-type&quot;&gt;exists&lt;/span&gt; l&apos;, x :: l&apos; = l }.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We recall that because &lt;code class=&quot;hljs language-coq&quot;&gt;{ l: list a | &lt;span class=&quot;hljs-type&quot;&gt;l&lt;/span&gt; &amp;lt;&amp;gt; [] }&lt;/code&gt; is not the same as &lt;code class=&quot;hljs language-coq&quot;&gt;list a&lt;/code&gt;, in theory we cannot just compare &lt;code class=&quot;hljs language-coq&quot;&gt;l&lt;/code&gt; with &lt;code class=&quot;hljs language-coq&quot;&gt;x :: l&apos;&lt;/code&gt; (we need to
use &lt;code class=&quot;hljs language-coq&quot;&gt;proj1_sig&lt;/code&gt;). One advantage of &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Program&lt;/span&gt;&lt;/code&gt; is to deal with it using
an implicit coercion.&lt;/p&gt;
&lt;p&gt;Note that for the type inference to work as expected, the
unwrapped value (here, &lt;code class=&quot;hljs language-coq&quot;&gt;x :: l&apos;&lt;/code&gt;) needs to be the left operand of
&lt;code class=&quot;hljs language-coq&quot;&gt;=&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now that &lt;code class=&quot;hljs language-coq&quot;&gt;head&lt;/code&gt; have been specified, we have to implement it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;#[program]
&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; head {a} (l: list a | &lt;span class=&quot;hljs-type&quot;&gt;l&lt;/span&gt; &amp;lt;&amp;gt; [])
  : { x : a | &lt;span class=&quot;hljs-type&quot;&gt;exists&lt;/span&gt; l&apos;, cons x l&apos; = l } :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; l &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;x&lt;/span&gt; :: l&apos; =&amp;gt; x
  | &lt;span class=&quot;hljs-type&quot;&gt;[] =&amp;gt; !
  end&lt;/span&gt;.

&lt;span class=&quot;hljs-keyword&quot;&gt;Next&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Obligation&lt;/span&gt;.
  &lt;span class=&quot;hljs-built_in&quot;&gt;exists&lt;/span&gt; l&apos;.
  &lt;span class=&quot;hljs-built_in&quot;&gt;reflexivity&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;Qed&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I want to highlight several things here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We return &lt;code class=&quot;hljs language-coq&quot;&gt;x&lt;/code&gt; (of type &lt;code class=&quot;hljs language-coq&quot;&gt;a&lt;/code&gt;) rather than a sigma-type, then
&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Program&lt;/span&gt;&lt;/code&gt; is smart enough to wrap it. To do so, it tries to prove the post
condition and because it fails, we have to do it ourselves (this is the
Obligation we solve after the function definition.)&lt;/li&gt;
&lt;li&gt;The &lt;code class=&quot;hljs language-coq&quot;&gt;[]&lt;/code&gt; case is absurd regarding the precondition, we tell Coq that
using the bang (&lt;code class=&quot;hljs language-coq&quot;&gt;!&lt;/code&gt;) symbol.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We can have a look at the extracted code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;(** val head : &apos;a1 list -&amp;gt; &apos;a1 **)&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; head = &lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt;
| &lt;span class=&quot;hljs-type&quot;&gt;Nil&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;(* absurd case *)&lt;/span&gt;
| &lt;span class=&quot;hljs-type&quot;&gt;Cons&lt;/span&gt; (a, _) -&amp;gt; a
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The implementation is pretty straightforward, but the pre- and
post conditions have faded away. Also, the absurd case is
discarded using an assertion. This means one thing: [head] should
not be used directly from the Ocaml world. &quot;Interface&quot; functions
have to be total. *)&lt;/p&gt;
&lt;h2&gt;The Practice&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;From&lt;/span&gt; Coq &lt;span class=&quot;hljs-keyword&quot;&gt;Require&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Import&lt;/span&gt; Lia.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I have challenged myself to build a strongly specified library. My goal was to
define a type &lt;code class=&quot;hljs language-coq&quot;&gt;vector : nat -&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;&lt;/code&gt; such as &lt;code class=&quot;hljs language-coq&quot;&gt;vector a n&lt;/code&gt;
is a list of &lt;code class=&quot;hljs language-coq&quot;&gt;n&lt;/code&gt; instance of &lt;code class=&quot;hljs language-coq&quot;&gt;a&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Inductive&lt;/span&gt; vector (a : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;) : nat -&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt; :=
| &lt;span class=&quot;hljs-type&quot;&gt;vcons&lt;/span&gt; {n} : a -&amp;gt; vector a n -&amp;gt; vector a (S n)
| &lt;span class=&quot;hljs-type&quot;&gt;vnil&lt;/span&gt; : vector a O.

&lt;span class=&quot;hljs-keyword&quot;&gt;Arguments&lt;/span&gt; vcons [a n] &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;Arguments&lt;/span&gt; vnil {a}.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I had three functions in mind: &lt;code class=&quot;hljs language-coq&quot;&gt;take&lt;/code&gt;, &lt;code class=&quot;hljs language-coq&quot;&gt;drop&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;extract&lt;/code&gt;.
I learned a few lessons. My main takeaway remains: do not use sigma types,
&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Program&lt;/span&gt;&lt;/code&gt; and dependent types together. From my point of view, Coq is not
yet ready for this. Maybe it is possible to make those three work together, but
I have to admit I did not find out how. As a consequence, my preconditions are
defined as extra arguments.&lt;/p&gt;
&lt;p&gt;To be able to specify the post conditions of my three functions and
some others, I first defined &lt;code class=&quot;hljs language-coq&quot;&gt;nth&lt;/code&gt; to get the &lt;em&gt;nth&lt;/em&gt; element of a
vector.&lt;/p&gt;
&lt;p&gt;My first attempt to write &lt;code class=&quot;hljs language-coq&quot;&gt;nth&lt;/code&gt; was a failure.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;#[program]
&lt;span class=&quot;hljs-keyword&quot;&gt;Fixpoint&lt;/span&gt; nth {a n}
    (v : vector a n) (i : nat) {struct v}
  : option a :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; v, i &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;vcons&lt;/span&gt; x &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt;, O =&amp;gt; Some x
  | &lt;span class=&quot;hljs-type&quot;&gt;vcons&lt;/span&gt; x r, S i =&amp;gt; nth r i
  | &lt;span class=&quot;hljs-type&quot;&gt;vnil&lt;/span&gt;, &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; =&amp;gt; None
  &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;raised an anomaly.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;#[program]
&lt;span class=&quot;hljs-keyword&quot;&gt;Fixpoint&lt;/span&gt; nth {a n}
    (v : vector a n) (i : nat) {struct v}
  : option a :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; v &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;vcons&lt;/span&gt; x r =&amp;gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; i &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
    | &lt;span class=&quot;hljs-type&quot;&gt;O&lt;/span&gt; =&amp;gt; Some x
    | &lt;span class=&quot;hljs-type&quot;&gt;S&lt;/span&gt; i =&amp;gt; nth r i
    &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;vnil&lt;/span&gt; =&amp;gt; None
  &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With &lt;code class=&quot;hljs language-coq&quot;&gt;nth&lt;/code&gt;, it is possible to give a very precise definition of
&lt;code class=&quot;hljs language-coq&quot;&gt;take&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;#[program]
&lt;span class=&quot;hljs-keyword&quot;&gt;Fixpoint&lt;/span&gt; take {a n}
    (v : vector a n) (e : nat | &lt;span class=&quot;hljs-type&quot;&gt;e&lt;/span&gt; &amp;lt;= n)
  : { u : vector a e | &lt;span class=&quot;hljs-type&quot;&gt;forall&lt;/span&gt; i : nat,
        i &amp;lt; e -&amp;gt; nth u i = nth v i } :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; e &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;S&lt;/span&gt; e&apos; =&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; v &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
            | &lt;span class=&quot;hljs-type&quot;&gt;vcons&lt;/span&gt; x r =&amp;gt; vcons x (take r e&apos;)
            | &lt;span class=&quot;hljs-type&quot;&gt;vnil&lt;/span&gt; =&amp;gt; !
            &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;O&lt;/span&gt; =&amp;gt; vnil
  &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;.

&lt;span class=&quot;hljs-keyword&quot;&gt;Next&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Obligation&lt;/span&gt;.
  now &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; le_S_n.
&lt;span class=&quot;hljs-keyword&quot;&gt;Defined&lt;/span&gt;.

&lt;span class=&quot;hljs-keyword&quot;&gt;Next&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Obligation&lt;/span&gt;.
  &lt;span class=&quot;hljs-built_in&quot;&gt;induction&lt;/span&gt; i.
  + &lt;span class=&quot;hljs-built_in&quot;&gt;reflexivity&lt;/span&gt;.
  + &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; e0.
    now &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; Lt.lt_S_n.
&lt;span class=&quot;hljs-keyword&quot;&gt;Defined&lt;/span&gt;.

&lt;span class=&quot;hljs-keyword&quot;&gt;Next&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Obligation&lt;/span&gt;.
  now &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; PeanoNat.Nat.nle_succ_0 &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt; H.
&lt;span class=&quot;hljs-keyword&quot;&gt;Defined&lt;/span&gt;.

&lt;span class=&quot;hljs-keyword&quot;&gt;Next&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Obligation&lt;/span&gt;.
  now &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; PeanoNat.Nat.nlt_0_r &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt; H.
&lt;span class=&quot;hljs-keyword&quot;&gt;Defined&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As a side note, I wanted to define the post condition as follows:
&lt;code class=&quot;hljs language-coq&quot;&gt;{ v&apos;: vector A e | &lt;span class=&quot;hljs-type&quot;&gt;forall&lt;/span&gt; (i : nat | &lt;span class=&quot;hljs-type&quot;&gt;i&lt;/span&gt; &amp;lt; e), nth v&apos; i = nth v i }&lt;/code&gt;. However, this made the goals and hypotheses become very hard
to read and to use. Sigma types in sigma types: not a good
idea.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;(** val take : &apos;a1 vector -&amp;gt; nat -&amp;gt; &apos;a1 vector **)&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;rec&lt;/span&gt; take v = &lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt;
| &lt;span class=&quot;hljs-type&quot;&gt;O&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;Vnil&lt;/span&gt;
| &lt;span class=&quot;hljs-type&quot;&gt;S&lt;/span&gt; e&apos; -&amp;gt;
  (&lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; v &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;
   | &lt;span class=&quot;hljs-type&quot;&gt;Vcons&lt;/span&gt; (_, x, r) -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;Vcons&lt;/span&gt; (e&apos;, x, (take r e&apos;))
   | &lt;span class=&quot;hljs-type&quot;&gt;Vnil&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;(* absurd case *)&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I could tackle &lt;code class=&quot;hljs&quot;&gt;drop&lt;/code&gt; in a very similar manner:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;#[program]
&lt;span class=&quot;hljs-keyword&quot;&gt;Fixpoint&lt;/span&gt; drop {a n}
    (v : vector a n) (b : nat | &lt;span class=&quot;hljs-type&quot;&gt;b&lt;/span&gt; &amp;lt;= n)
  : { v&apos;: vector a (n - b) | &lt;span class=&quot;hljs-type&quot;&gt;forall&lt;/span&gt; i,
        i &amp;lt; n - b -&amp;gt; nth v&apos; i = nth v (b + i) } :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; b &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;0&lt;/span&gt; =&amp;gt; v
  | &lt;span class=&quot;hljs-type&quot;&gt;S&lt;/span&gt; n =&amp;gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; v &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
           | &lt;span class=&quot;hljs-type&quot;&gt;vcons&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; r =&amp;gt; (drop r n)
           | &lt;span class=&quot;hljs-type&quot;&gt;vnil&lt;/span&gt; =&amp;gt; !
           &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;)
  &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;.

&lt;span class=&quot;hljs-keyword&quot;&gt;Next&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Obligation&lt;/span&gt;.
  now &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; &amp;lt;- Minus.minus_n_O.
&lt;span class=&quot;hljs-keyword&quot;&gt;Defined&lt;/span&gt;.

&lt;span class=&quot;hljs-keyword&quot;&gt;Next&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Obligation&lt;/span&gt;.
  &lt;span class=&quot;hljs-built_in&quot;&gt;induction&lt;/span&gt; n;
    &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; &amp;lt;- eq_rect_eq;
    &lt;span class=&quot;hljs-built_in&quot;&gt;reflexivity&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;Defined&lt;/span&gt;.

&lt;span class=&quot;hljs-keyword&quot;&gt;Next&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Obligation&lt;/span&gt;.
  now &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; le_S_n.
&lt;span class=&quot;hljs-keyword&quot;&gt;Defined&lt;/span&gt;.

&lt;span class=&quot;hljs-keyword&quot;&gt;Next&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Obligation&lt;/span&gt;.
  now &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; PeanoNat.Nat.nle_succ_0 &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt; H.
&lt;span class=&quot;hljs-keyword&quot;&gt;Defined&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The proofs are easy to write, and the extracted code is exactly what one might
want it to be:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;(** val drop : &apos;a1 vector -&amp;gt; nat -&amp;gt; &apos;a1 vector **)&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;rec&lt;/span&gt; drop v = &lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt;
| &lt;span class=&quot;hljs-type&quot;&gt;O&lt;/span&gt; -&amp;gt; v
| &lt;span class=&quot;hljs-type&quot;&gt;S&lt;/span&gt; n -&amp;gt;
  (&lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; v &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;
   | &lt;span class=&quot;hljs-type&quot;&gt;Vcons&lt;/span&gt; (_, _, r) -&amp;gt; drop r n
   | &lt;span class=&quot;hljs-type&quot;&gt;Vnil&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;(* absurd case *)&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Program&lt;/span&gt;&lt;/code&gt; really shone when it comes to implementing extract. I just
had to combine &lt;code class=&quot;hljs language-coq&quot;&gt;take&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;drop&lt;/code&gt;. *)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;#[program]
&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; extract {a n} (v : vector a n)
    (e : nat | &lt;span class=&quot;hljs-type&quot;&gt;e&lt;/span&gt; &amp;lt;= n) (b : nat | &lt;span class=&quot;hljs-type&quot;&gt;b&lt;/span&gt; &amp;lt;= e)
  : { v&apos;: vector a (e - b) | &lt;span class=&quot;hljs-type&quot;&gt;forall&lt;/span&gt; i,
        i &amp;lt; (e - b) -&amp;gt; nth v&apos; i = nth v (b + i) } :=
  take (drop v b) (e - b).


&lt;span class=&quot;hljs-keyword&quot;&gt;Next&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Obligation&lt;/span&gt;.
  &lt;span class=&quot;hljs-built_in&quot;&gt;transitivity&lt;/span&gt; e; &lt;span class=&quot;hljs-built_in&quot;&gt;auto&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;Defined&lt;/span&gt;.

&lt;span class=&quot;hljs-keyword&quot;&gt;Next&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Obligation&lt;/span&gt;.
  now &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; PeanoNat.Nat.sub_le_mono_r.
&lt;span class=&quot;hljs-keyword&quot;&gt;Defined&lt;/span&gt;.

&lt;span class=&quot;hljs-keyword&quot;&gt;Next&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Obligation&lt;/span&gt;.
  &lt;span class=&quot;hljs-built_in&quot;&gt;destruct&lt;/span&gt; drop; &lt;span class=&quot;hljs-built_in&quot;&gt;cbn&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt; *.
  &lt;span class=&quot;hljs-built_in&quot;&gt;destruct&lt;/span&gt; take; &lt;span class=&quot;hljs-built_in&quot;&gt;cbn&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt; *.
  &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; e1; &lt;span class=&quot;hljs-built_in&quot;&gt;auto&lt;/span&gt;.
  &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; &amp;lt;- e0; &lt;span class=&quot;hljs-built_in&quot;&gt;auto&lt;/span&gt;.
  &lt;span class=&quot;hljs-built_in&quot;&gt;lia&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;Defined&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The proofs are straightforward because the specifications of &lt;code class=&quot;hljs language-coq&quot;&gt;drop&lt;/code&gt; and
&lt;code class=&quot;hljs language-coq&quot;&gt;take&lt;/code&gt; are precise enough, and we do not need to have a look at their
implementations. The extracted version of &lt;code class=&quot;hljs language-coq&quot;&gt;extract&lt;/code&gt; is as clean as we can
anticipate.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;(** val extract : &apos;a1 vector -&amp;gt; nat -&amp;gt; nat -&amp;gt; &apos;a1 vector **)&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; extract v e b =
  take (drop v b) (sub e b)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I was pretty happy, so I tried some more. Each time, using &lt;code class=&quot;hljs language-coq&quot;&gt;nth&lt;/code&gt;, I managed
to write a precise post condition and to prove it holds true. For instance,
given &lt;code class=&quot;hljs language-coq&quot;&gt;map&lt;/code&gt; to apply a function &lt;code class=&quot;hljs language-coq&quot;&gt;f&lt;/code&gt; to each element of a vector &lt;code class=&quot;hljs language-coq&quot;&gt;v&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;#[program]
&lt;span class=&quot;hljs-keyword&quot;&gt;Fixpoint&lt;/span&gt; map {a b n} (v : vector a n) (f : a -&amp;gt; b)
  : { v&apos;: vector b n | &lt;span class=&quot;hljs-type&quot;&gt;forall&lt;/span&gt; i,
        nth v&apos; i = option_map f (nth v i) } :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; v &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;vnil&lt;/span&gt; =&amp;gt; vnil
  | &lt;span class=&quot;hljs-type&quot;&gt;vcons&lt;/span&gt; a v =&amp;gt; vcons (f a) (map v f)
  &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;.

&lt;span class=&quot;hljs-keyword&quot;&gt;Next&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Obligation&lt;/span&gt;.
  &lt;span class=&quot;hljs-built_in&quot;&gt;induction&lt;/span&gt; i.
  + &lt;span class=&quot;hljs-built_in&quot;&gt;reflexivity&lt;/span&gt;.
  + &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; e.
&lt;span class=&quot;hljs-keyword&quot;&gt;Defined&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I also managed to specify and write &lt;code class=&quot;hljs language-coq&quot;&gt;append&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;#[program]
Fixpoint append {a n m}
    (v : vector a n) (u : vector a m)
  : { w : vector a (n + m) | forall i,
        (i &amp;lt; n -&amp;gt; nth w i = nth v i) /\
        (n &amp;lt;= i -&amp;gt; nth w i = nth u (i - n))
    } :=
  match v with
  | vnil =&amp;gt; u
  | vcons a v =&amp;gt; vcons a (append v u)
  end.

Next Obligation.
  split.
  + now intro.
  + intros _.
    now rewrite PeanoNat.Nat.sub_0_r.
Defined.

Next Obligation.
  rename wildcard&apos; into n.
  destruct (Compare_dec.lt_dec i (S n)); split.
  + intros _.
    destruct i.
    ++ reflexivity.
    ++ cbn.
       specialize (a1 i).
       destruct a1 as [a1 _].
       apply a1.
       auto with arith.
  + intros false.
    lia.
  + now intros.
  + intros ord.
    destruct i.
    ++ lia.
    ++ cbn.
       specialize (a1 i).
       destruct a1 as [_ a1].
       apply a1.
       auto with arith.
Defined.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, I tried to implement &lt;code class=&quot;hljs language-coq&quot;&gt;map2&lt;/code&gt; that takes a vector of &lt;code class=&quot;hljs language-coq&quot;&gt;a&lt;/code&gt;, a vector of
&lt;code class=&quot;hljs language-coq&quot;&gt;b&lt;/code&gt; (both of the same size) and a function &lt;code class=&quot;hljs language-coq&quot;&gt;f : a -&amp;gt; b -&amp;gt; c&lt;/code&gt; and returns a
vector of &lt;code class=&quot;hljs language-coq&quot;&gt;c&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;First, we need to provide a precise specification for &lt;code class=&quot;hljs language-coq&quot;&gt;map2&lt;/code&gt;. To do that, we
introduce &lt;code class=&quot;hljs language-coq&quot;&gt;option_app&lt;/code&gt;, a function that Haskellers know all to well as being
part of the &lt;code class=&quot;hljs language-haskell&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Applicative&lt;/span&gt;&lt;/code&gt; type class.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; option_app {a b}
    (opf: option (a -&amp;gt; b))
    (opx: option a)
  : option b :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; opf, opx &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;Some&lt;/span&gt; f, Some x =&amp;gt; Some (f x)
  | &lt;span class=&quot;hljs-type&quot;&gt;_&lt;/span&gt;, &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; =&amp;gt; None
&lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We thereafter use &lt;code class=&quot;hljs language-coq&quot;&gt;&amp;lt;$&amp;gt;&lt;/code&gt; as an infix operator for &lt;code class=&quot;hljs language-coq&quot;&gt;option_map&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;&amp;lt;*&amp;gt;&lt;/code&gt; as
an infix operator for &lt;code class=&quot;hljs language-coq&quot;&gt;option_app&lt;/code&gt;. *)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Infix&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;&amp;lt;$&amp;gt;&quot;&lt;/span&gt; := option_map (&lt;span class=&quot;hljs-built_in&quot;&gt;at&lt;/span&gt; level &lt;span class=&quot;hljs-number&quot;&gt;50&lt;/span&gt;).
&lt;span class=&quot;hljs-keyword&quot;&gt;Infix&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;&amp;lt;*&amp;gt;&quot;&lt;/span&gt; := option_app (&lt;span class=&quot;hljs-built_in&quot;&gt;at&lt;/span&gt; level &lt;span class=&quot;hljs-number&quot;&gt;55&lt;/span&gt;).
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Given two vectors &lt;code class=&quot;hljs language-coq&quot;&gt;v&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;u&lt;/code&gt; of the same size and a function &lt;code class=&quot;hljs language-coq&quot;&gt;f&lt;/code&gt;, and given
&lt;code class=&quot;hljs language-coq&quot;&gt;w&lt;/code&gt; the result computed by &lt;code class=&quot;hljs language-coq&quot;&gt;map2&lt;/code&gt;, then we can propose the following
specification for &lt;code class=&quot;hljs language-coq&quot;&gt;map2&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;forall&lt;/span&gt; (i : nat), nth w i = f &amp;lt;$&amp;gt; nth v i &amp;lt;*&amp;gt; nth u i&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This reads as follows: the &lt;code class=&quot;hljs language-coq&quot;&gt;i&lt;/code&gt;th element of &lt;code class=&quot;hljs language-coq&quot;&gt;w&lt;/code&gt; is the result of applying
the &lt;code class=&quot;hljs language-coq&quot;&gt;i&lt;/code&gt;th elements of &lt;code class=&quot;hljs language-coq&quot;&gt;v&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;u&lt;/code&gt; to &lt;code class=&quot;hljs language-coq&quot;&gt;f&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It turns out implementing &lt;code class=&quot;hljs language-coq&quot;&gt;map2&lt;/code&gt; with the &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Program&lt;/span&gt;&lt;/code&gt; framework has
proven to be harder than I originally expected. My initial attempt was the
following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;#[program]
&lt;span class=&quot;hljs-keyword&quot;&gt;Fixpoint&lt;/span&gt; map2 {a b c n}
    (v : vector a n) (u : vector b n)
    (f : a -&amp;gt; b -&amp;gt; c) {struct v}
  : { w: vector c n | &lt;span class=&quot;hljs-type&quot;&gt;forall&lt;/span&gt; i,
        nth w i = f &amp;lt;$&amp;gt; nth v i &amp;lt;*&amp;gt; nth u i
    } :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; v, u &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;vcons&lt;/span&gt; x rst, vcons x&apos; rst&apos; =&amp;gt;
      vcons (f x x&apos;) (map2 rst rst&apos; f)
  | &lt;span class=&quot;hljs-type&quot;&gt;vnil&lt;/span&gt;, vnil =&amp;gt; vnil
  | &lt;span class=&quot;hljs-type&quot;&gt;_&lt;/span&gt;, &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; =&amp;gt; !
  &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;Illegal application:
The term &quot;@eq&quot; of type &quot;forall A : Type, A -&amp;gt; A -&amp;gt; Prop&quot;
cannot be applied to the terms
 &quot;nat&quot; : &quot;Set&quot;
 &quot;S wildcard&apos;&quot; : &quot;nat&quot;
 &quot;b&quot; : &quot;Type&quot;
The 3rd term has type &quot;Type&quot; which should be coercible
to &quot;nat&quot;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So I had to fallback to defining the function in pure Ltac.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;#[program]
&lt;span class=&quot;hljs-keyword&quot;&gt;Fixpoint&lt;/span&gt; map2 {a b c n}
    (v : vector a n) (u : vector b n)
    (f : a -&amp;gt; b -&amp;gt; c) {struct v}
  : { w: vector c n | &lt;span class=&quot;hljs-type&quot;&gt;forall&lt;/span&gt; i,
        nth w i = f &amp;lt;$&amp;gt; nth v i &amp;lt;*&amp;gt; nth u i
    } := &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt;.

&lt;span class=&quot;hljs-keyword&quot;&gt;Next&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Obligation&lt;/span&gt;.
  &lt;span class=&quot;hljs-built_in&quot;&gt;dependent&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;induction&lt;/span&gt; v; &lt;span class=&quot;hljs-built_in&quot;&gt;dependent&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;induction&lt;/span&gt; u.
  + &lt;span class=&quot;hljs-built_in&quot;&gt;remember&lt;/span&gt; (IHv u f) &lt;span class=&quot;hljs-built_in&quot;&gt;as&lt;/span&gt; u&apos;.
    &lt;span class=&quot;hljs-built_in&quot;&gt;inversion&lt;/span&gt; u&apos;.
    &lt;span class=&quot;hljs-built_in&quot;&gt;refine&lt;/span&gt; (exist &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; (vcons (f a0 a1) x) &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt;).
    &lt;span class=&quot;hljs-built_in&quot;&gt;intros&lt;/span&gt; i.
    &lt;span class=&quot;hljs-built_in&quot;&gt;induction&lt;/span&gt; i.
    * &lt;span class=&quot;hljs-built_in&quot;&gt;reflexivity&lt;/span&gt;.
    * &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; (H i).
  + &lt;span class=&quot;hljs-built_in&quot;&gt;refine&lt;/span&gt; (exist &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; vnil &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt;).
    &lt;span class=&quot;hljs-built_in&quot;&gt;reflexivity&lt;/span&gt;.
&lt;span class=&quot;hljs-keyword&quot;&gt;Qed&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Is It Usable?&lt;/h2&gt;
&lt;p&gt;This post mostly gives the &quot;happy ends&quot; for each function. I think I tried
too hard for what I got in return and therefore I am convinced &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Program&lt;/span&gt;&lt;/code&gt;
is not ready (at least for a dependent type, I cannot tell for the rest). For
instance, I found at least one bug in Program logic (I still have to report
it). Have a look at the following code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;#[program]
&lt;span class=&quot;hljs-keyword&quot;&gt;Fixpoint&lt;/span&gt; map2 {a b c n}
     (u : vector a n) (v : vector b n)
     (f : a -&amp;gt; b -&amp;gt; c) {struct v}
  : vector c n :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; u &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;_&lt;/span&gt; =&amp;gt; vnil
  &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It gives the following error:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;Error: Illegal application:
The term &quot;@eq&quot; of type &quot;forall A : Type, A -&amp;gt; A -&amp;gt; Prop&quot;
cannot be applied to the terms
 &quot;nat&quot; : &quot;Set&quot;
 &quot;0&quot; : &quot;nat&quot;
 &quot;wildcard&apos;&quot; : &quot;vector A n&apos;&quot;
The 3rd term has type &quot;vector A n&apos;&quot; which should be
coercible to &quot;nat&quot;.
&lt;/code&gt;&lt;/pre&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>Implementing Strongly-Specified Functions with the refine Tactic</title>
      <link>https://soap.coffee/~lthms/posts/StronglySpecifiedFunctionsRefine.html</link>
      <guid>https://soap.coffee/~lthms/posts/StronglySpecifiedFunctionsRefine.html</guid>
      <pubDate>January 11, 2015</pubDate>
      <description>
        
        &lt;h1&gt;Implementing Strongly-Specified Functions with the &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;refine&lt;/span&gt;&lt;/code&gt; Tactic&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/coq.html&quot; class=&quot;tag hover-lavender&quot; marked=&quot;&quot;&gt;coq&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;I started to play with Coq, the interactive theorem prover
developed by Inria, a few weeks ago. It is a very powerful tool,
yet hard to master. Fortunately, there are some very good readings
if you want to learn (I recommend the Coq&apos;Art). This article is
not one of them.&lt;/p&gt;
&lt;p&gt;In this article, we will see how to implement strongly specified
list manipulation functions in Coq. Strong specifications are used
to ensure some properties on functions&apos; arguments and return
value. It makes Coq type system very expressive. Thus, it is
possible to specify in the type of the function &lt;code class=&quot;hljs language-coq&quot;&gt;pop&lt;/code&gt; that the return
value is the list passed as an argument in which the first element has been
removed, for example.&lt;/p&gt;
&lt;h2&gt;Is This List Empty?&lt;/h2&gt;
&lt;p&gt;It&apos;s the first question to deal with when manipulating
lists. There are some functions that require their arguments not
to be empty. It&apos;s the case for the &lt;code class=&quot;hljs language-coq&quot;&gt;pop&lt;/code&gt; function, for instance
it is not possible to remove the first element of a list that does
not have any elements in the first place.&lt;/p&gt;
&lt;p&gt;When one wants to answer such a question as “Is this list empty?”,
he has to keep in mind that there are two ways to do it: by a
predicate or by a boolean function. Indeed, &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Prop&lt;/span&gt;&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;bool&lt;/code&gt; are
two different worlds that do not mix easily. One solution is to
write two definitions and to prove their equivalence.  That is
&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;forall&lt;/span&gt; args, predicate args &amp;lt;-&amp;gt; bool_function args = true&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Another solution is to use the &lt;code class=&quot;hljs language-coq&quot;&gt;sumbool&lt;/code&gt; type as middlemen. The
scheme is the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Defining &lt;code class=&quot;hljs language-coq&quot;&gt;predicate : args → &lt;span class=&quot;hljs-keyword&quot;&gt;Prop&lt;/span&gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Defining &lt;code class=&quot;hljs language-coq&quot;&gt;predicate_dec : args -&amp;gt; { predicate args } + { ~predicate args }&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Defining &lt;code class=&quot;hljs language-coq&quot;&gt;predicate_b&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; predicate_b (args) :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; predicate_dec args &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt; true &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; false.
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Defining the &lt;code class=&quot;hljs language-coq&quot;&gt;empty&lt;/code&gt; Predicate&lt;/h3&gt;
&lt;p&gt;A list is empty if it is &lt;code class=&quot;hljs language-coq&quot;&gt;[]&lt;/code&gt; (&lt;code class=&quot;hljs language-coq&quot;&gt;nil&lt;/code&gt;). It&apos;s as simple as that!&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; empty {a} (l : list a) : &lt;span class=&quot;hljs-keyword&quot;&gt;Prop&lt;/span&gt; := l = [].
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Defining a decidable version of &lt;code class=&quot;hljs language-coq&quot;&gt;empty&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;A decidable version of &lt;code class=&quot;hljs language-coq&quot;&gt;empty&lt;/code&gt; is a function which takes a list
&lt;code class=&quot;hljs language-coq&quot;&gt;l&lt;/code&gt; as its argument and returns either a proof that &lt;code class=&quot;hljs language-coq&quot;&gt;l&lt;/code&gt; is empty,
or a proof that &lt;code class=&quot;hljs language-coq&quot;&gt;l&lt;/code&gt; is not empty. This is encoded in the Coq
standard library with the &lt;code class=&quot;hljs language-coq&quot;&gt;sumbool&lt;/code&gt; type, and is written as
follows: &lt;code class=&quot;hljs language-coq&quot;&gt;{ empty l } + { ~ empty l }&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; empty_dec {a} (l : list a)
  : { empty l } + { ~ empty l }.
&lt;span class=&quot;hljs-keyword&quot;&gt;Proof&lt;/span&gt;.
  &lt;span class=&quot;hljs-built_in&quot;&gt;refine&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; l &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
          | &lt;span class=&quot;hljs-type&quot;&gt;[] =&amp;gt; left&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt;
          | &lt;span class=&quot;hljs-type&quot;&gt;_&lt;/span&gt; =&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;right&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt;
          &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;);
    &lt;span class=&quot;hljs-built_in&quot;&gt;unfold&lt;/span&gt; empty; &lt;span class=&quot;hljs-built_in&quot;&gt;trivial&lt;/span&gt;.
  &lt;span class=&quot;hljs-built_in&quot;&gt;unfold&lt;/span&gt; not; &lt;span class=&quot;hljs-built_in&quot;&gt;intro&lt;/span&gt; H; &lt;span class=&quot;hljs-built_in&quot;&gt;discriminate&lt;/span&gt; H.
&lt;span class=&quot;hljs-keyword&quot;&gt;Defined&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, I decided to use the &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;refine&lt;/span&gt;&lt;/code&gt; tactic which is
convenient when we manipulate the &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Set&lt;/span&gt;&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Prop&lt;/span&gt;&lt;/code&gt; sorts at the
same time.&lt;/p&gt;
&lt;h3&gt;Defining &lt;code class=&quot;hljs language-coq&quot;&gt;empty_b&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;With &lt;code class=&quot;hljs language-coq&quot;&gt;empty_dec&lt;/code&gt;, we can define &lt;code class=&quot;hljs language-coq&quot;&gt;empty_b&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; empty_b {a} (l : list a) : bool :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; empty_dec l &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt; true &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; false.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&apos;s try to extract &lt;code class=&quot;hljs language-coq&quot;&gt;empty_b&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;bool&lt;/span&gt; =
| &lt;span class=&quot;hljs-type&quot;&gt;True&lt;/span&gt;
| &lt;span class=&quot;hljs-type&quot;&gt;False&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; sumbool =
| &lt;span class=&quot;hljs-type&quot;&gt;Left&lt;/span&gt;
| &lt;span class=&quot;hljs-type&quot;&gt;Right&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt; =
| &lt;span class=&quot;hljs-type&quot;&gt;Nil&lt;/span&gt;
| &lt;span class=&quot;hljs-type&quot;&gt;Cons&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; * &lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;(** val empty_dec : &apos;a1 list -&amp;gt; sumbool **)&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; empty_dec = &lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt;
| &lt;span class=&quot;hljs-type&quot;&gt;Nil&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;Left&lt;/span&gt;
| &lt;span class=&quot;hljs-type&quot;&gt;Cons&lt;/span&gt; (a, l0) -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;Right&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;(** val empty_b : &apos;a1 list -&amp;gt; bool **)&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; empty_b l =
  &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; empty_dec l &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;Left&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;True&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;Right&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-type&quot;&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In addition to &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-symbol&quot;&gt;&apos;a&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;&lt;/code&gt;, Coq has created the &lt;code class=&quot;hljs language-ocaml&quot;&gt;sumbool&lt;/code&gt; and
&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;bool&lt;/span&gt;&lt;/code&gt; types and &lt;code class=&quot;hljs language-ocaml&quot;&gt;empty_b&lt;/code&gt; is basically a translation from the
former to the latter. We could have stopped with &lt;code class=&quot;hljs language-ocmal&quot;&gt;empty_dec&lt;/code&gt;, but
&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Left&lt;/span&gt;&lt;/code&gt; and &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;Right&lt;/span&gt;&lt;/code&gt; are less readable that &lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;True&lt;/span&gt;&lt;/code&gt; and
&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;False&lt;/span&gt;&lt;/code&gt;. Note that it is possible to configure the Extraction mechanism
to use primitive OCaml types instead, but this is out of the scope of this
article.&lt;/p&gt;
&lt;h2&gt;Defining Some Utility Functions&lt;/h2&gt;
&lt;h3&gt;Defining &lt;code class=&quot;hljs language-coq&quot;&gt;pop&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;There are several ways to write a function that removes the first
element of a list. One is to return &lt;code class=&quot;hljs&quot;&gt;nil&lt;/code&gt; if the given list was
already empty:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; pop {a} ( l :list a) :=
  &lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; l &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
  | &lt;span class=&quot;hljs-type&quot;&gt;_&lt;/span&gt; :: l =&amp;gt; l
  | &lt;span class=&quot;hljs-type&quot;&gt;[] =&amp;gt; []
  end&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But it&apos;s not really satisfying. A &lt;code class=&quot;hljs&quot;&gt;pop&lt;/code&gt; call over an empty list should not be
possible. It can be done by adding an argument to &lt;code class=&quot;hljs&quot;&gt;pop&lt;/code&gt;: the proof that the
list is not empty.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; pop {a} (l : list a) (h : ~ empty l)
  : list a.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are, as usual when it comes to lists, two cases to
consider.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;l = x :: rst&lt;/code&gt;, and therefore &lt;code class=&quot;hljs language-coq&quot;&gt;pop (x :: rst) h&lt;/code&gt; is &lt;code class=&quot;hljs language-coq&quot;&gt;rst&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;l = []&lt;/code&gt;, which is not possible since we know &lt;code class=&quot;hljs language-coq&quot;&gt;l&lt;/code&gt; is not empty.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The challenge is to convince Coq that our reasoning is
correct. There are, again, several approaches to achieve that.  We
can, for instance, use the &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;refine&lt;/span&gt;&lt;/code&gt; tactic again, but this time we
need to know a small trick to succeed as using a “regular” &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt;&lt;/code&gt;
will not work.&lt;/p&gt;
&lt;p&gt;From the following goal:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;  a : Type
  l : list a
  h : ~ empty l
  ============================
  list a
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using the &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;refine&lt;/span&gt;&lt;/code&gt; tactic naively, for instance, this way:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;  &lt;span class=&quot;hljs-built_in&quot;&gt;refine&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; l &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
          | &lt;span class=&quot;hljs-type&quot;&gt;_&lt;/span&gt; :: rst =&amp;gt; rst
          | &lt;span class=&quot;hljs-type&quot;&gt;[] =&amp;gt; _&lt;/span&gt;
          &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;).
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;leaves us the following goal to prove:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;  a : Type
  l : list a
  h : ~ empty l
  ============================
  list a
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nothing has changed! Well, not exactly. See, &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;refine&lt;/span&gt;&lt;/code&gt; has taken
our incomplete Gallina term, found a hole, done some
type-checking, found that the type of the missing piece of our
implementation is &lt;code class=&quot;hljs language-coq&quot;&gt;list a&lt;/code&gt; and therefore has generated a new
goal of this type.  What &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;refine&lt;/span&gt;&lt;/code&gt; has not done, however, is
remembering that we are in the case where &lt;code class=&quot;hljs language-coq&quot;&gt;l = []&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We need to generate a goal from a hole wherein this information is
available. It is possible to use a long form of &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt;&lt;/code&gt;. The
general approach is this: rather than returning a value of type
&lt;code class=&quot;hljs language-coq&quot;&gt;list a&lt;/code&gt;, our match will return a function of type &lt;code class=&quot;hljs language-coq&quot;&gt;l = ?l&apos; -&amp;gt; list a&lt;/code&gt;, where &lt;code class=&quot;hljs language-coq&quot;&gt;?l&lt;/code&gt; is a value of &lt;code class=&quot;hljs language-coq&quot;&gt;l&lt;/code&gt; for a given case (that is,
either &lt;code class=&quot;hljs language-coq&quot;&gt;x :: rst&lt;/code&gt; or &lt;code class=&quot;hljs language-coq&quot;&gt;[]&lt;/code&gt;). Of course and as a consequence, the type
of the &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt;&lt;/code&gt; in now a function which awaits a proof to return
the expected result. Fortunately, this proof is trivial: it is
&lt;code class=&quot;hljs language-coq&quot;&gt;eq_refl&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;  &lt;span class=&quot;hljs-built_in&quot;&gt;refine&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; l &lt;span class=&quot;hljs-built_in&quot;&gt;as&lt;/span&gt; l&apos;
                &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; l = l&apos; -&amp;gt; list a
          &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
          | &lt;span class=&quot;hljs-type&quot;&gt;_&lt;/span&gt; :: rst =&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; =&amp;gt; rst
          | &lt;span class=&quot;hljs-type&quot;&gt;[] =&amp;gt; fun&lt;/span&gt; equ =&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt;
          &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt; eq_refl).
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For us to conclude the proof, this is way better.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;  a : Type
  l : list a
  h : ~ empty l
  equ : l = []
  ============================
  list a
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We conclude the proof, and therefore the definition of &lt;code class=&quot;hljs language-coq&quot;&gt;pop&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;  &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; equ &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt; h.
  &lt;span class=&quot;hljs-built_in&quot;&gt;exfalso&lt;/span&gt;.
  now &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; h.
&lt;span class=&quot;hljs-keyword&quot;&gt;Defined&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&apos;s better and yet it can still be improved. Indeed, according to its type,
&lt;code class=&quot;hljs language-coq&quot;&gt;pop&lt;/code&gt; returns “some list.” As a matter of fact, &lt;code class=&quot;hljs language-coq&quot;&gt;pop&lt;/code&gt; returns “the
same list without its first argument.” It is possible to write
such precise definition thanks to sigma types, defined as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Inductive&lt;/span&gt; sig (A : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt;) (P : A -&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Prop&lt;/span&gt;) : &lt;span class=&quot;hljs-keyword&quot;&gt;Type&lt;/span&gt; :=
  exist : &lt;span class=&quot;hljs-keyword&quot;&gt;forall&lt;/span&gt; (x : A), P x -&amp;gt; sig P.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Rather than &lt;code class=&quot;hljs language-coq&quot;&gt;sig A p&lt;/code&gt;, sigma-types can be written using the
notation &lt;code class=&quot;hljs language-coq&quot;&gt;{ a | &lt;span class=&quot;hljs-type&quot;&gt;P&lt;/span&gt; }&lt;/code&gt;. They express subsets, and can be used to constraint
arguments and results of functions.&lt;/p&gt;
&lt;p&gt;We finally propose a strongly specified definition of &lt;code class=&quot;hljs language-coq&quot;&gt;pop&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; pop {a} (l : list a | &lt;span class=&quot;hljs-type&quot;&gt;~ empty&lt;/span&gt; l)
  : { l&apos; | &lt;span class=&quot;hljs-type&quot;&gt;exists&lt;/span&gt; a, proj1_sig l = cons a l&apos; }.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you think the previous use of &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt;&lt;/code&gt; term was ugly, brace yourselves.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;  &lt;span class=&quot;hljs-built_in&quot;&gt;refine&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; proj1_sig l &lt;span class=&quot;hljs-built_in&quot;&gt;as&lt;/span&gt; l&apos;
                &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; proj1_sig l = l&apos;
                       -&amp;gt; { l&apos; | &lt;span class=&quot;hljs-type&quot;&gt;exists&lt;/span&gt; a, proj1_sig l = cons a l&apos; }
          &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
          | &lt;span class=&quot;hljs-type&quot;&gt;[] =&amp;gt; fun&lt;/span&gt; equ =&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt;
          | &lt;span class=&quot;hljs-type&quot;&gt;(_&lt;/span&gt; :: rst) =&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; equ =&amp;gt; exist &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; rst &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt;
          &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt; eq_refl).
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This leaves us two goals to tackle.&lt;/p&gt;
&lt;p&gt;First, we need to discard the case where &lt;code class=&quot;hljs language-coq&quot;&gt;l&lt;/code&gt; is the empty list.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;  a : Type
  l : {l : list a | ~ empty l}
  equ : proj1_sig l = []
  ============================
  {l&apos; : list a | exists a0 : a, proj1_sig l = a0 :: l&apos;}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;  + &lt;span class=&quot;hljs-built_in&quot;&gt;destruct&lt;/span&gt; l &lt;span class=&quot;hljs-built_in&quot;&gt;as&lt;/span&gt; [l nempty]; &lt;span class=&quot;hljs-built_in&quot;&gt;cbn&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt; *.
    &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; equ &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt; nempty.
    &lt;span class=&quot;hljs-built_in&quot;&gt;exfalso&lt;/span&gt;.
    now &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; nempty.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we need to prove that the result we provide (&lt;code class=&quot;hljs language-coq&quot;&gt;rst&lt;/code&gt;) when the
list is not empty is correct with respect to the specification of
&lt;code class=&quot;hljs language-coq&quot;&gt;pop&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;  a : Type
  l : {l : list a | ~ empty l}
  a0 : a
  rst : list a
  equ : proj1_sig l = a0 :: rst
  ============================
  exists a1 : a, proj1_sig l = a1 :: rst
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;  + &lt;span class=&quot;hljs-built_in&quot;&gt;destruct&lt;/span&gt; l &lt;span class=&quot;hljs-built_in&quot;&gt;as&lt;/span&gt; [l nempty]; &lt;span class=&quot;hljs-built_in&quot;&gt;cbn&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt; *.
    &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; equ.
    now &lt;span class=&quot;hljs-built_in&quot;&gt;exists&lt;/span&gt; a0.
&lt;span class=&quot;hljs-keyword&quot;&gt;Defined&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&apos;s have a look at the extracted code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;(** val pop : &apos;a1 list -&amp;gt; &apos;a1 list **)&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; pop = &lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt;
| &lt;span class=&quot;hljs-type&quot;&gt;Nil&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;(* absurd case *)&lt;/span&gt;
| &lt;span class=&quot;hljs-type&quot;&gt;Cons&lt;/span&gt; (a, l0) -&amp;gt; l0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If one tries to call &lt;code class=&quot;hljs language-coq&quot;&gt;pop nil&lt;/code&gt;, the &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;assert&lt;/span&gt;&lt;/code&gt; ensures the call fails. Extra
information given by the sigma type has been stripped away. It can be
confusing, and in practice it means that, we you rely on the extraction
mechanism to provide a certified OCaml module, you &lt;em&gt;cannot expose
strongly specified functions in its public interface&lt;/em&gt; because nothing in the
OCaml type system will prevent a misuse which will in practice leads to an
&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;&lt;/code&gt;. *)&lt;/p&gt;
&lt;h2&gt;Defining &lt;code class=&quot;hljs language-coq&quot;&gt;push&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;It is possible to specify &lt;code class=&quot;hljs language-coq&quot;&gt;push&lt;/code&gt; the same way &lt;code class=&quot;hljs language-coq&quot;&gt;pop&lt;/code&gt; has been. The only
difference is &lt;code class=&quot;hljs language-coq&quot;&gt;push&lt;/code&gt; accepts lists with no restriction at all. Thus, its
definition is a simpler, and we can write it without &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;refine&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; push {a} (l : list a) (x : a)
  : { l&apos; | &lt;span class=&quot;hljs-type&quot;&gt;l&lt;/span&gt;&apos; = x :: l } :=
  exist &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; (x :: l) eq_refl.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the extracted code is just as straightforward.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; push l a =
  &lt;span class=&quot;hljs-type&quot;&gt;Cons&lt;/span&gt; (a, l)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Defining &lt;code class=&quot;hljs language-coq&quot;&gt;head&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Same as &lt;code class=&quot;hljs language-coq&quot;&gt;pop&lt;/code&gt; and &lt;code class=&quot;hljs language-coq&quot;&gt;push&lt;/code&gt;, it is possible to add extra information in the
type of &lt;code class=&quot;hljs language-coq&quot;&gt;head&lt;/code&gt;, namely the returned value of &lt;code class=&quot;hljs language-coq&quot;&gt;head&lt;/code&gt; is indeed the first value
of &lt;code class=&quot;hljs language-coq&quot;&gt;l&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Definition&lt;/span&gt; head {a} (l : list a | &lt;span class=&quot;hljs-type&quot;&gt;~ empty&lt;/span&gt; l)
  : { x | &lt;span class=&quot;hljs-type&quot;&gt;exists&lt;/span&gt; r, proj1_sig l = x :: r }.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&apos;s not a surprise its definition is very close to &lt;code class=&quot;hljs language-coq&quot;&gt;pop&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;  &lt;span class=&quot;hljs-built_in&quot;&gt;refine&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;match&lt;/span&gt; proj1_sig l &lt;span class=&quot;hljs-built_in&quot;&gt;as&lt;/span&gt; l&apos;
                &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; proj1_sig l = l&apos; -&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt;
          &lt;span class=&quot;hljs-built_in&quot;&gt;with&lt;/span&gt;
          | &lt;span class=&quot;hljs-type&quot;&gt;[] =&amp;gt; fun&lt;/span&gt; equ =&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt;
          | &lt;span class=&quot;hljs-type&quot;&gt;x&lt;/span&gt; :: &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; =&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;fun&lt;/span&gt; equ =&amp;gt; exist &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt; x &lt;span class=&quot;hljs-keyword&quot;&gt;_&lt;/span&gt;
          &lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt; eq_refl).
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The proof is also very similar, and are left to read as an exercise for
passionate readers.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-coq&quot;&gt;  + &lt;span class=&quot;hljs-built_in&quot;&gt;destruct&lt;/span&gt; l &lt;span class=&quot;hljs-built_in&quot;&gt;as&lt;/span&gt; [l falso]; &lt;span class=&quot;hljs-built_in&quot;&gt;cbn&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt; *.
    &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; equ &lt;span class=&quot;hljs-built_in&quot;&gt;in&lt;/span&gt; falso.
    &lt;span class=&quot;hljs-built_in&quot;&gt;exfalso&lt;/span&gt;.
    now &lt;span class=&quot;hljs-built_in&quot;&gt;apply&lt;/span&gt; falso.
  + &lt;span class=&quot;hljs-built_in&quot;&gt;exists&lt;/span&gt; l0.
    now &lt;span class=&quot;hljs-built_in&quot;&gt;rewrite&lt;/span&gt; equ.
&lt;span class=&quot;hljs-keyword&quot;&gt;Defined&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, the extracted code is as straightforward as it can get.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ocaml&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; head = &lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt;
| &lt;span class=&quot;hljs-type&quot;&gt;Nil&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;(* absurd case *)&lt;/span&gt;
| &lt;span class=&quot;hljs-type&quot;&gt;Cons&lt;/span&gt; (a, l0) -&amp;gt; a
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Writing strongly specified functions allows for reasoning about the result
correctness while computing it. This can help in practice. However, writing
these functions with the &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;refine&lt;/span&gt;&lt;/code&gt; tactic does not enable a very idiomatic
Coq code.&lt;/p&gt;
&lt;p&gt;To improve the situation, the &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Program&lt;/span&gt;&lt;/code&gt; framework distributed with the
Coq standard library helps, but it is better to understand what &lt;code class=&quot;hljs language-coq&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Program&lt;/span&gt;&lt;/code&gt;
achieves under its hood, which is basically what we have done in this article.&lt;/p&gt;
        
      </description>
    </item>
    
    
  </channel>
</rss>
