<?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 - ocaml</title>
    <link>https://soap.coffee/~lthms/tags/ocaml.html</link>
    <description>Posts tagged "ocaml"</description>
    <atom:link href="https://soap.coffee/~lthms/tags/ocaml.xml" rel="self"
               type="application/rss+xml" />
    
    
    <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>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>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>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>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>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>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>
    
    
  </channel>
</rss>
