<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>https://patrick.sirref.org/Patrick Ferris/</name>
    <uri>https://patrick.sirref.org/Patrick%20Ferris/</uri>
  </author>
  <updated>2026-04-07T00:00:00-00:00</updated>
  <title>Patrick's OCaml Blog</title>
  <id>https://patrick.sirref.org/ocaml-blog/</id>
  <link rel="alternate" href="https://patrick.sirref.org/ocaml-blog/" />
  <link rel="self" href="https://patrick.sirref.org/ocaml-blog/atom.xml" />
  <entry>
    <title>OCaml Roundup: April 2026</title>
    <published>2026-04-07T00:00:00-00:00</published>
    <updated>2026-04-07T00:00:00-00:00</updated>
    <author>
      <name>https://patrick.sirref.org/Patrick Ferris/</name>
      <uri>https://patrick.sirref.org/Patrick%20Ferris/</uri>
    </author>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/ocaml-roundup-april-2026/" />
    <id>https://patrick.sirref.org/ocaml-roundup-april-2026/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>In April, I worked on lots of different projects. Thankfully, things have been quiet on the <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> front (in part due to <a href="https://patrick.sirref.org/nathanreb/">Nathan</a> taking on some more work and being between releases of the OCaml compiler). I managed to improve some of our migration error logic and do a little spring-cleaning.</p>
        <section>
          <header>
            <h2>More Landlock Thoughts</h2>
          </header>
          <p>Elsewhere, I spent some time exploring <a href="https://patrick.sirref.org/landlock-eio/">Landlock and how it might be used with Eio</a>. I think it is useful to down tools once in a while and try out some newfangled API or OS feature. Landlock is quite different to Capsicum (I had assumed they would be more similar). Whilst I enjoy the fine-grained control over access and capabilities, the manual process of constructing rules is a little cumbersome (and perhaps easy to make mistakes with). Combining that <![CDATA[with [Eio]'s capability API might make that more tenable. The idea being you]]> could have some Eio code like:</p>
          <pre class="hilite">
            <code>
              <span class="ocaml-keyword-other">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-unit"><![CDATA[()]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-constant-language-capital-identifier">Eio_linux</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">run</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">@@</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other">fun</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">env</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-entity-name-function-binding">data</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Eio</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">Path</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source">env</span>
              <span class="ocaml-keyword-other">#</span>
              <span class="ocaml-source">fs</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">/</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">/data</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other">in</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-constant-language-capital-identifier">Eio</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">Path</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">with_open_dir</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">sw</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">data</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">@@</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other">fun</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">data_dir</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-keyword-other">match</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Eio_linux</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">Landlock</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">enter</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-unit"><![CDATA[()]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other">with</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-keyword-other">|</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Error</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-constant-language-polymorphic-variant">`Msg</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">m</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">failwith</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">msg</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-keyword-other">|</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Ok</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-unit"><![CDATA[()]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">    </span>
              <span class="ocaml-comment-block"><![CDATA[(*]]></span>
              <span class="ocaml-comment-block"><![CDATA[ At this point, only certain default operations can happen to [data_dir].]]></span>
              <span class="ocaml-comment-block"><![CDATA[*)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">    </span>
              <span class="ocaml-source">analysis</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">data_dir</span>
              <span class="ocaml-source">
</span>
            </code>
          </pre>
          <p>Opening the directory (in the <code>openat</code>-sense) adds a Landlock rule to the current context (some kind of process-local state). This rule would be removed whenever the data directory is closed (by hand or when the function returns, i.e., when the internal <code>Eio.Switch</code> releases its resources). Doing the bookkeeping internally means mistakes are less likely to be made whilst also improving, in my opinion, the API.</p>
          <p>This breaks down for networking, unfortunately. Whilst the filesystem hierarchy provides a clean way to produce capabilities (a handle on a directory + <code>openat</code> + <code>RESOLVE_BENEATH</code>), networking does not. The Landlock API, at the time of writing, only allows rules based on <em>port numbers</em>. The system API is completely ambient (<code>socket</code> + <code>connect</code>). <a href="https://patrick.sirref.org/eio/">Eio</a>'s API provides access to the network through a single network `capability. All of these mechanisms are somewhat at odds. What does a network look like if it adheres to the ideas we have for combining Landlock and Eio (like in the filesystem example)?</p>
          <p>The API becomes port-oriented. We're already at odds with Unix domain sockets, but we will carry on regardless. A capability on a <em>port</em> means you can <code>listen</code> on that port and <code>accept</code> connections, or you could <code>connect</code> to it and send data. At the time of writing, Landlock is restricted to TCP ports. In <a href="https://patrick.sirref.org/eio/">Eio</a>, there is no API to <code>with_open_port</code>, i.e., to register your intent to do something with that port -- you either <code>listen</code> or <code>connect</code>.</p>
          <p>All of this starts feeling a lot like <a href="https://en.wikipedia.org/wiki/Plan_9_from_Bell_Labs">Plan 9</a>; something which I hope to explore further soon.</p>
        </section>
        <section>
          <header>
            <h2>Weekly logs</h2>
          </header>
          <p>The full details are in the weeklies transcluded below:</p>
          <section>
            <header>
              <h3>Moving away from Github</h3>
            </header>
            <p>A short week for me as I was hiking with family in and around <a href="https://en.wikipedia.org/wiki/Porthmadog">Porthmadog, Wales</a>.</p>
            <img width="600" src="https://patrick.sirref.org/bafkrmig6yukypbk4lk2xxq56dm3yfc7i7wm4vrwihpxs37ywu6s63wq3ri.jpg" />
            <section>
              <header>
                <h4>Reliance on Github</h4>
              </header>
              <p>I joined Github in 2016, but only began using it in earnest (according to my Github activity) in July 2018: right after Microsoft announced its intent to acquire Github; and just before <a href="https://www.computerworld.com/article/3535690/microsoft-acquisitions-a-timeline-of-growth-and-a-few-missteps.html">they closed the $7.5bn deal</a>. I originally joined to boost my résumé and I hoped to receive the odd open-source contribution to projects I was working on (like <a href="https://github.com/patricoferris/ppx_deriving_yaml">ppx_deriving_yaml</a>). Since then, I have used Github extensively both at work (<a href="https://tarides.com/">Tarides</a>) and for more personal projects.</p>
              <p>There have been many reasons to jump ship from Github ever since the Microsoft acquisition (e.g. <a href="https://github.com/resources/insights/2026-pricing-changes-for-github-actions">their planned (and quickly unplanned) announcement to charge self-hosted Github runners</a>). Ultimately, I was convinced when I noticed the new AI tool on the homepage with options to select your "versatile and highly intelligent" model. There is no need for me to stay on the platform for my personal projects. AI integration into Github has nullified those earlier motivations for hosting my projects on the site. The number of contributions has increased, but many of them fix superficial elements of an underlying bug. In my (maybe too uncharitable) imagination, it is all too easy for contributors to prompt their <em>built-in</em> LLM to "fix this broken unit test" and for the fix to layer a single-use workaround on top, instead of identifying and correcting the relevant code. This is, at least, what it looks like to me when I receive a new review request on my open-source projects.</p>
              <p>At the end of last week I set up my own Git infrastructure following <a href="https://patrick.sirref.org/ryangibb/">Ryan's</a> <a href="https://github.com/ryangibb/nixos">nixos</a> setup. In the future, the source of truth for my projects will be <a href="https://git.sirref.org/">git.sirref.org</a> (I will likely continue to mirror to <a href="https://tangled.org/patrick.sirref.org/">tangled.org</a> or Github).</p>
              <section>
                <header>
                  <h5>Reduce, Reuse, Recycle</h5>
                </header>
                <p>Part of self-hosting your own source code is managing some form of automatic testing. I hesitate to describe it as "continuous integration" as the term is confusing and overloaded. Luckily, parts of the OCaml community have been <a href="https://github.com/ocurrent">building test infrastructure for a while</a>.</p>
                <p>I have a proclivity for rebuilding things from scratch be it to learn or to build something the way I want. It is a proclivity I am trying to reign in as I find less and less time to hack on projects. I think this is a good thing. Reusing and recycling existing technologies, in earnest, feels like a pushback on the <a href="https://en.wikipedia.org/wiki/Not_invented_here">not-invented-here syndrome</a> that seems to be snowballing thanks to LLMs and code generation tools.</p>
                <p>To that end, I dusted off my <a href="https://www.ocurrent.org/">OCurrent</a> knowledge, and repurposed the "local" mode of <a href="https://ocaml.ci.dev/">OCaml-CI</a> to work with my <a href="https://git.sirref.org/">git repositories</a>. After battling through nested layers of git submodules, I managed to <code>Nix</code>-ify this and get it running at <a href="https://tests.sirref.org/">tests.sirref.org</a>. I needed to add multi-repository support as well as <a href="https://ocaml.org/p/current/0.7.4/doc/current/Current/Monitor/index.html">Current.Monitor</a>s for the local git refs. By no means perfect, but it is nice to own the testing infrastructure (and the cost of downloading OCaml images and the compute to run the tests).</p>
              </section>
            </section>
          </section>
          <section>
            <header>
              <h3>Landlocked Eio</h3>
            </header>
            <p>I spent the start of last week wrapping up the "local" CI I mentioned <a href="https://patrick.sirref.org/weekly-2026-w15/">the previous week</a>. Unfortunately it was mostly a packaging nightmare, followed by missing features in <code>ocaml-ci-local</code>. It would be great to have a richer CLI tool for running tests on a directory of git repositories, but unfortunately most of the existing tooling has prioritised the Github/Gitlab etc. APIs.</p>
            <p>After coming across <a href="https://minimal.dev/">minimal</a> during the week, I took it as an opportunity to learn a little more about Linux's <a href="https://lwn.net/Articles/859908/">Landlock</a> mechanism.</p>
            <section>
              <header>
                <h4>Landlocked Eio </h4>
              </header>
              <p><a href="https://lwn.net/Articles/859908/">Landlock</a> is a sandboxing mechanism that has existed in the Linux kernel since 5.13. It allows unprivileged processes a means to restrict their ambient rights (e.g. creating a file or opening a network connection). These rights are ambient in the <a href="https://en.wikipedia.org/wiki/Ambient_authority">ambient authority</a> sense, i.e., any process can attempt to perform an action without needing access to any particular capability to do so.</p>
              <p>Ambient systems are often contrasted with capability-based ones. In terms of operating systems, this is most commonly illustrated with <a href="https://patrick.sirref.org/miller2003capability/">access-control-lists-as-columns and capabilities-as-rows in an access matrix</a>.</p>
              <p><a href="https://patrick.sirref.org/eio/">Eio</a> is a capability-based library in OCaml -- resources are provided at the start of the application and can be passed around wherever they are needed. The design is covered in <a href="https://patrick.sirref.org/talex5/">Thomas Leonard</a>'s <a href="https://roscidus.com/blog/blog/2023/04/26/lambda-capabilities/">lambda capabilities blog post</a>. Unfortunately, any application (willingly or via a third-party library) may ambiently access OS resources. In OCaml, this may be by using the standard library functions (e.g. <code>Sys.readdir</code>), things from the <code>Unix</code> module, a C FFI function or by spawning a subprocess.</p>
              <p>I had a go at "landlocking" Eio applications last week after stumbling across <a href="https://minimal.dev/">minimal's</a> <a href="github.com/gominimal/hakoniwa">hakoniwa</a> library for process isolation (which is very reminiscent of <a href="https://patrick.sirref.org/void-processes/">void processes</a>).</p>
              <pre class="hilite">
                <code>
                  <span class="ocaml-keyword-other">module</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-constant-language-capital-identifier">Landlock</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-keyword-operator">=</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-constant-language-capital-identifier">Eio_linux</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                  <span class="ocaml-constant-language-capital-identifier">Landlock</span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-keyword-other">let</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-source"><![CDATA[(]]></span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-keyword-operator">/</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-source"><![CDATA[)]]></span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-keyword-operator">=</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-constant-language-capital-identifier">Eio</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                  <span class="ocaml-constant-language-capital-identifier">Path</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                  <span class="ocaml-source"><![CDATA[(]]></span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-keyword-operator">/</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-source"><![CDATA[)]]></span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-keyword">let</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-entity-name-function-binding">run_eio</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-source">file</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-keyword-operator">=</span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-source">  </span>
                  <span class="ocaml-constant-language-capital-identifier">Eio</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                  <span class="ocaml-source">traceln</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-string-quoted-double">"</span>
                  <span class="ocaml-string-quoted-double">Writing to file</span>
                  <span class="ocaml-string-quoted-double">"</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-source">  </span>
                  <span class="ocaml-constant-language-capital-identifier">Eio</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                  <span class="ocaml-constant-language-capital-identifier">Path</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                  <span class="ocaml-source">save</span>
                  <span class="ocaml-source"> ~</span>
                  <span class="ocaml-source">create</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                  <span class="ocaml-source"><![CDATA[(]]></span>
                  <span class="ocaml-constant-language-polymorphic-variant">`Exclusive</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-constant-numeric-octal-integer">0o644</span>
                  <span class="ocaml-source"><![CDATA[)]]></span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-source">file</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-string-quoted-double">"</span>
                  <span class="ocaml-string-quoted-double">hello, world!</span>
                  <span class="ocaml-string-quoted-double">"</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-source">  </span>
                  <span class="ocaml-constant-language-capital-identifier">Eio</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                  <span class="ocaml-source">traceln</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-string-quoted-double">"</span>
                  <span class="ocaml-string-quoted-double">Reading file: </span>
                  <span class="ocaml-constant-character-printf"><![CDATA[%s]]></span>
                  <span class="ocaml-string-quoted-double">"</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-source"><![CDATA[(]]></span>
                  <span class="ocaml-constant-language-capital-identifier">Eio</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                  <span class="ocaml-constant-language-capital-identifier">Path</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                  <span class="ocaml-source">load</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-source">file</span>
                  <span class="ocaml-source"><![CDATA[)]]></span>
                  <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-source">  </span>
                  <span class="ocaml-constant-language-capital-identifier">Eio</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                  <span class="ocaml-constant-language-capital-identifier">Path</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                  <span class="ocaml-source">unlink</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-source">file</span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-keyword">let</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-entity-name-function-binding">bad_program</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-constant-language-unit"><![CDATA[()]]></span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-keyword-operator">=</span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-source">  </span>
                  <span class="ocaml-constant-language-capital-identifier">In_channel</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                  <span class="ocaml-source">with_open_bin</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-string-quoted-double">"</span>
                  <span class="ocaml-string-quoted-double">/etc/passwd</span>
                  <span class="ocaml-string-quoted-double">"</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-constant-language-capital-identifier">In_channel</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                  <span class="ocaml-source">input_all</span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-source">  </span>
                  <span class="ocaml-keyword-operator">|&gt;</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-constant-language-capital-identifier">Eio</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                  <span class="ocaml-source">traceln</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-string-quoted-double">"</span>
                  <span class="ocaml-string-quoted-double">/etc/passwd: </span>
                  <span class="ocaml-constant-character-printf"><![CDATA[%s]]></span>
                  <span class="ocaml-string-quoted-double">"</span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-keyword-other">let</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-constant-language-unit"><![CDATA[()]]></span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-keyword-operator">=</span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-source">  </span>
                  <span class="ocaml-constant-language-capital-identifier">Eio_linux</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                  <span class="ocaml-source">run</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-keyword-operator">@@</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-keyword-other">fun</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-source">env</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-keyword-operator">-&gt;</span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-source">  </span>
                  <span class="ocaml-constant-language-capital-identifier">Eio</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                  <span class="ocaml-constant-language-capital-identifier">Path</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                  <span class="ocaml-source">with_open_dir</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-source"><![CDATA[(]]></span>
                  <span class="ocaml-constant-language-capital-identifier">Eio</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                  <span class="ocaml-constant-language-capital-identifier">Stdenv</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                  <span class="ocaml-source">cwd</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-source">env</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-keyword-operator">/</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-string-quoted-double">"</span>
                  <span class="ocaml-string-quoted-double">.</span>
                  <span class="ocaml-string-quoted-double">"</span>
                  <span class="ocaml-source"><![CDATA[)]]></span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-keyword-operator">@@</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-keyword-other">fun</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-source">dir</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-keyword-operator">-&gt;</span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-source">  </span>
                  <span class="ocaml-keyword">let</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-entity-name-function-binding">parent_fd</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-keyword-operator">=</span>
                  <span class="ocaml-source"> 
</span>
                  <span class="ocaml-source">    </span>
                  <span class="ocaml-constant-language-capital-identifier">Eio_unix</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                  <span class="ocaml-constant-language-capital-identifier">Resource</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                  <span class="ocaml-source">fd_opt</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-source"><![CDATA[(]]></span>
                  <span class="ocaml-source">fst</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-source">dir</span>
                  <span class="ocaml-source"><![CDATA[)]]></span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-keyword-operator">|&gt;</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-constant-language-capital-identifier">Option</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                  <span class="ocaml-source">get</span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-source">  </span>
                  <span class="ocaml-keyword-other">in</span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-source">  </span>
                  <span class="ocaml-keyword">let</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-entity-name-function-binding">file</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-keyword-operator">=</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-source">dir</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-keyword-operator">/</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-string-quoted-double">"</span>
                  <span class="ocaml-string-quoted-double">hello.txt</span>
                  <span class="ocaml-string-quoted-double">"</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-keyword-other">in</span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-source">  </span>
                  <span class="ocaml-keyword">let</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-entity-name-function-binding">rules</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-keyword-operator">=</span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-source">    </span>
                  <span class="ocaml-constant-language-capital-identifier">Landlock</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                  <span class="ocaml-constant-language-capital-identifier">Rule</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-source">      </span>
                  <span class="ocaml-source"><![CDATA[[]]></span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-source">        </span>
                  <span class="ocaml-source">path_beneath</span>
                  <span class="ocaml-source"> ~</span>
                  <span class="ocaml-source">parent_fd</span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-source">          ~</span>
                  <span class="ocaml-source">flags</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                  <span class="ocaml-constant-language-capital-identifier">Flags</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                  <span class="ocaml-constant-language-capital-identifier">Fs</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                  <span class="ocaml-source"><![CDATA[(]]></span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-source">            </span>
                  <span class="ocaml-source">write_file</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-keyword-operator">+</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-source">read_file</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-keyword-operator">+</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-source">make_reg</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-keyword-operator">+</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-source">remove_file</span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-source">           </span>
                  <span class="ocaml-source"><![CDATA[)]]></span>
                  <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-source">      </span>
                  <span class="ocaml-source"><![CDATA[]]]></span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-source">  </span>
                  <span class="ocaml-keyword-other">in</span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-source">  </span>
                  <span class="ocaml-keyword-other">match</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-constant-language-capital-identifier">Landlock</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                  <span class="ocaml-source">enter</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-source">rules</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-keyword-other">with</span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-source">  </span>
                  <span class="ocaml-keyword-other">|</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-constant-language-capital-identifier">Ok</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-constant-language-unit"><![CDATA[()]]></span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-keyword-operator">-&gt;</span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-source">      </span>
                  <span class="ocaml-source">run_eio</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-source">file</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-source">      </span>
                  <span class="ocaml-source">bad_program</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-constant-language-unit"><![CDATA[()]]></span>
                  <span class="ocaml-source">
</span>
                  <span class="ocaml-source">  </span>
                  <span class="ocaml-keyword-other">|</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-constant-language-capital-identifier">Error</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-constant-language-polymorphic-variant">`Not_supported</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-keyword-operator">-&gt;</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-constant-language-capital-identifier">Eio</span>
                  <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                  <span class="ocaml-source">traceln</span>
                  <span class="ocaml-source"> </span>
                  <span class="ocaml-string-quoted-double">"</span>
                  <span class="ocaml-string-quoted-double">Landlock not supported!</span>
                  <span class="ocaml-string-quoted-double">"</span>
                  <span class="ocaml-source">
</span>
                </code>
              </pre>
              <p>Running this program (with the necessary privileges) prints the following.</p>
              <pre><![CDATA[+Writing to file
+Reading file: hello, world!
Fatal error: exception Sys_error("/etc/passwd: Permission denied")]]></pre>
              <p>Eio already has a similar function for the BSDs using <a href="https://github.com/ocaml-multicore/eio#filesystem-access">capsicum</a>. In capsicum, <a href="https://man.freebsd.org/cgi/man.cgi?query=cap_enter">processes enter a capability mode</a>:</p>
              <blockquote>
                <p><code>cap_enter()</code> places the current process into capability mode, a mode of execution in which processes may	only issue system calls	operating on file descriptors or reading limited global system state.</p>
              </blockquote>
              <p>This plays nicely with <a href="https://patrick.sirref.org/eio/">Eio</a>'s capabilities. Within the scope of <code>Eio.Path.with_open_dir</code>, the directory will remain usable after entering "cap" mode. This is not the case with landlock unless you add a specific <code>path_beneath</code> rule to the ruleset (like in the example above). However, you could imagine plumbing the necessary information throughout the <code>Eio_linux</code> backend for it to build a set of rules that can be applied at any given moment in order to mimic the capsicum semantics.</p>
            </section>
            <section>
              <header>
                <h4>Self-hosting Music </h4>
              </header>
              <p>After my friend, <a href="https://gretathompson.com/">Greta</a>, sent me some articles about music streaming services and their exploitation of artists, I decided enough was enough and setup <a href="https://www.navidrome.org/">navidrome</a>. It is compatible with <a href="https://www.subsonic.org/pages/api.jsp">Subsonic</a> and so far I'm very pleased to be streaming my own music to my devices. I am using <a href="https://substreamer.org/">substreamer</a> on iOS. On my laptop, I tried out <a href="https://github.com/rossberg/camp">Andreas Rossberg's Camp</a></p>
              <blockquote>
                <p>What you got here is an old-school music player heavily inspired by good old <![CDATA[Winamp [1], with a focus on decent music library and playlist handling.]]></p>
              </blockquote>
              <p>I took <a href="https://patrick.sirref.org/anilmadhavapeddy/">Anil's</a> <a href="https://github.com/avsm/oi">OCaml Installer</a> tool for a spin with great success... after a few mishaps mostly related to system dependencies.</p>
              <pre><![CDATA[$ nix-shell -p pkg-config gcc pulseaudio miniaudio libxi libxrandr libxinerama libffi mesa libxcursor libGL 
$ oi-linux-x86_64 run --with=https://github.com/patricoferris/camp#nix -- camp]]></pre>
              <p>The fixes in my fork of Camp are just to install the assets using <code>dune</code> and also statically provide the <code>-lpulse</code> flag (which should probably be dynamically picked up). Otherwise, raylib or miniaudio selects the <code>Null</code> playback device. Roll-on <a href="https://ryan.freumh.org/papers/2026-package-calculus.html">cross-ecosystem package management</a>.</p>
              <img src="https://patrick.sirref.org/bafkrmifuphhk6ys7hpaqm2jaad6qr7253nevf6ddu4bh7d5tjyasp35kum.png" />
            </section>
          </section>
          <section>
            <header>
              <h3>Shell forks revisited</h3>
            </header>
            <p>Whilst I did get up to some other work last week, I decided to dedicate this weekly to <code>fork</code>-ing in the shell.</p>
            <section>
              <header>
                <h4>Must we fork?</h4>
              </header>
              <p>I have spent some time trying to figure out: can you implement a shell that never has to <code>fork</code> and run its own code (as opposed to <code>fork+exec</code>-ing, which is necessary)? There are, at least, two bits of POSIX shell semantics that make this hard: concurrency and redirects, particularly in the presence of shell built-ins.</p>
              <p>Individual commands in a pipeline, according to the <a href="https://patrick.sirref.org/posixSpec/">POSIX specification</a>, will have their standard input and output connected up before other redirections.</p>
              <blockquote>
                <p>The standard input, standard output, or both of a command shall be considered to be assigned by the pipeline before any redirection specified by redirection operators that are part of the command.</p>
              </blockquote>
              <p>Additionally:</p>
              <blockquote>
                <p>...each command of a multi-command pipeline is in a subshell environment; as an extension, however, any or all commands in a pipeline may be executed in the current environment.</p>
              </blockquote>
              <p>Where a subshell is defined as:</p>
              <blockquote>
                <p>Subshell: A shell execution environment, distinguished from the main or current shell execution environment.</p>
              </blockquote>
              <p>We will note that subshell <code>\neq </code> child process. In practice, however, the two are used fairly interchangeably given the semantics of spawning a child process. Perhaps the two most crucial aspects of a given command in a subshell are that:</p>
              <ol>
                <li>
                  <p>It is run <em>in parallel</em> with the other commands.</p>
                </li>
                <li>
                  <p>It should be <a href="https://en.wikipedia.org/wiki/Reentrancy_(computing)"><em>reentrant</em></a>.</p>
                </li>
              </ol>
              <p>In what follows we will assume that we are discussing a multi-command pipeline <code>p</code>.</p>
              <p>
                <code> \texttt {p} =  \texttt {cmd}_1 | ... | \texttt {cmd}_n \text { where } n \geq  2 </code>
              </p>
              <section>
                <header>
                  <h5>Pipeline parallelism</h5>
                </header>
                <p>The <a href="https://patrick.sirref.org/posixSpec/">POSIX specification</a> does not mandate parallelism explicitly for commands in a pipeline. However, in practice the semantics of a pipeline necessitate concurrency at the very least.</p>
                <p>Suppose we have <code>\texttt {cmd}_1 | \texttt {cmd}_2</code> where <code>\texttt {cmd}_1</code> produces an infinite amount of output (e.g., <code>cat /dev/urandom</code>) and <code>\texttt {cmd}_2</code> consumes a finite amount of input (e.g., <a href="https://github.com/dinosaure/hxd"><code>hxd-xxd -l100</code></a>). What is the result of running this pipeline with the default POSIX shell options?</p>
                <pre class="hilite">
                  <code>
                    <span class="sh-source">$ dash -c </span>
                    <span class="sh-punctuation-definition-string-begin">"</span>
                    <span class="sh-string-quoted-double">cat /dev/urandom | hxd.xxd -l100</span>
                    <span class="sh-punctuation-definition-string-end">"</span>
                    <span class="sh-source">
</span>
                    <span class="sh-source">00000000: 5033 7981 ae44 d475 074c 5361 0a9e 3828  P3y..D.u.LSa..8</span>
                    <span class="sh-punctuation-definition-subshell"><![CDATA[(]]></span>
                    <span class="sh-meta-scope-subshell">
</span>
                    <span class="sh-meta-scope-subshell">00000010: f88c 1f9e 3b0e bcde 528a f78c b1e4 7195  ....</span>
                    <span class="sh-keyword-operator-list">;</span>
                    <span class="sh-meta-scope-subshell">...R.....q.
</span>
                    <span class="sh-meta-scope-subshell"><![CDATA[00000020: 16f2 8325 c90b 9310 539c af04 8289 c3a0  ...%....S.......]]></span>
                    <span class="sh-meta-scope-subshell">
</span>
                    <span class="sh-meta-scope-subshell">00000030: 57c5 680a 2c81 a999 71b6 708e 95df e720  W.h.,...q.p....
</span>
                    <span class="sh-meta-scope-subshell">00000040: 004c 407a 8365 9448 65c6 b435 bed2 4084  .L@z.e.He..5..@.
</span>
                    <span class="sh-meta-scope-subshell">00000050: 62ea 96ab 2b23 0385 f9d2 fc30 d090 1719  b...+#.....0....
</span>
                    <span class="sh-meta-scope-subshell">00000060: 68d1 c514                                h...
</span>
                    <span class="sh-meta-scope-subshell">cat: write error: Broken pipe
</span>
                  </code>
                </pre>
                <p>There are three factors that influence the pipeline's execution behaviour (i.e. what is done about the commands that are run and the exit status we return).</p>
                <ol>
                  <li>
                    <p><code>pipefail</code>: With <code>pipefail</code> set to <code>false</code> (the default), the exit status of the pipeline is entirely decided upon by the exit status of the <em>rightmost</em> command (above <code>\texttt {cmd}_2</code>). With <code>pipefail</code>, the pipe will exit with 0 if all commands exit with 0; otherwise the non-zero exit status of the <em>rightmost</em> command is taken.</p>
                  </li>
                  <li>
                    <p><code>!</code>: If the pipeline begins with <code>!</code> then this inverts the exit code in the way you might expect.</p>
                  </li>
                  <li>
                    <p>All commands must terminate.</p>
                  </li>
                </ol>
                <p>Whilst in theory <code>\texttt {cmd}_1</code> does not terminate, the termination of <code>\texttt {cmd}_2</code> closes the reading end of the pipe resulting in the <code>Broken pipe</code> system error.</p>
                <p>Let's replace <code>\texttt {cmd}_1</code> with the following <em>compound command</em> that also produces, left to its own devices, infinite output on <code>stdout</code>.</p>
                <pre class="hilite">
                  <code>
                    <span class="sh-keyword-control">while</span>
                    <span class="sh-meta-scope-while-loop"> </span>
                    <span class="sh-support-function-builtin">echo</span>
                    <span class="sh-meta-scope-while-loop"> </span>
                    <span class="sh-punctuation-definition-string-begin">"</span>
                    <span class="sh-string-quoted-double">some bytes</span>
                    <span class="sh-punctuation-definition-string-end">"</span>
                    <span class="sh-keyword-operator-list">;</span>
                    <span class="sh-meta-scope-while-loop"> </span>
                    <span class="sh-keyword-control">do</span>
                    <span class="sh-meta-scope-while-loop">
</span>
                    <span class="sh-meta-scope-while-loop">  </span>
                    <span class="sh-support-function-builtin">:</span>
                    <span class="sh-meta-scope-while-loop">
</span>
                    <span class="sh-keyword-control">done</span>
                    <span class="sh-source"> </span>
                    <span class="sh-keyword-operator-pipe">|</span>
                    <span class="sh-source"> hxd.xxd -l100
</span>
                  </code>
                </pre>
                <p>In this example, we no longer have the luxury of being able to <code>fork</code> and <code>exec</code>. The compound command (the <code>while</code> loop) forces our hand -- we must rely on the internal execution logic of the shell to keep it going. How then do we prevent <code>\texttt {cmd}_1</code> from blocking our shell from spawning <code>\texttt {cmd}_2</code>?</p>
                <p>For most shells, this is where they might <code>fork</code> themselves and allow the <code>while</code> loop to execute in the child. The parent continuing on. Alternatively, the work could continue on in a separate thread (in OCaml parlance, domain). Fibers (green threads, coroutines etc.) are only possible if there are a sufficient number of co-operative yields (which can be hard to track: any control flow or shell built-in would need to ensure they periodically yield to the other commands in the pipeline).</p>
                <p>With that being said, it would seem we have workarounds to ensure the parallel aspects of pipelines are possible to build without forking the shell state itself.</p>
              </section>
              <section>
                <header>
                  <h5>Command Reentrancy</h5>
                </header>
                <p>Command reentrancy deals with the fact that commands in a pipeline run in <em>subshells</em>. In practice, this means any <code>\texttt {cmd}_i</code> should not impact the <em>execution environment</em> of any other <code>\texttt {cmd}_j</code>. Commands may certainly interfere with one another: a rogue <code>rm</code> might remove a file that some other command was about to read or was in the middle of reading!</p>
                <p><code>\S 2.13</code> of the POSIX shell specification describes the execution environment. In <a href="https://patrick.sirref.org/merry/">Merry</a> we lift this into the <code>ctx</code> type making it completely immutable; the only way to update the context is to destructively declare new fields, e.g., <code><![CDATA[{ ctx with cwd = "/home/bactrian" }]]></code>. All shell built-ins work directly from the context as opposed to any state that might <em>also</em> be kept by the process itself (e.g., we do not call <code>getcwd(3)</code> to expand <code>PWD</code>, but instead read it from the context).</p>
                <p>Most state is handled nicely by this <em>functional</em> implementation of the shell; except open (or not) file descriptors. The <code>exec</code> built-in is particularly thorny in this regard:</p>
                <blockquote>
                  <p>If exec is specified with no operands, any redirections associated with the exec command shall be made in the current shell execution environment.</p>
                </blockquote>
                <p>So, <code>exec 3&gt;&amp;1</code> says "in the current execution environment map file descriptor <code>3</code> to <code>stdout</code>" and <code>exec &gt; /dev/null</code> says "in the current execution environment map <code>stdout</code> to <code>/dev/null</code>. This is often used to silence anything writing to <code>stdout</code>.</p>
                <pre class="hilite">
                  <code>
                    <span class="sh-entity-name-function">info</span>
                    <span class="sh-meta-function"> </span>
                    <span class="sh-punctuation-definition-arguments"><![CDATA[()]]></span>
                    <span class="sh-meta-function"> </span>
                    <span class="sh-punctuation-definition-group"><![CDATA[{]]></span>
                    <span class="sh-meta-scope-group">
</span>
                    <span class="sh-meta-scope-group">  </span>
                    <span class="sh-support-function-builtin">echo</span>
                    <span class="sh-meta-scope-group"> </span>
                    <span class="sh-punctuation-definition-string-begin">"</span>
                    <span class="sh-string-quoted-double">INFO: </span>
                    <span class="sh-punctuation-definition-variable">$</span>
                    <span class="sh-variable-other-positional">1</span>
                    <span class="sh-punctuation-definition-string-end">"</span>
                    <span class="sh-meta-scope-group"> </span>
                    <span class="sh-keyword-operator-redirect">&gt;&amp;3</span>
                    <span class="sh-meta-scope-group">
</span>
                    <span class="sh-punctuation-definition-group"><![CDATA[}]]></span>
                    <span class="sh-punctuation-definition-function">
</span>
                    <span class="sh-source">
</span>
                    <span class="sh-support-function-builtin">exec</span>
                    <span class="sh-source"> </span>
                    <span class="sh-keyword-operator-redirect">3&gt;&amp;1</span>
                    <span class="sh-source"> </span>
                    <span class="sh-keyword-operator-redirect">&gt;</span>
                    <span class="sh-source"> /dev/null
</span>
                    <span class="sh-source">info </span>
                    <span class="sh-punctuation-definition-string-begin">"</span>
                    <span class="sh-string-quoted-double">Starting up server...</span>
                    <span class="sh-punctuation-definition-string-end">"</span>
                    <span class="sh-source">
</span>
                    <span class="sh-support-function-builtin">echo</span>
                    <span class="sh-source"> </span>
                    <span class="sh-punctuation-definition-string-begin">"</span>
                    <span class="sh-string-quoted-double">Some noisy program spamming STDOUT</span>
                    <span class="sh-punctuation-definition-string-end">"</span>
                    <span class="sh-source">
</span>
                    <span class="sh-source">info </span>
                    <span class="sh-punctuation-definition-string-begin">"</span>
                    <span class="sh-string-quoted-double">All is quiet...</span>
                    <span class="sh-punctuation-definition-string-end">"</span>
                    <span class="sh-source">
</span>
                  </code>
                </pre>
                <p>If we are not running shell built-ins inside new child processes, then we must lift the file descriptor table into the context as well and <em>disallow</em> any two built-ins to run in parallel. Consider this example:</p>
                <pre class="hilite">
                  <code>
                    <span class="sh-support-function-builtin">exec</span>
                    <span class="sh-source"> </span>
                    <span class="sh-keyword-operator-redirect">&lt;</span>
                    <span class="sh-source"> ./hello.txt
</span>
                    <span class="sh-source">
</span>
                    <span class="sh-keyword-control">while</span>
                    <span class="sh-meta-scope-while-loop"> </span>
                    <span class="sh-support-function-builtin">read</span>
                    <span class="sh-meta-scope-while-loop"> line</span>
                    <span class="sh-keyword-operator-list">;</span>
                    <span class="sh-meta-scope-while-loop"> </span>
                    <span class="sh-keyword-control">do</span>
                    <span class="sh-meta-scope-while-loop">
</span>
                    <span class="sh-meta-scope-while-loop">  </span>
                    <span class="sh-support-function-builtin">echo</span>
                    <span class="sh-meta-scope-while-loop"> </span>
                    <span class="sh-punctuation-definition-string-begin">"</span>
                    <span class="sh-string-quoted-double">Got </span>
                    <span class="sh-punctuation-definition-variable">$</span>
                    <span class="sh-variable-other-normal">line</span>
                    <span class="sh-punctuation-definition-string-end">"</span>
                    <span class="sh-meta-scope-while-loop"> </span>
                    <span class="sh-keyword-operator-redirect">&gt;&amp;2</span>
                    <span class="sh-meta-scope-while-loop">
</span>
                    <span class="sh-keyword-control">done</span>
                    <span class="sh-source"> </span>
                    <span class="sh-keyword-operator-pipe">|</span>
                    <span class="sh-source"> </span>
                    <span class="sh-punctuation-definition-subshell"><![CDATA[(]]></span>
                    <span class="sh-meta-scope-subshell">exec </span>
                    <span class="sh-keyword-operator-redirect">&lt;</span>
                    <span class="sh-meta-scope-subshell"> ./world.txt</span>
                    <span class="sh-keyword-operator-list">;</span>
                    <span class="sh-meta-scope-subshell"> cat</span>
                    <span class="sh-punctuation-definition-subshell"><![CDATA[)]]></span>
                    <span class="sh-source">
</span>
                  </code>
                </pre>
                <p>If we allow <code>exec</code> to <em>change</em> the set of open file descriptors of the shell process directly, then individual commands in the pipeline are no longer re-entrant. The pipeline here is not being used to pipe bytes from one command to another, but instead to expose concurrency and the subshell behaviour.</p>
                <p>The second <code>exec &lt; ./world.txt</code> has no impact on the currently opened file on <code>stdin</code>, the while loop continues to read <code>./hello.txt</code>. This is straightforward to implement with <code>fork</code> as you can <code>dup2</code> any files you need. The bookkeeping and isolation is all provided by the POSIX process semantics. Without <code>fork</code>, the file descriptors would have to be saved and restored on every suspension and resumption to provide an illusion of isolation.</p>
                <p>We could relax our rule to "disallow any two built-ins to run in parallel" by taking a lock on the file descriptor table, but considering the lock is held from the point of resumption until the next suspension it might not achieve very much in practice.</p>
                <p>Some of the intricacies of scheduling are also covered in <a href="https://patrick.sirref.org/greenberg2020smoosh/">Michael Greenberg's <em>An executable and formal semantics of the POSIX shell</em></a>.</p>
                <blockquote>
                  <p>To motivate the question, consider the following two pipelines:</p>
                  <p>(1) <code>while true; do echo 5; done | true</code></p>
                  <p>(2) <code><![CDATA[while true; do echo 5; done | { read x; echo $((x+42)); }]]></code></p>
                  <p>Both pipelines spawn two processes, both of which use shell builtins exclusively: neither of these pipelines needs to make an <code>execve</code> system call (though some systems may implement true or echo as executables, Smoosh and most shells build them in).</p>
                </blockquote>
                <p>Scheduling is an opaque part of the <a href="https://patrick.sirref.org/posixSpec/">POSIX specification</a>. Indeed, as we have argued here, there is <em>no</em> semantics for scheduling. Here is a similar pipeline run through a script that <code>strace</code>s for <code>clone</code> and <code>fork</code> calls on various shells:</p>
                <pre><![CDATA[% ./test/check_fork.sh "while echo 5; do : ; done | true"
bash  3
dash  3
yash  1 
zsh   1
ksh   1
ash   3]]></pre>
                <p>It might make an interesting use case for effects in OCaml -- whilst we can certainly piggyback on <a href="https://patrick.sirref.org/eio/">Eio</a>'s existing suspension mechanisms, this is slightly different in that we need to ensure some preconditions are true before resuming certain computations. Fiber-local state is insufficient as programs implicitly depend on global state of the process (in particular the FD table). In this sense, we need some form of suspension-resumption hooks.</p>
              </section>
            </section>
          </section>
        </section>
      </div>
    </content>
  </entry>
  <entry>
    <title>OCaml Roundup: February 2026</title>
    <published>2026-03-10T00:00:00-00:00</published>
    <updated>2026-03-10T00:00:00-00:00</updated>
    <author>
      <name>https://patrick.sirref.org/Patrick Ferris/</name>
      <uri>https://patrick.sirref.org/Patrick%20Ferris/</uri>
    </author>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/ocaml-roundup-february-2026/" />
    <id>https://patrick.sirref.org/ocaml-roundup-february-2026/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>Much like last month, this month has been busy with lots of work on <a href="https://patrick.sirref.org/ocaml-tiff/">ocaml-tiff</a> thanks to <a href="https://patrick.sirref.org/tambe%20salome/">Tambe Salome</a> and <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a>.</p>
        <section>
          <header>
            <h2>Outreachy</h2>
          </header>
          <p><a href="https://patrick.sirref.org/tambe%20salome/">Tambe Salome</a>, at the time of writing, has completed her internship! We will be hosting the biannual <a href="https://discuss.ocaml.org/t/outreachy-demo-day-for-december-2025-round/17883">Demo Day celebration</a> for this round's interns, so please do come along.</p>
          <p>Since the last update <a href="https://patrick.sirref.org/tambe%20salome/">Tambe Salome</a> and I have been slowly making progress on making the write-functionality more feature-complete. As I eluded <a href="https://patrick.sirref.org/ocaml-roundup-january-2026/">last month</a>, TIFF files are <em>hard</em> to write. Their internal structure is all over the place: directories, immediate and non-immediate values, 32-bit or 64-bit, little or big endian etc. We're tackling this bit by bit, evolving the library to be able to support writing to files. In the early days, when we only read TIFF files there was no need to store information that we could readily pull from the file itself (via something like <code>pread(2)</code>). Now, we need to be able to hold those same values in memory before writing them to the file, so we will need some kind of API change internally to support this.</p>
          <p>This month, I also bumped up against well-meaning contributions to <a href="https://patrick.sirref.org/ocaml-tiff/">ocaml-tiff</a> that made use of AI. This left me with some thoughts that I am adding below.</p>
          <section>
            <header>
              <h3>Vibecoding Etiquette</h3>
            </header>
            <p>I am yet to jump head-first into using LLM-based tools like Claude Code or even ChatGPT to help with my programming in any serious way. After using some "free"-tier tools to try to better understand some tricky eBPF problems and to make sense of the semantics of POSIX shells, I was left unimpressed and ultimately felt my time was wasted.</p>
            <p>I feel unwilling to send my money to the corporations behind these tools. This is for a variety of reasons including the deeply worrying relationship with the US Department of War (I struggle to find the meaningful difference between <a href="https://www.anthropic.com/news/where-stand-department-war">"opertational planning" vs. "operational decision-making" given the leaders of the US DoW</a>), environmental concerns, exploitation of human labour and a fast-and-loose approach to copyright laws. All of which leaves the entire industry very unattractive to me.</p>
            <p>Everybody can draw their line where they want, and I am, in good faith, trying to find where mine should be.</p>
            <p>Unfortunately, my own decision to not use these tools is not completely in my control. What do I do about pull requests to open-source libraries I maintain that include agentic code? I am, after all, participating in the idea of open-source and inclusive collaboration. Agentic code also comes in many flavours, from blatant LLM-generated pull requests to heavily edited, human-in-the-loop contributions.</p>
            <p>An immediate first step for me is to develop some policy for contributions to projects I maintain regarding code where LLMs have had a hand. This can help set expectations for contributors. <a href="https://github.com/ocaml-multicore/eio/blob/main/HACKING.md#ai-generated-code">Eio's "AI-generated Code"</a> subsection is succinct and prohibits contributions that <em>solely</em> use AI.</p>
            <blockquote>
              <p>It obfuscates how you think. Purely AI-generated code tells us little about how you think and the problems you might be having. This makes it harder to provide good feedback on PRs and issues.</p>
              <p>It is often more work to review. Particularly for the OCaml ecosystem and libraries like Eio, it seems that these tools are not very good and generate a lot of believable code that is in actual fact completely wrong. PR comments and the code submitted with them can say completely different things.</p>
              <p>It is a grey area for licensing. Models like ChatGPT have been trained on lots of code with different licenses and has been known to simply copy code as an answer to a prompt. We would like to avoid this headache as best we can.</p>
            </blockquote>
            <p>Additionally, I plead to other developers to <em>own</em> their use of these tools. Please, make Claude a co-author of the commits where Claude has generated <em>any</em> code at the very least. This is the bare minimum. I have strong feelings about the etiquette of sending AI summarised information or LLM-generated code to other people, but before any of that, the decent thing is to remove any uncertainty in the receiving party's mind of how the information they are receiving came to be. In this way, I appreciate the <a href="https://github.com/ocaml/ocaml/blob/trunk/AI.md">OCaml compiler's AI notice</a> which includes:</p>
            <blockquote>
              <p>If a significant portion of your code, PR description, review comments or messages has been AI-generated, this must be disclosed, stating which tool was used and for what. Reviewing AI-produced code can require a different approach from human-written code. You should have an acknowledgement anyway even if another human contributor did some of the work.</p>
            </blockquote>
          </section>
        </section>
        <section>
          <header>
            <h2>Ppxlib</h2>
          </header>
          <p>We are still in the throes of supporting OCaml 5.5 in <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a>. Some of the features have proved more complicated to encode into migrations that "roundtrip". Roundtripping, in the context of <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a>, is when a modern feature of OCaml must be preserved in older abstract syntax trees which may have no specific node to encode them.</p>
          <section>
            <header>
              <h3>Bugs in Ptyp_open</h3>
            </header>
            <p>Unfortunately, <a href="https://patrick.sirref.org/jonmsterling/">Jon Sterling</a> was <a href="https://mastodon.social/@jonmsterling@mathstodon.xyz/116085163199163273">bitten by this recently</a>. The feature in question was locally opening modules in types (added in OCaml 5.2). For example:</p>
            <pre class="hilite">
              <code>
                <span class="ocaml-keyword-other">module</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">M</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other">struct</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">  </span>
                <span class="ocaml-keyword-other">type</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">t</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-support-type">int</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-keyword-other">end</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-keyword-other">type</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">t</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">M</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source"><![CDATA[(]]></span>
                <span class="ocaml-source">t</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">list</span>
                <span class="ocaml-source"><![CDATA[)]]></span>
                <span class="ocaml-source">
</span>
              </code>
            </pre>
            <p>Here, the <code>M.(t list)</code> is an example of a new AST node called <code>Ptyp_open</code>. I had hastily not migrated <code>Ptyp_open</code> to older compilers. So what happened? Jon had used this new feature in his project with a 5.3 compiler with <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> 0.35. This is before our <a href="https://patrick.sirref.org/ppxlib-5-2/">internal bump to the 5.2 AST</a> so the code migrated all the way down to OCaml 4.14! Whilst passing from 5.2 to 5.1 we raised an error saying:</p>
            <blockquote>
              <p>Error: migration error: module open in types is not supported before OCaml 5.02</p>
            </blockquote>
            <p>The error is confusing (least of all because there is a typo on the OCaml version number). Since then, we have <a href="https://github.com/ocaml-ppx/ppxlib/pull/625">patched this issue</a> and have planned to <a href="https://github.com/ocaml-ppx/ppxlib/compare/main...0.35">release a patched 0.35</a> in the not too distant future.</p>
            <p>If you can bump to <code>ppxlib&gt;=0.36</code> then you will not face this issue.</p>
          </section>
          <section>
            <header>
              <h3>Modular Explicits</h3>
            </header>
            <p>We ran into a fairly interesting corner of the OCaml language whilst trying to migrate modular explicits in <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a>. As a recap, in OCaml 5.5 you can now right function types that depend on modules. For example:</p>
            <pre class="hilite">
              <code>
                <span class="ocaml-keyword-other">module</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other">type</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">Add</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other">sig</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">  </span>
                <span class="ocaml-keyword">type</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-entity-name-function-binding">t</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">  </span>
                <span class="ocaml-keyword">val</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-entity-name-function-binding">add</span>
                <span class="ocaml-source"> : t -&gt; t -&gt; t
</span>
                <span class="ocaml-keyword-other">end</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-keyword">let</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-entity-name-function-binding">add</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[(]]></span>
                <span class="ocaml-keyword-other">module</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">A</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">Add</span>
                <span class="ocaml-source"><![CDATA[)]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">-&gt;</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">A</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source">t</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">-&gt;</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">A</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source">t</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">-&gt;</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">A</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source">t</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">  </span>
                <span class="ocaml-keyword-other">fun</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[(]]></span>
                <span class="ocaml-keyword-other">module</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">A</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">Add</span>
                <span class="ocaml-source"><![CDATA[)]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">a</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">b</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">-&gt;</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">A</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source">add</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">a</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">b</span>
                <span class="ocaml-source">
</span>
              </code>
            </pre>
            <p>We have to tell the compiler the module type of <code>A</code> by adding <code>: Add</code>. However, there is another very similar syntax for these kinds of constraints, <code>(module A : module Add)</code>. And in fact, the former syntax was syntactic sugar for the latter. In OCaml 5.5, these two <a href="https://github.com/ocaml/ocaml/pull/14149">were distinguished from one another</a> and <code>(module A : Add)</code> is the required syntax for modular explicits. As you might imagine, this is a bit of a headache in terms of <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> migrations. In the end, we try to preserve the original intent of the author where possible, and you can read more about it on the PR for distinguishing the two.</p>
          </section>
        </section>
        <section>
          <header>
            <h2>Six Month Retrospective</h2>
          </header>
          <p>This month marks the end of six months of work with <a href="https://tarides.com/">Tarides</a>. I wrote a small retrospective and plan for my next six months below.</p>
          <section>
            <header>
              <h3>Fellowship Roundup</h3>
            </header>
            <section>
              <header>
                <h4>Overview</h4>
              </header>
              <p>February is the final month of my current six-month fellowship work with <a href="https://tarides.com/">Tarides</a>. A lot of the work can be summarised by reading the <a href="https://patrick.sirref.org/ocaml-blog/">roundups</a> (see <a href="https://patrick.sirref.org/ocaml-roundup-october-2025/">October</a>, <a href="https://patrick.sirref.org/ocaml-roundup-november-2025/">November</a>, <a href="https://patrick.sirref.org/ocaml-roundup-december-2025/">December</a> and <a href="https://patrick.sirref.org/ocaml-roundup-january-2026/">January</a>). I have been writing throughout the fellowship. However, they do not quite capture all the work I have been doing.</p>
              <p>Below, I pick individual projects and expand on them more holistically rather than pointing at individual PRs or issues.</p>
              <section>
                <header>
                  <h5>Ppxlib</h5>
                </header>
                <p>Most of my time over the past six months has been devoted to <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> maintenance. A large proportion of this time has been solo development work. <a href="https://patrick.sirref.org/ppxlib/">Ppxlib</a> is a cornerstone library of the OCaml ecosystem (whether people like it or not).</p>
                <pre><![CDATA[$ opam list --depends-on=ppxlib --recursive | wc -l
2030]]></pre>
                <p>Moreover, it is completely invaluable to Jane Street too. Like other AST-based tools (e.g. ocamlformat, merlin), <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> must follow a regular release schedule to support newer compilers. During the years of multicore OCaml development, <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> maintenance was a little easier as the Parsetree rarely changed. However, since then, the same cannot be said. Since OCaml 5.2, here are just some of the Parsetree changes:</p>
                <ul>
                  <li>
                    <p>Functions are represented according to their arity.</p>
                  </li>
                  <li>
                    <p>Local module opens on types.</p>
                  </li>
                  <li>
                    <p>Effect syntax.</p>
                  </li>
                  <li>
                    <p>Modular explicits.</p>
                  </li>
                  <li>
                    <p>External types.</p>
                  </li>
                  <li>
                    <p>Locations for all parts of long identifiers.</p>
                  </li>
                  <li>
                    <p>Labeled tuples.</p>
                  </li>
                </ul>
                <p>In a perfect world, each of these require a codec for serialising the feature into ASTs that do not support the feature, plenty of tests and new <code>Ast_builder</code>/<code>Ast_pattern</code> functions for using the feature. <a href="https://patrick.sirref.org/nathanreb/">Nathan</a> and I have been managing pretty well I would say, though we are not getting any technical debt work done.</p>
              </section>
              <section>
                <header>
                  <h5>Outreachy</h5>
                </header>
                <p>As the OCaml coordinator for <a href="https://patrick.sirref.org/outreachy/">Outreachy</a> I have been running the latest December 2025 round. We are lucky to have <em>four</em> projects on the go!</p>
                <ul>
                  <li>
                    <p>Thibaut Mattio is mentoring two projects: <a href="https://www.outreachy.org/outreachy-december-2025-internship-cohort/communities/ocaml/#raven-create-a-monitoring-dashboard-for-deep-learn">an ML dashboard for Raven</a> and <a href="https://www.outreachy.org/outreachy-december-2025-internship-cohort/communities/ocaml/#create-an-oxcaml-backend-for-raven">an OxCaml backend for Raven</a>.</p>
                  </li>
                  <li>
                    <p><a href="https://github.com/xvw">Xvw</a> is mentoring a <a href="https://github.com/yocaml/">Yocaml</a> <a href="https://www.outreachy.org/outreachy-december-2025-internship-cohort/communities/ocaml/#improve-yocaml-error-reporting-and-data-model">project</a>.</p>
                  </li>
                  <li>
                    <p>I am <a href="https://patrick.sirref.org/outreachy-ocaml-tiff/">mentoring</a> a <a href="https://patrick.sirref.org/geocaml/">Geocaml</a> project.</p>
                  </li>
                </ul>
              </section>
              <section>
                <header>
                  <h5>Eio</h5>
                </header>
                <p>During my work on tools like <a href="https://patrick.sirref.org/shelter/">Shelter</a> I have made a few improvements to <a href="https://patrick.sirref.org/eio/">Eio</a> including:</p>
                <ul>
                  <li>
                    <p><a href="https://github.com/ocaml-multicore/eio/pull/821">A draft PR for incremental reading of directories</a>.</p>
                  </li>
                  <li>
                    <p><a href="https://github.com/ocaml-multicore/eio/pull/803">New fork actions for processes: setgid, setuid and process groups</a>.</p>
                  </li>
                  <li>
                    <p><a href="https://github.com/ocaml-multicore/eio/pull/823">Utility functions for overriding standard environments</a>.</p>
                  </li>
                  <li>
                    <p><a href="https://github.com/ocaml-multicore/eio/pull/822">Fixing documentation</a>.</p>
                  </li>
                </ul>
              </section>
              <section>
                <header>
                  <h5>OxCaml</h5>
                </header>
                <p>I have enjoyed my work on OxCaml went it has happend. I think a few tools have been useful including the <a href="https://patrick.sirref.org/try-oxcaml/">try-oxcaml</a> work. <a href="https://patrick.sirref.org/dra27/">David</a> and I also had fun at <a href="https://patrick.sirref.org/icfp-2025/">ICFP</a> discussing some quick experiments related to <a href="https://patrick.sirref.org/icfp-oxcaml-uring/">io_uring and OxCaml</a>.</p>
                <p>One road-blocker here is the comparative amount of time spent trying to keep the OxCaml ecosystem working. Given my limited time working on fellowship projects, the rate of change of OxCaml (including the opam ecosystem) meant most of the time was spent making it just work, not exploring or experimenting with the features themselves. I think this has got better in recent months and perhaps jumping back in I would be surprised at the progress that has been made there.</p>
              </section>
              <section>
                <header>
                  <h5>Forester</h5>
                </header>
                <p><a href="https://tarides.org/">Tarides</a> are funding some work on <a href="https://patrick.sirref.org/forester/">forester</a>. This site uses <a href="https://patrick.sirref.org/forester/">forester</a> by way of <a href="https://patrick.sirref.org/graft/">graft</a> and I have spent some time working on these tools during the fellowship.</p>
                <p>This includes a <code>bytesrw</code>-based <a href="https://patrick.sirref.org/bib/">bibtex</a> library in OCaml that could be released soon.</p>
              </section>
              <section>
                <header>
                  <h5>Papers</h5>
                </header>
                <p>I had the great fortune of attending <a href="https://patrick.sirref.org/ifcp-2025/">ICFP</a> where I presented two talks and was co-author on a few others too.</p>
                <hr />
                <section>
                  <header>
                    <h6>Functional Networking for Millions of Docker Desktops (Experience Report)</h6>
                  </header>
                  <section>
                    <header>
                      <h6>Abstract</h6>
                    </header>
                    <p>
	Docker is a developer tool used by millions of developers to build, share
	and run software stacks. The Docker Desktop clients for Mac and Windows
	have long used a novel combination of virtualisation and OCaml unikernels
	to seamlessly run Linux containers on these non-Linux hosts.

	We reflect on a decade of shipping this functional OCaml code into
	production across hundreds of millions of developer desktops, and discuss
	the lessons learnt from our experiences in integrating OCaml deeply into
	the container architecture that now drives much of the global cloud. We
	conclude by observing just how good a fit for systems programming that the
	unikernel approach has been, particularly when combined with the OCaml
	module and type system.
</p>
                  </section>
                </section>
                <section>
                  <header>
                    <h6>What we talk about when we talk about scientific programming</h6>
                  </header>
                  <section>
                    <header>
                      <h6>Abstract</h6>
                    </header>
                    <p>
	Programming for the planet undoubtedly involves programming
	scientifically, but what kind of programming are we talking about
	and what makes it scientific? In what ways does it differ from
	other forms of programming, if at all? Is scientific programming,
	data science or machine learning fundamentally different to
	constructing a compiler or building a high-throughput web server?
	By considering how the scientific method (with its falsifiable
	hypotheses and repeatable and reproducible experiments) relates to
	scientific programming, I hope to explore how computer science and
	traditional programming techniques are coming up short in meeting
	the requirements of scientific programmers.
</p>
                  </section>
                </section>
                <section>
                  <header>
                    <h6>Generating a corpus of Hazel programs from ill-typed OCaml programs</h6>
                  </header>
                  <section>
                    <header>
                      <h6>Abstract</h6>
                    </header>
                    <p>
		When developing a new programming language, having a large corpus of
		both correct and incorrect programs allows language designers to test
		and explore the capabilities of their new language. However,
		bootstrapping such a corpus of incorrect programs is time-consuming and
		arduous. We therefore explore how to reuse code from more mature
		languages to generate a corpus of ill-typed code for newer ones. We
		have developed a compiler to Hazel, an emerging language with typed
		holes, from the more mature OCaml ecosystem. We find it practical to
		generate a comprehensive corpus of ill-typed programs for Hazel
		development, and discuss future larger scale efforts towards bridging
		ecosystems.
</p>
                  </section>
                </section>
                <p>See also <a href="https://patricoferris.github.io/hazel_of_ocaml/">the online hazel of ocaml compiler</a></p>
                <section>
                  <header>
                    <h6>Decomposable Type Highlighting for Bidirectional Type and Cast Systems</h6>
                  </header>
                  <section>
                    <header>
                      <h6>Abstract</h6>
                    </header>
                    <p>
		 We explore how to provide programmers with an interactive
		 interface for explaining the process by which static types and
		 dynamic casts are derived, with the goal of improving the
		 debugging of static and dynamic type errors. To this end, we
		 define mathematical foundations for a decomposable highlighting
		 system within a bidirectional system, and show how these can be
		 propagated through dynamic types in a cast system. Our prototype
		 implementation in the gradually typed Hazel language includes a
		 web-based user interface, through which we highlight the
		 importance of type level debugging.
</p>
                  </section>
                </section>
                <section>
                  <header>
                    <h6>Yirgacheffe: A Declarative Approach to Geospatial Data</h6>
                  </header>
                  <section>
                    <header>
                      <h6>Abstract</h6>
                    </header>
                    <p>
		We present Yirgacheffe, a declarative geospatial library that
		allows spatial algorithms to be implemented concisely, supports
		parallel execution, and avoids common errors by automatically
		handling data (large geospatial rasters) and resources (cores,
		memory, GPUs). Our primary user domain comprises ecologists,
		where a typical problem involves cleaning messy occurrence data,
		overlaying it over tiled rasters, combining layers, and deriving
		actionable insights from the results. We describe the successes
		of this approach towards driving key pipelines related to global
		biodiversity and describe the capability gaps that remain, hoping
		to motivate more research into geospatial domain-specific
		languages.
	</p>
                  </section>
                </section>
                <hr />
                <p>I had some great conversations with <a href="https://patrick.sirref.org/kc/">KC</a> too with respect to my current research.</p>
              </section>
            </section>
            <section>
              <header>
                <h4>Future Work</h4>
              </header>
              <p>As I enter my final year of the PhD, my goal would be to try and align more of my fellowship work with my own research wherever it makes sense. This research focuses on the following hypothesis:</p>
              <blockquote>
                <p>Embedding deep provenance tracking, reversible execution and mergeable histories directly into an interactive programming environment (a POSIX-like shell) greatly decreases the gap between exploratory scientific work and reproducible, publishable results; all whilst leaving existing workflows intact and being programming language agnostic.</p>
              </blockquote>
              <p>I want to focus on building these tools using <a href="https://patrick.sirref.org/irmin/">Irmin</a>, <a href="https://patrick.sirref.org/eio/">Eio</a>, <a href="https://patrick.sirref.org/oxcaml/">OxCaml</a> etc. There are other projects I wish to continue regardless, like <a href="https://patrick.sirref.org/outreachy/">Outreachy</a>, though just as a coordinator (not a mentor).</p>
              <section>
                <header>
                  <h5>Overlapping PhD Work</h5>
                </header>
                <p>There are multiple projects that overlap with my work. For example, <a href="https://patrick.sirref.org/irmin/">Irmin</a>, which I wrote a <a href="https://patrick.sirref.org/irmin-retro/">retrospective</a> for. This is at the core of <a href="https://patrick.sirref.org/shelter/">Shelter</a> and suggests an extremely valid use case for a brancheable, mergeable database.</p>
                <p>In addition to this, continuing to work on <a href="https://patrick.sirref.org/eio/">Eio</a> makes sense to me too. <a href="https://patrick.sirref.org/eio/">Eio</a> currently has no maintainer and no active development, but the <a href="https://github.com/ocaml-multicore/eio/issues">issues are piling up</a>. In particular, I am making heavy use of <a href="https://patrick.sirref.org/eio/">Eio</a> in <a href="https://patrick.sirref.org/merry/">Merry</a>, a POSIX(ish) shell written in OCaml. Aside from research angles on brancheable and mergeable shells, I am also quite interested in how this might look in terms of OxCaml. I met with <a href="https://patrick.sirref.org/anilmadhavapeddy/">Anil</a> and <a href="https://patrick.sirref.org/talex5/">Thomas</a> recently to discuss the future of <a href="https://patrick.sirref.org/eio/">Eio</a> and there was some agreement that we are all heavy users of it and hope to keep up its maintenance and set of features.</p>
                <p>One large piece of work that is sorely needed here is moving <a href="https://patrick.sirref.org/eio/">Eio</a> to <code>bytes</code> and not bigarray-backed <code>Cstruct</code>s. Any libraries using <code>bytesrw</code> (e.g. <code>jsont</code>) incur an extra copy of data into and out of the bytes. <a href="https://patrick.sirref.org/anilmadhavapeddy/">Anil</a> has been <a href="https://anil.recoil.org/notes/oxcaml-httpz">working on some of the pieces</a> recently to make this better!</p>
              </section>
              <section>
                <header>
                  <h5>Maintaining and Releasing my own libraries</h5>
                </header>
                <p>I have published quite a few OCaml libraries in my time, below is just a few libraries (filtered to not include OCurrent projects).</p>
                <pre><![CDATA[$ opam list --all --no-switch --columns=name,authors: | grep -E "sirref|Ferris" | cut -d " " -f1
carbon
geojson
geojsone
graft
hilite
ISO3166
jekyll-format
ppx_deriving_ezjsonm
ppx_deriving_yaml
rtree
search
topojson
topojsone
cid
multibase
multicodec
multihash
multihash-digestif]]></pre>
                <p>Some of these are used in the community including <code>hilite</code>, <code>ppx_deriving_yaml</code> and the multi-codecs. I would like to do some general maintenance of some of these tools and release a few iterations of <a href="https://patrick.sirref.org/graft/">graft</a> which now makes use of <a href="https://patrick.sirref.org/bib/">bib</a>.</p>
              </section>
              <section>
                <header>
                  <h5>Ppxlib Maintenance</h5>
                </header>
                <p>By far, maintenance of <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> takes up a majority of my time. I think, given the other work I need to focus on, it would be great to try to minimise the amount of time working on <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a>. In particular, perhaps only maintaining <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> as far as OCaml release-readiness is a possibility and important bug fixes (like <a href="https://github.com/ocaml-ppx/ppxlib/pull/613">the OOM bug reported by Jane Street</a>).</p>
              </section>
              <section>
                <header>
                  <h5>Forester, Graft and Writing</h5>
                </header>
                <p>With all of this work, I am eager to communicate what I am up to and my thoughts on open source, OCaml, OxCaml etc. I am glad to be using <a href="https://patrick.sirref.org/forester/">Forester</a> to do this, particularly as it is written in OCaml (and could make great use of my own work on <a href="https://patrick.sirref.org/eio/">Eio</a>).</p>
                <p>I hope to continue working on <a href="https://patrick.sirref.org/graft/">Graft</a> and related tools like <a href="https://patrick.sirref.org/bib/">bib</a>. But I would also like to start writing some long-form content similar to the <a href="https://patrick.sirref.org/irmin-retro/">Irmin retrospective</a>.</p>
              </section>
            </section>
          </section>
        </section>
      </div>
    </content>
  </entry>
  <entry>
    <title>OCaml Roundup: March 2026</title>
    <published>2026-03-10T00:00:00-00:00</published>
    <updated>2026-03-10T00:00:00-00:00</updated>
    <author>
      <name>https://patrick.sirref.org/Patrick Ferris/</name>
      <uri>https://patrick.sirref.org/Patrick%20Ferris/</uri>
    </author>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/ocaml-roundup-march-2026/" />
    <id>https://patrick.sirref.org/ocaml-roundup-march-2026/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <section>
          <header>
            <h2>A POSIX Shell in OCaml</h2>
          </header>
          <p>Long time, no weekly. Since the start of this year I have been building a POSIX shell in OCaml called <code>msh</code> (with the underlying library called <code>Merry</code>). <a href="https://patrick.sirref.org/merry/">Merry</a> is available online now.</p>
          <section>
            <header>
              <h3>A POSIX(ish) shell in OCaml</h3>
            </header>
            <p><a href="https://patrick.sirref.org/merry/">Merry</a> is a POSIX(ish) in OCaml. It uses  <a href="https://patrick.sirref.org/eio/">Eio</a> alongside <a href="github.com/colis-anr/morbig">Morbig</a> (a static parser for POSIX shell).</p>
            <section>
              <header>
                <h4>Why another (POSIX) shell?</h4>
              </header>
              <p>Shells have been around for a long time. In my research on the notion of <em>metashell</em> I wrote about Louis Pouzin originally coining the term:</p>
              <section>
                <header>
                  <h5>Louis Pouzin's "SHELL" </h5>
                </header>
                <p>I spent some time reading <a href="https://patrick.sirref.org/pouzin-shell-2013/">part of the multics design documentation</a> this week. Louis Pouzin coined the term "SHELL" in this document, and I was reminded yet again just how important it is to be a good writer even as a "computer science researcher". For example, this excerpt from the requirements section of the document</p>
                <blockquote>
                  <p>The previous definitions imply that a command MUST be designed while keeping in mind the user, sitting at his console, wondering about what might be going on, mistyping or forgetting arguments, even if fully aware of the conventions, and possibly interfering with the command by hasty quits, carriage returns, and other temperamental reactions.</p>
                </blockquote>
                <p>And then later, when defining the "SHELL".</p>
                <blockquote>
                  <p>We may envision a common procedure called automatically by the supervisor whenever a user types in some message at his console, at a time when he has no other process in active execution under console control (presently called command level). This procedure acts as an interface between console messages and subroutine. The purpose of such a procedure is to create a medium of exchange into which one could activate any procedure, <em>inside of another program if it were called</em>. Hereafter, for simplification, we shall refer to that procedure as the "SHELL".</p>
                </blockquote>
                <p>It still surprises how little the undergraduate degree in computer science at <a href="https://patrick.sirref.org/ucam/">Cambridge</a> focuses on writing skills.</p>
              </section>
              <p>I built <a href="https://patrick.sirref.org/shelter/">Shelter</a> exploring the idea of a shell-like interface that allowed users to <em>undo</em> their shell actions (amongst other cool tricks). Unfortunately <em>shell-like</em> is not enough. <a href="https://patrick.sirref.org/shelter/">Shelter</a> cut many corners to masquerade as a shell (e.g. appending <code>env</code> to understand how a command may have altered the execution environment). I felt it was necessary to make <a href="https://patrick.sirref.org/shelter/">Shelter</a> a "SHELL"! To do that, I needed a solid foundation to build on.</p>
              <p><code>msh</code>, the POSIX shell that comes with <a href="https://patrick.sirref.org/merry/">Merry</a>, is by no means POSIX-complete in terms of features. But it is my <a href="https://github.com/patricoferris/nixos/blob/e0faf870f76710d4a75ace775f333c88f1321c5a/modules/default.nix#L59">daily driver at this point</a>. It includes a pure OCaml rewrite of <a href="github.com/antirez/linenoise">linenoise</a> (a small, self-contained alternative to the venerable <code>readline</code>) called <a href="https://tangled.org/patrick.sirref.org/bruit">bruit</a>.</p>
              <p>If you have <code>docker</code> installed on your machine, you can take it for a spin today:</p>
              <pre><![CDATA[docker run -it --rm patrickferris/msh]]></pre>
              <p>The <code>patrickferris/msh</code> docker image is just for trying it out. It is based on the OCaml 5.3 alpine image.</p>
              <p>Alternatively, you can build <code>msh</code> from source and have it available in your opam switch.</p>
              <pre><![CDATA[opam pin git+https://tangled.org/patrick.sirref.org/merry]]></pre>
              <p>There are many small paper cuts left to patch over, but most of it is porcelain (e.g. <code>ctrl+left-arrow</code> for moving in <a href="https://tangled.org/patrick.sirref.org/bruit">bruit</a>). Unfortunately, these are the kinds of things that you will <em>immediately</em> stumble upon.</p>
            </section>
            <section>
              <header>
                <h4>What makes Merry different?</h4>
              </header>
              <p>Nothing.</p>
              <p><a href="https://patrick.sirref.org/merry/">Merry</a> is supposed to be a solid, POSIX-ish base to build on. Unfortunaltely, as it turns out, the subset of features from the POSIX specification that people <em>actually use</em>... is pretty much all of it. Every possible redirection, variable expansion, shell built-in and compound command make some appearance. Not to mention the non-POSIX bits of shell we all take for granted (e.g. <code>&amp;&gt;</code>-redirection).</p>
              <p><a href="https://patrick.sirref.org/merry/">Merry</a> and <code>msh</code> are useable. You will most likely find bugs if you use them. If, when using <code>msh</code>, you find something obscure happening you can enable debug mode either my setting the variable <code>MSH_DEBUG</code> or by invoking <code>msh</code> with <code>-v -v</code>.</p>
            </section>
            <section>
              <header>
                <h4>What's next?</h4>
              </header>
              <p>It is soon time to combine <a href="https://patrick.sirref.org/shelter/">Shelter</a> and <a href="https://patrick.sirref.org/merry/">Merry</a> into the time-travelling, POSIX-ish shell that I have been trying to build since I first started working on <a href="https://patrick.sirref.org/shelter/">Shelter</a>.</p>
              <p>For this to be successful, I need <a href="https://patrick.sirref.org/merry/">Merry</a> to be able to pass plenty of tests and right now that involves trying to install plenty of packages using tools like <code>apk</code> and <code>apt</code>.</p>
              <section>
                <header>
                  <h5>Shell MRDT</h5>
                </header>
                <p>What I am particularly interested in reasoning about, is the <a href="https://tangled.org/patrick.sirref.org/merry/blob/main/src/lib/eval.ml#L22">execution context</a> in <a href="https://patrick.sirref.org/merry/">Merry</a>. This value, alongside the file-system, constitutes a fairly deep understanding of the state that changes in each step of a shell's evaluation loop.</p>
                <p>This was, in terms of <a href="https://patrick.sirref.org/shelter/">Shelter</a>, the missing piece for truly building some kind of <a href="https://patrick.sirref.org/mrdts/">MRDT</a> across shell sessions.</p>
              </section>
            </section>
          </section>
          <section>
            <header>
              <h3>TIFF in OCaml</h3>
            </header>
            <p>I picked up from the excellent <a href="https://patrick.sirref.org/outreachy/">Outreachy</a> work of <a href="https://patrick.sirref.org/tambe%20salome/">Tambe Salome</a> in getting write-support in <a href="https://patrick.sirref.org/ocaml-tiff/">ocaml-tiff</a>. We are getting closer to the kind of API I envisaged in this latest round of refinement and review.</p>
            <pre class="hilite">
              <code>
                <span class="ocaml-keyword-other">let</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[(]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">/</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[)]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">Eio</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-constant-language-capital-identifier">Path</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source"><![CDATA[(]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">/</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[)]]></span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-keyword">let</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-entity-name-function-binding">checkerboard</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">~</span>
                <span class="ocaml-source">size</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">  </span>
                <span class="ocaml-keyword">let</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-entity-name-function-binding">v</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">Nx</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source">zeros</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">Nx</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source">uint8</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[[|]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">size</span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">size</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[|]]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other">in</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">  </span>
                <span class="ocaml-keyword">for</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-entity-name-function-binding">row</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-integer">0</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other">to</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">size</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">-</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-integer">1</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other">do</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">    </span>
                <span class="ocaml-keyword">for</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-entity-name-function-binding">col</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-integer">0</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other">to</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">size</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">-</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-integer">1</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other">do</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">      </span>
                <span class="ocaml-keyword-other">if</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[(]]></span>
                <span class="ocaml-source">row</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">+</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">col</span>
                <span class="ocaml-source"><![CDATA[)]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">mod</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-integer">2</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-integer">0</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other">then</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">Nx</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source">set_item</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[[]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">row</span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">col</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[]]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-integer">254</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">v</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">    </span>
                <span class="ocaml-keyword-other">done</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">  </span>
                <span class="ocaml-keyword-other">done</span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">  </span>
                <span class="ocaml-constant-language-capital-identifier">Nx</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source">to_bigarray</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">v</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-keyword-other">let</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-unit"><![CDATA[()]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">  </span>
                <span class="ocaml-constant-language-capital-identifier">Eio_posix</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source">run</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">@@</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other">fun</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">env</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">-&gt;</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">  </span>
                <span class="ocaml-constant-language-capital-identifier">Tiff_eio</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source">with_open_out</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[(]]></span>
                <span class="ocaml-source">env</span>
                <span class="ocaml-keyword-other">#</span>
                <span class="ocaml-source">cwd</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">/</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-string-quoted-double">"</span>
                <span class="ocaml-string-quoted-double">example.tiff</span>
                <span class="ocaml-string-quoted-double">"</span>
                <span class="ocaml-source"><![CDATA[)]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">@@</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other">fun</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">w</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">-&gt;</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">  </span>
                <span class="ocaml-keyword">let</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-entity-name-function-binding">tif</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">Tiff</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source">make</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[(]]></span>
                <span class="ocaml-source">checkerboard</span>
                <span class="ocaml-source"> ~</span>
                <span class="ocaml-source">size</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-constant-numeric-decimal-integer">256</span>
                <span class="ocaml-source"><![CDATA[)]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other">in</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">  </span>
                <span class="ocaml-constant-language-capital-identifier">Tiff</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source">to_file</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">tif</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">w</span>
                <span class="ocaml-source">
</span>
              </code>
            </pre>
            <img src="https://patrick.sirref.org/bafkrmiaqqczj5lemda5ijfjtjsyldbhmveu3btfvoa7rpt5k4dvdejjuhu.png" />
            <p>I have also been extremely pleased to see further external collaborators appearing:</p>
            <ul>
              <li>
                <p><a href="https://github.com/geocaml/ocaml-tiff/pull/63">Nicolas</a> helping out with metadata maintainence.</p>
              </li>
              <li>
                <p><a href="https://github.com/geocaml/ocaml-tiff/pull/62">Virgile</a> adding support for reading multi-image TIFF files.</p>
              </li>
            </ul>
          </section>
        </section>
        <section>
          <header>
            <h2>Ppxlib release and Merry updates</h2>
          </header>
          <section>
            <header>
              <h3>0.38.0 </h3>
            </header>
            <p><a href="https://patrick.sirref.org/nathanreb/">Nathan</a> and I <a href="https://github.com/ocaml/opam-repository/pull/29563">released ppxlib.0.38.0</a> last week. Its main feature is full <em>migration</em> support for the upcoming OCaml 5.5 compiler (currently in its <code>alpha3</code> release). This means supporting the handful of new features landing in OCaml 5.5: <a href="https://patrick.sirref.org/modular-explicits/">modular explicits</a>, external type declarations and arbitrary "local" structure items.</p>
            <p>As <a href="https://patrick.sirref.org/nathenreb/">Nathan</a> and I continue to find a plausible maintenance story for <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a>, <a href="https://patrick.sirref.org/nathenreb/">Nathan</a> has opened <a href="https://github.com/ocaml/ocaml/issues/14668">an issue on the OCaml compiler to discuss the idea of adding additional extension points to the language</a>.</p>
            <p>This comes from the desire to be able to store encoded versions of new OCaml features inside older abstract syntax trees.</p>
            <p>There are also some nice bug fixes in there too:</p>
            <ul>
              <li>
                <p><a href="https://github.com/ocaml-ppx/ppxlib/pull/613">A potential OOM</a> loop has now been removed.</p>
              </li>
              <li>
                <p>
                  <a href="https://github.com/ocaml-ppx/ppxlib/pull/619">Locations have been restored to long identifiers!</a>
                </p>
              </li>
            </ul>
          </section>
          <section>
            <header>
              <h3>Merry updates</h3>
            </header>
            <p>It turns out writing a POSIX(ish) shell is hard; at least, there is a vast number of slightly obscure features that one needs to support. I think this is surprising because most people writing shell scripts write simple shell scripts; scripts that use a much smaller subset of features. In the same breath, those same developers are likely to use something like <code>apt-get install bash</code> which runs a plethora of more advanced (and non-POSIX) shell scripts!</p>
            <section>
              <header>
                <h4>Exec redirects</h4>
              </header>
              <p>In a shell script, you can use the built-in command <code>exec</code> to replace the current process with a new one (e.g. <code>exec vim</code>). However, there is a <a href="https://pubs.opengroup.org/onlinepubs/9799919799/utilities/V3_chap02.html#tag_19_21"><em>different</em> mode of operation</a> for <code>exec</code>:</p>
              <blockquote>
                <p>If exec is specified with no operands, any redirections associated with the exec command shall be made in the current shell execution environment.</p>
              </blockquote>
              <p>One of my litmus tests for <a href="https://patrick.sirref.org/merry/">Merry</a> is the <a href="https://wiki.debian.org/Debootstrap">Debian debootstrap scripts</a> (h/t <a href="https://patrick.sirref.org/anilmadhavapeddy/">Anil</a>). One thing that it does is the following:</p>
              <pre class="hilite">
                <code>
                  <span class="sh-entity-name-function">err</span>
                  <span class="sh-meta-function"> </span>
                  <span class="sh-punctuation-definition-arguments"><![CDATA[()]]></span>
                  <span class="sh-meta-function"> </span>
                  <span class="sh-punctuation-definition-group"><![CDATA[{]]></span>
                  <span class="sh-meta-scope-group">
</span>
                  <span class="sh-meta-scope-group">  </span>
                  <span class="sh-support-function-builtin">printf</span>
                  <span class="sh-meta-scope-group"> </span>
                  <span class="sh-punctuation-definition-string-begin">"</span>
                  <span class="sh-string-quoted-double">err </span>
                  <span class="sh-punctuation-definition-variable">$</span>
                  <span class="sh-variable-other-positional">1</span>
                  <span class="sh-punctuation-definition-string-end">"</span>
                  <span class="sh-meta-scope-group"> </span>
                  <span class="sh-keyword-operator-redirect">&gt;&amp;4</span>
                  <span class="sh-meta-scope-group">
</span>
                  <span class="sh-punctuation-definition-group"><![CDATA[}]]></span>
                  <span class="sh-punctuation-definition-function">
</span>
                  <span class="sh-source">
</span>
                  <span class="sh-support-function-builtin">exec</span>
                  <span class="sh-source"> </span>
                  <span class="sh-keyword-operator-redirect">4&gt;&amp;1</span>
                  <span class="sh-source"> 
</span>
                </code>
              </pre>
              <p>A lot of detail has been elided for clarity. <code>exec 4&gt;&amp;1</code> sets up a redirection for the shell's execution environment in which file descriptor <code>4</code> is now an alias for standard output. So, writing to <code>4</code> (by redirecting a command's standard output to <code>4</code> i.e. <code>&gt;&amp;4</code>) will output to where standard output is going (most likely the terminal).</p>
              <p>For this to work, shell's must <a href="https://www.man7.org/linux/man-pages/man2/dup.2.html"><code>dup2</code></a> the relevant file descriptors which have the following condition:</p>
              <blockquote>
                <p>If the file descriptor newfd was previously open, it is closed before being reused; the close is performed silently (i.e., any errors during the close are not reported by dup2()).</p>
              </blockquote>
              <p>This is all very well, unless your program has an important file already open that happens to have file descriptor <code>4</code>. The <a href="https://patrick.sirref.org/eio/">Eio</a> Linux and POSIX backends suffer from this problem. Both make use of a file-based synchronisation mechanism for waking up the eventloop should another domain push a completion to the scheduler's run queue. On Linux this is <a href="https://github.com/ocaml-multicore/eio/blob/c44ee5ce96c120b7ccc23a12d241dc8672e2888f/lib_eio_linux/sched.ml#L501">via an eventfd</a> and in <a href="https://github.com/ocaml-multicore/eio/blob/c44ee5ce96c120b7ccc23a12d241dc8672e2888f/lib_eio_posix/sched.ml#L20">POSIX, a pipe</a>.</p>
              <p>This <code>dup2</code> will close the <code>eventfd</code> and will likely grind Eio to a halt (or an <code>assert false</code>). For now, I have resorted to vendoring <a href="https://patrick.sirref.org/eio/">Eio</a> and moving the <code>eventfd</code> file descriptors to higher values, though I <a href="https://github.com/ocaml-multicore/eio/pull/836">have opened a PR to make this more configurable</a>. This bug is quite easy to write up... it was not so easy to find!</p>
              <p>As a random example, consider the <code>debconf/confmodule</code> <a href="https://sources.debian.org/src/debconf/1.5.77/confmodule/">script</a> which offers very little room for a buggy implementation!</p>
            </section>
          </section>
          <section>
            <header>
              <h3>Outreachy</h3>
            </header>
            <p>The presentations from the demonstrations for this round of Outreachy are now online!</p>
            <section>
              <header>
                <h4>Write support in OCaml TIFF library</h4>
              </header>
              <p>I am mentoring <a href="https://patrick.sirref.org/tambe-salome/">Tambe Salome</a> during the December 2025 Outreachy round to add support for writing TIFF files in the <a href="https://patrick.sirref.org/ocaml-tiff/">ocaml-tiff</a> library.</p>
              <p>You can now see the video of the demonstration day presentation:</p>
              <div style="text-align: center">
<iframe title="Outreachy Demo Day December 2025 Round" width="560" height="315" src="https://watch.ocaml.org/videos/embed/8aUqMhFvhQGq4WJLH3ukjA?start=1h18m33s" frameborder="0" allowfullscreen="" sandbox="allow-same-origin allow-scripts allow-popups allow-forms" />
</div>
            </section>
          </section>
        </section>
        <section>
          <header>
            <h2>Forking in Shells &amp; Library Maintenance</h2>
          </header>
          <p>This week, <a href="https://patrick.sirref.org/merry/">Merry</a> got close to executing <code>apt-get install ca-certificates</code> and running Debian's <code>debootstrap</code> scripts correctly. <a href="https://patrick.sirref.org/nathan/">Nathan</a> and I released <a href="https://patrick.sirref.org/ppxlib/">Ppxlib</a> <code>0.38.0</code>, I added support to <a href="https://github.com/geocaml/ocaml-proj">ocaml-proj</a> for compiling to the browser and I fixed a long-standing bug in <a href="https://github.com/patricoferris/hilite">hilite</a>.</p>
          <section>
            <header>
              <h3>Forking in Merry</h3>
            </header>
            <p>So far, <a href="https://patrick.sirref.org/merry/">Merry</a> has managed to support many features of the POSIX shell specification without needing to do a <code>fork(2)</code> without an <code>exec</code>. Or, to put it another way, all the forking that <a href="https://patrick.sirref.org/merry/">Merry</a> does, will only be followed by running C code. This is actually a feature of <a href="https://patrick.sirref.org/eio/">Eio</a>'s <code>Process</code> API. It is required to make process execution safe in the context of multiple domains in OCaml (mostly due to ensuring consistency within the garbage collector). However, it is perfectly okay to <code>fork</code> and run OCaml code provided there is only a single domain.</p>
            <p>In a shell, many features of the shell language require that commands (or built-ins, function applications etc.) execute within a <code>subshell</code>. The specification does not go into detail about how shells should implement this, but many choose to <code>fork</code> in order to preserve some state in the parent (for example, the file descriptor table). Some shells try to minimise the number of forks as an optimisation. The <a href="https://patrick.sirref.org/korn1996korn/">korn shell (ksh)</a> is one such shell.</p>
            <blockquote>
              <p>Using the notation <code>$(command)</code> will cause <code>command</code> to execute in a subshell of the current ksh. In many instances, ksh will not actually fork/exec a subshell when command is a built-in or a shell function.</p>
            </blockquote>
            <p>By trying to adhere to Multicore OCaml's "<em>thou shalt not fork</em>" commandment, <a href="https://patrick.sirref.org/merry/">Merry</a> is much more similar to <code>ksh</code> in this regard. However, whenever there is an interaction with a shell built-in and semantics that need a child process, things get tricky very quickly. Consider the following:</p>
            <pre class="hilite">
              <code>
                <span class="sh-keyword-control">while</span>
                <span class="sh-meta-scope-while-loop"> </span>
                <span class="sh-support-function-builtin">echo</span>
                <span class="sh-meta-scope-while-loop"> </span>
                <span class="sh-punctuation-definition-string-begin">"</span>
                <span class="sh-string-quoted-double">hello</span>
                <span class="sh-punctuation-definition-string-end">"</span>
                <span class="sh-keyword-operator-list">;</span>
                <span class="sh-meta-scope-while-loop"> </span>
                <span class="sh-keyword-control">do</span>
                <span class="sh-meta-scope-while-loop">
</span>
                <span class="sh-meta-scope-while-loop">  </span>
                <span class="sh-support-function-builtin">:</span>
                <span class="sh-meta-scope-while-loop">
</span>
                <span class="sh-keyword-control">done</span>
                <span class="sh-source"> </span>
                <span class="sh-keyword-operator-pipe">|</span>
                <span class="sh-source"> head -n 3
</span>
              </code>
            </pre>
            <p>We have a mix of shell built-ins, normal commands, a compound command (the <code>while</code> loop) and a pipeline. Each individual command in the pipeline requires you to run them in a subshell and set them up <em>before</em> executing them. Without a <code>fork</code> for that first command, you may end up looping forever which is not the intended behaviour here. I had a good conversation with <a href="https://patrick.sirref.org/mdales/">Michael</a> about the implications of this for reproducibility.</p>
            <p>For now, I have started implementing a <code>fork</code> for some of the shell features whilst still trying to maintain the functional core of the implementation.</p>
          </section>
          <section>
            <header>
              <h3>An OCaml 5.5 compatible Ppxlib</h3>
            </header>
            <p><a href="https://patrick.sirref.org/nathanreb/">Nathan</a> and I released an OCaml 5.5 compatible version of <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a>.</p>
            <section>
              <header>
                <h4>0.38.0 </h4>
              </header>
              <p><a href="https://patrick.sirref.org/nathanreb/">Nathan</a> and I <a href="https://github.com/ocaml/opam-repository/pull/29563">released ppxlib.0.38.0</a> last week. Its main feature is full <em>migration</em> support for the upcoming OCaml 5.5 compiler (currently in its <code>alpha3</code> release). This means supporting the handful of new features landing in OCaml 5.5: <a href="https://patrick.sirref.org/modular-explicits/">modular explicits</a>, external type declarations and arbitrary "local" structure items.</p>
              <p>As <a href="https://patrick.sirref.org/nathenreb/">Nathan</a> and I continue to find a plausible maintenance story for <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a>, <a href="https://patrick.sirref.org/nathenreb/">Nathan</a> has opened <a href="https://github.com/ocaml/ocaml/issues/14668">an issue on the OCaml compiler to discuss the idea of adding additional extension points to the language</a>.</p>
              <p>This comes from the desire to be able to store encoded versions of new OCaml features inside older abstract syntax trees.</p>
              <p>There are also some nice bug fixes in there too:</p>
              <ul>
                <li>
                  <p><a href="https://github.com/ocaml-ppx/ppxlib/pull/613">A potential OOM</a> loop has now been removed.</p>
                </li>
                <li>
                  <p>
                    <a href="https://github.com/ocaml-ppx/ppxlib/pull/619">Locations have been restored to long identifiers!</a>
                  </p>
                </li>
              </ul>
            </section>
          </section>
          <section>
            <header>
              <h3>Browser support for ocaml-proj</h3>
            </header>
            <p>A while ago <a href="https://github.com/geocaml/ocaml-proj">I built some "modern" bindings to PROJ4 in OCaml</a>. After reading <a href="https://patrick.sirref.org/jonludlam/">Jon Ludlam</a>'s <a href="https://jon.recoil.org/blog/2026/03/weeknotes-2026-12.html">weeknotes</a> (and speaking with him and <a href="https://patrick.sirref.org/anilmadhavapeddy/">Anil</a>, I thought it might be nice to add a Javascript backend to those bindings). This was relatively straight-forward using <a href="https://dune.readthedocs.io/en/stable/virtual-libraries.html">Dune's virtual libraries</a> and is <a href="https://github.com/geocaml/ocaml-proj/blob/main/src/js/proj.ml">available on Github</a>.</p>
            <p>With virtual libraries, your own data analysis could (if you wished) depend solely on the <code>proj</code> library and later choose to either link it with <code>proj.c</code> or <code>proj.js</code> depending on where the analysis is being deployed.</p>
            <p>I briefly looked at WASM support, but quickly realised there was not much appetite for it and trying to compile around the C FFI was going to be hard.</p>
          </section>
          <section>
            <header>
              <h3>Hilite updates</h3>
            </header>
            <p>Since I helped <a href="https://ocaml.org/">relaunch the ocaml.org</a> website a few years ago, I have maintained <a href="https://github.com/patricoferris/hilite">hilite</a>, a tool for doing build-time syntax highligting.</p>
            <p>It is being used on the <a href="https://ocaml.org/">ocaml.org</a> website, <a href="https://github.com/xhtmlboi/yocaml/blob/45858f4b25730149dae3735e7fcdb9111ac1f9eb/yocaml_markdown.opam#L18">in yocaml_markdown</a> and also in <a href="https://patrick.sirref.org/mdales/">Michael's</a> <a href="https://github.com/mdales/webplats/blob/cf0ea95a66bae52f02a00739eb02564fc94183ee/webplats.opam#L19">webplats</a> (when it works...).</p>
            <p>And it was <a href="https://patrick.sirref.org/mdales/">Michael</a> who led me to finally fixing and adding syntax highlighting support for Python and Go. Once I was on this roll, I finally took a look at fixing the long-standing bug of trying to highlight ocaml-mdx code, like the following:</p>
            <pre class="hilite">
              <code>
                <span class="ocaml-mdx-hash">#</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-float">50.123</span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-mdx-hash">#</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-integer">1</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-string-quoted-double">"</span>
                <span class="ocaml-string-quoted-double">file.ml</span>
                <span class="ocaml-string-quoted-double">"</span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source">
</span>
              </code>
            </pre>
            <p>In fact, this code now highlights fine, but was the source of the bug. The syntax highlighting grammer confuses the ocaml-mdx <code>#</code> as a toplevel directive and trouble ensues.</p>
          </section>
        </section>
      </div>
    </content>
  </entry>
  <entry>
    <title>OCaml Roundup: January 2026</title>
    <published>2026-02-05T00:00:00-00:00</published>
    <updated>2026-02-05T00:00:00-00:00</updated>
    <author>
      <name>https://patrick.sirref.org/Patrick Ferris/</name>
      <uri>https://patrick.sirref.org/Patrick%20Ferris/</uri>
    </author>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/ocaml-roundup-january-2026/" />
    <id>https://patrick.sirref.org/ocaml-roundup-january-2026/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>A new year, another roundup in my open-source, OCaml activities. This month has been busy with lots of work on <a href="https://patrick.sirref.org/ocaml-tiff/">ocaml-tiff</a> thanks to <a href="https://patrick.sirref.org/tambe%20salome/">Tambe Salome</a> and <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a>.</p>
        <section>
          <header>
            <h2>Outreachy</h2>
          </header>
          <p><a href="https://patrick.sirref.org/tambe%20salome/">Tambe Salome</a> has been working to add write support to <a href="https://patrick.sirref.org/ocaml-tiff/">ocaml-tiff</a>; and we are well on the way to having good support. Writing TIFF files is no easy business. Unlike many formats, TIFF files have an internal metadata-data split, with values sometimes being place nowhere near the metadata describing the values in the file. In practice, it means if you do not wish to read the whole file into memory, then your IO layer must support seeking to file offsets. This means when you come to <em>write</em> the file, you might need to write at different offsets too.</p>
          <p>This becomes particularly complicated when you do not know ahead of time how you are going to layout the file (e.g. how many strips will the raw data be separated into). For now, we are doing the sane first step and assuming we are copying a TIFF file we have access to but pushing all the copying via the OCaml values we read from our source TIFF. And <a href="https://patrick.sirref.org/tambe-salome/">Salome</a> has made excellent progress:</p>
          <pre><![CDATA[$ exiftool test/data/uniform.tiff > input.exif
$ dune exec -- example/copy.exe test/data/uniform.tiff example.tiff
$ exiftool example.tiff > output.exif
$ patdiff input.exif output.exif
------ input.exif
++++++ output.exif
@|-1,23 +1,23 ============================================================
 |ExifTool Version Number         : 13.39
-|File Size                       : 66 kB
+|File Size                       : 118 bytes
 |File Permissions                : -rw-r--r--
 |File Type                       : TIFF
 |File Type Extension             : tif
 |MIME Type                       : image/tiff
 |Exif Byte Order                 : Little-endian (Intel, II)
 |Image Width                     : 256
 |Image Height                    : 256
 |Bits Per Sample                 : 8
 |Compression                     : Uncompressed
 |Photometric Interpretation      : BlackIsZero
 |Strip Offsets                   : 122
 |Rows Per Strip                  : 256
 |Strip Byte Counts               : 65536
 |Planar Configuration            : Chunky
 |Image Size                      : 256x256
 |Megapixels                      : 0.066]]></pre>
          <p>From this slightly edited output, we can see that the OCaml libary is doing a good job at preserving the metadata. The file size discrepancy is because we have not tackled writing the raw data to the file yet! This is next on our TODOs, write data to a file given a strip-offset plan. Once we do that we can then start to think how might we come up with such a plan if we did not have one.</p>
        </section>
        <section>
          <header>
            <h2>Ppxlib</h2>
          </header>
          <p>The first cut of <a href="https://patrick.sirref.org/ocaml%205.5">OCaml 5.5</a> is not too far away, at which point the Parsetree will be frozen. Unfortunately (for <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> maintainers), a handful of new features sneaked into this release including: modular explicits, external type declarations and the <a href="https://patrick.sirref.org/ocaml-roundup-december-2025/">previously mentioned</a> local structure items.</p>
          <p>All of these features require migrations to support newer compilers. In this migration process, <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> lowers modern ASTs to the AST of OCaml 5.2. New AST nodes (or new items of exisiting AST nodes) must be encoded to survive the migration process. We have a few PRs to support 5.5 fully:</p>
          <ul>
            <li>
              <p><a href="https://github.com/ocaml-ppx/ppxlib/pull/606">The initial PR to support 5.5</a>.</p>
            </li>
            <li>
              <p><a href="https://github.com/ocaml-ppx/ppxlib/pull/621">Supporting all the new local structure items</a>.</p>
            </li>
            <li>
              <p><a href="https://github.com/ocaml-ppx/ppxlib/pull/622">Full support for modular explicits and external type declarations</a>.</p>
            </li>
          </ul>
          <p>Additionally, <a href="https://patrick.sirref.org/nathanreb/">Nathan</a> has been adding better feature encoding support for the 5.3 and 5.4. Unlike the migration code above, these also include <code>Ast_builder</code> and <code>Ast_pattern</code> functions for building and matching on the new AST nodes. This allows ppx authors to <em>use</em> those nodes in their ppxes.</p>
          <ul>
            <li>
              <p><a href="https://github.com/ocaml-ppx/ppxlib/pull/624">OCaml 5.3 effect syntax</a>.</p>
            </li>
            <li>
              <p><a href="https://github.com/ocaml-ppx/ppxlib/pull/607">OCaml 5.4 labeled tuples</a>.</p>
            </li>
          </ul>
          <p>Finally, we have an important bug fix where long identifiers were given a <code>Location.none</code>. Unfortunately, it is not possible to fully recover a long identifier's location because of the possibility of whitespaces (e.g. <code>Foo (M).t</code> is valid). <a href="https://github.com/ocaml-ppx/ppxlib/pull/619">Read more about that fix here</a>.</p>
        </section>
      </div>
    </content>
  </entry>
  <entry>
    <title>OCaml Roundup: December 2025</title>
    <published>2026-01-11T00:00:00-00:00</published>
    <updated>2026-01-11T00:00:00-00:00</updated>
    <author>
      <name>https://patrick.sirref.org/Patrick Ferris/</name>
      <uri>https://patrick.sirref.org/Patrick%20Ferris/</uri>
    </author>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/ocaml-roundup-december-2025/" />
    <id>https://patrick.sirref.org/ocaml-roundup-december-2025/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>December was busy, both personally and in my OCaml-related work. If you haven't been following along have a read of my <a href="https://patrick.sirref.org/ocaml-roundup-october-2025/">October</a> and <a href="https://patrick.sirref.org/ocaml-roundup-november-2025/">November</a> roundups.</p>
        <section>
          <header>
            <h2>Outreachy December Round </h2>
          </header>
          <p>December marks the beginning of a new <a href="https://patrick.sirref.org/outreachy/">Outreachy</a> round, and I am very excited to be working with <a href="https://patrick.sirref.org/tambe-salome/">Tambe Salome</a> on improving the <a href="https://patrick.sirref.org/ocaml-tiff/">ocaml-tiff</a> library.</p>
          <p>In particular, we will be adding the ability to <em>write</em> TIFF files from raw data. I imagine an API something like:</p>
          <pre class="hilite">
            <code>
              <span class="ocaml-keyword-other">val</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">write</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-storage-type">'repr</span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-storage-type">'kind</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Tiff</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">Data</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">t</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-constant-language-capital-identifier">Tiff</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">File</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">wo</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-support-type">unit</span>
              <span class="ocaml-source">
</span>
            </code>
          </pre>
          <p>So far <a href="https://patrick.sirref.org/tambe-salome/">Salome</a> has been making excellent progress churning through some issues that are blocking us from starting the main project, including:</p>
          <ol>
            <li>
              <p><a href="https://github.com/geocaml/ocaml-tiff/pull/56">Adding a sublibrary</a> for <a href="https://patrick.sirref.org/eio/">Eio</a>.</p>
            </li>
            <li>
              <p><a href="https://github.com/geocaml/ocaml-tiff/pull/57">Using the new Nx library</a>.</p>
            </li>
            <li>
              <p>
                <a href="https://github.com/geocaml/ocaml-tiff/pull/58">Uncovering bugs in our decoding of the number of bits per pixel</a>
              </p>
            </li>
            <li>
              <p><a href="https://github.com/geocaml/ocaml-tiff/pull/59">Preliminary work on write support</a>!</p>
            </li>
          </ol>
          <p>As a community, the mentors and mentees also had a community call to introduce ourselves to eachother. I am very excited about the <a href="https://yocaml.github.io/tutorial/">Yocaml</a> project and the <em>two</em> <a href="https://raven-ml.dev/">Raven</a> projects.</p>
        </section>
        <section>
          <header>
            <h2>Ppxlib</h2>
          </header>
          <p>If you recall, I discussed the new representation for local constructs in the AST.</p>
          <section>
            <header>
              <h3>Initial OCaml 5.5 Support </h3>
            </header>
            <p>We <a href="https://github.com/ocaml-ppx/ppxlib/pull/606">recently merged 5.5 support</a> into our <code>main</code> branch (thanks to Nathan for the review). It cast a light on some new features coming to OCaml including the ability to define <em>any</em> structure <em>locally</em>. Most OCaml programmers will be familiar with things like local opens (e.g. <code>let open M in</code>). This has now been extended to include any structure item (more or less, you cannot nest value bindings).</p>
            <p><em>External</em> types have also landed, bringing with them a new "type kind" in the AST. You can <a href="https://github.com/gasche/ocaml/blob/44e69a0eb6d57ea2e7dc14c6ea4bac4a260a2d5b/manual/src/refman/extensions/externaltypes.etex">read about them in the manual</a>.</p>
          </section>
          <p>It transpires that since then, changes have landed in the compiler that mean just about <em>any</em> OCaml structure item can now be declared locally. I have documented an <a href="https://github.com/ocaml-ppx/ppxlib/issues/617">issue on ppxlib</a> about the problems this will cause for us:</p>
          <blockquote>
            <p>Currently, we only migrate the previously supported structure items that could appear in a let-binding (<code>let open</code> etc.). Now, however, the compiler allows anything to appear in a local let-binding except additional let-bindings (<code>let let ...</code>) and includes (<code>let include</code>). Whereas the previous change had a 1:1 mapping from a 5.4 AST node to a 5.5 AST node, now we do not and will need to think of a suitable encoding.</p>
          </blockquote>
          <section>
            <header>
              <h3>Migration Woes</h3>
            </header>
            <p>We had more migration woes in the form of incorrect (or missing) locations for long identifiers (thanks to <a href="https://github.com/ocaml-ppx/ppxlib/issues/618">gasche for the report</a>). Long identifiers, or <code>Longident</code>s are used in OCaml to identify values like <code>Foo.bar</code> or <code>Map.Make(String).t</code>. In OCaml 5.4, each segment of the identifier was given a precise location. This means that in the migration from 5.3 to 5.4 we have to reconstruct those locations.</p>
            <p>However, our code didn't do this, instead it simply defaulted to <code>Location.none</code> causing some imprecise error codes in preprocessed OCaml files. For example:</p>
            <pre class="hilite">
              <code>
                <span class="ocaml-keyword-other">let</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-unit"><![CDATA[()]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">NonExistingModule</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source">run</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-unit"><![CDATA[()]]></span>
                <span class="ocaml-source">
</span>
              </code>
            </pre>
            <p>Has the following error:</p>
            <pre><![CDATA[File "_none_", line 1:              
Error: Unbound module NonExistingModule]]></pre>
            <p>I have <a href="https://github.com/ocaml-ppx/ppxlib/pull/619">proposed a fix</a> which partially brings back locations during the migration. Part of the problem, I think, is that the exact location of long identifiers containing applications (like <code>Map.Make(String).t</code>) is lost. This is because there could be arbitrary white-space in the original source code (e.g. <code>Map.Make    (String).t</code>)</p>
          </section>
        </section>
      </div>
    </content>
  </entry>
  <entry>
    <title>OCaml Roundup: November 2025</title>
    <published>2025-12-09T00:00:00-00:00</published>
    <updated>2025-12-09T00:00:00-00:00</updated>
    <author>
      <name>https://patrick.sirref.org/Patrick Ferris/</name>
      <uri>https://patrick.sirref.org/Patrick%20Ferris/</uri>
    </author>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/ocaml-roundup-november-2025/" />
    <id>https://patrick.sirref.org/ocaml-roundup-november-2025/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>A roundup of <em>some</em> of my OCaml activity this month!</p>
        <section>
          <header>
            <h2>Ppxlib Updates</h2>
          </header>
          <p>I managed to get a substantial amount of ppxlib work completed in the last month. Some of those bits are described in detail below.</p>
          <section>
            <header>
              <h3>Initial OCaml 5.5 Support </h3>
            </header>
            <p>We <a href="https://github.com/ocaml-ppx/ppxlib/pull/606">recently merged 5.5 support</a> into our <code>main</code> branch (thanks to Nathan for the review). It cast a light on some new features coming to OCaml including the ability to define <em>any</em> structure <em>locally</em>. Most OCaml programmers will be familiar with things like local opens (e.g. <code>let open M in</code>). This has now been extended to include any structure item (more or less, you cannot nest value bindings).</p>
            <p><em>External</em> types have also landed, bringing with them a new "type kind" in the AST. You can <a href="https://github.com/gasche/ocaml/blob/44e69a0eb6d57ea2e7dc14c6ea4bac4a260a2d5b/manual/src/refman/extensions/externaltypes.etex">read about them in the manual</a>.</p>
          </section>
          <section>
            <header>
              <h3>Bug Fixes for Attribute Rewriters</h3>
            </header>
            <p>There <a href="https://github.com/ocaml-ppx/ppxlib/pull/613">was a bug</a> in the error handling for attribute rewriters -- a relatively new feature to have been added to ppxlib.</p>
            <p>In some places, ppxlib makes use of a <code>With_error.t</code> monad. Unlike the <code>Result.t</code> monad, <code>With_error.t</code> allows you to <em>collect</em> errors rather than find the first error and thread it through your program. This can make sense if your program can meaningfully do work after encountering an error. Unfortunately, in the logic for replacing attributes, the code could not recover from an error where there were duplicate attributes.</p>
          </section>
          <section>
            <header>
              <h3>Value binding constraints in ppxlib</h3>
            </header>
            <p>I spent a good few hours understanding why the <a href="https://github.com/mirage/repr/pull/110">CI tests in my PR to mirage/repr</a> were still failing. It turns out, the bug, is fairly simple to reproduce. Consider the following OCaml code:</p>
            <pre class="hilite">
              <code>
                <span class="ocaml-keyword">let</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-entity-name-function-binding">g</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-support-type">int</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-integer">1</span>
                <span class="ocaml-source">
</span>
              </code>
            </pre>
            <p>We have a let-binding that contains a type constraint. Where, in the abstract syntax tree sense, do we attach the constraint? Since OCaml 5.1, we have quite a few options for how this can be represented.</p>
            <p>The first is using the <code>Ppat_constraint</code> AST node which allows you to attach a type constraint to any pattern.</p>
            <pre class="hilite">
              <code>
                <span class="ocaml-source">    </span>
                <span class="ocaml-keyword-other">|</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">Ppat_constraint</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other">of</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">pattern</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">*</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">core_type</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">    </span>
                <span class="ocaml-comment-block"><![CDATA[(*]]></span>
                <span class="ocaml-comment-block"><![CDATA[ (P : T)]]></span>
                <span class="ocaml-comment-block"><![CDATA[*)]]></span>
                <span class="ocaml-source">
</span>
              </code>
            </pre>
            <p>This tends to be used for things like function arguments (e.g. <code>fun (x : int) -&gt; x + 1</code>). So it doesn't quite capture what we want for this binding constraint.</p>
            <p>On older OCaml compilers, <code>let g : int = 1</code> also includes a <code>Pexp_constraint</code> on the body of the value binding. This makes sense if we consider a more general case of the syntax where we allow functions.</p>
            <pre class="hilite">
              <code>
                <span class="ocaml-keyword">let</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-entity-name-function-binding">g</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">x</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-support-type">int</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">x</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">+</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-integer">1</span>
                <span class="ocaml-source">
</span>
              </code>
            </pre>
            <p>In this example, we no longer parse a <code>Ppat_constraint</code> and instead this is treated as syntactic sugar for:</p>
            <pre class="hilite">
              <code>
                <span class="ocaml-keyword">let</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-entity-name-function-binding">g</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">x</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[(]]></span>
                <span class="ocaml-source">x</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">+</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-integer">1</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-support-type">int</span>
                <span class="ocaml-source"><![CDATA[)]]></span>
                <span class="ocaml-source">
</span>
              </code>
            </pre>
            <p>In <a href="https://github.com/ocaml/ocaml/pull/12119">OCaml 5.1 a new field for value bindings was added</a> allowing type constraints to be tracked directly in the bindings themselves.</p>
            <pre class="hilite">
              <code>
                <span class="ocaml-keyword-other">and</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">value_binding</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">  </span>
                <span class="ocaml-source"><![CDATA[{]]></span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">    </span>
                <span class="ocaml-source">pvb_pat</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">pattern</span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">    </span>
                <span class="ocaml-source">pvb_expr</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">expression</span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">    </span>
                <span class="ocaml-source">pvb_constraint</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">poly_constraint</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">option</span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">    </span>
                <span class="ocaml-source">pvb_attributes</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">attributes</span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">    </span>
                <span class="ocaml-source">pvb_loc</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">Location</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source">t</span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">  </span>
                <span class="ocaml-source"><![CDATA[}]]></span>
                <span class="ocaml-comment-doc"><![CDATA[(**]]></span>
                <span class="ocaml-comment-doc"><![CDATA[ [let pat : type_constraint = exp]]]></span>
                <span class="ocaml-comment-doc"><![CDATA[*)]]></span>
                <span class="ocaml-source">
</span>
              </code>
            </pre>
            <p>Our type constraint (<code>: int</code>) can be recorded in the <code>pvb_constraint</code> directly. This is a nice change, bringing the concrete syntax of the language closer to the parsetree. For ppxlib, however, it does create a bit of a headache as we now have to encode the different versions of expressing type constraints into the AST of the compiler <em>before</em> 5.1!</p>
            <p>So what was the bug? The author's of <code>repr</code> had added some value bindings to circumvent some "unused value warnings" in OCaml. They choose to write these bindings like:</p>
            <pre class="hilite">
              <code>
                <span class="ocaml-keyword-other">let</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[(]]></span>
                <span class="ocaml-constant-language">_</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-support-type">int</span>
                <span class="ocaml-source"><![CDATA[)]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-integer">1</span>
                <span class="ocaml-source">
</span>
              </code>
            </pre>
            <p>Here, I have simplified the types and the body of the binding. The significant thing to notice is the parentheses surrounding the value binding's pattern. This <em>forces</em> the AST representation to be a single <code>Ppat_constraint</code> node regardless of the current compiler version. No <code>Pexp_constraint</code> and no <code>pvb_constraint</code>.</p>
            <p>However, using ppxlib with a compiler less than 5.1 meant that this did not roundtrip cleanly. Instead, the value <em>after</em> passing through ppxlib's migrations was:</p>
            <pre class="hilite">
              <code>
                <span class="ocaml-keyword">let</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-entity-name-function-binding">_</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-support-type">int</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-integer">1</span>
                <span class="ocaml-source">
</span>
              </code>
            </pre>
            <p>After bottoming out at the issue, I discovered we <a href="https://github.com/ocaml-ppx/ppxlib/blob/22778658345fce526e6146da188cdc2d6d2e5286/test/501_migrations/reverse_migrations.t#L142">already had a test case for this in ppxlib</a>! Whatsomore, <code>ocamlformat.0.20.0</code> (which <code>repr</code> was still using) actually transforms instances of <code>let x : t = ...</code> into <code>let (x : t) = ...</code>! This limitation does not seem inherent to the parsetree, the printer or the migrations. But I have asked the (very kind and friendly) previous maintainers about these changes.</p>
          </section>
        </section>
        <section>
          <header>
            <h2>Outreachy</h2>
          </header>
          <p>December 8th 2025 marks the start of the next round of Outreachy. I have been preparing some issues for <a href="https://github.com/geocaml/ocaml-tiff">geocaml/ocaml-tiff</a> and I am excited to get started with <a href="https://github.com/giftcup">Tambe Salome</a>!</p>
        </section>
        <section>
          <header>
            <h2>Graft and Bib </h2>
          </header>
          <p>I spent some time at the start of the month updating and fixing <a href="https://patrick.sirref.org/graft/">Graft</a> and <a href="https://patrick.sirref.org/bib/">Bib</a>.</p>
          <p>I added <a href="https://graft.sirref.org/named-subtrees">named subtrees</a> to the markdown syntax. This allows users to create subtrees with headings that are also externally linkable.</p>
          <p>With some more bug fixing, I hope to release both libraries before the new year!</p>
        </section>
      </div>
    </content>
  </entry>
  <entry>
    <title>OCaml Roundup: October 2025</title>
    <published>2025-11-05T00:00:00-00:00</published>
    <updated>2025-11-05T00:00:00-00:00</updated>
    <author>
      <name>https://patrick.sirref.org/Patrick Ferris/</name>
      <uri>https://patrick.sirref.org/Patrick%20Ferris/</uri>
    </author>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/ocaml-roundup-october-2025/" />
    <id>https://patrick.sirref.org/ocaml-roundup-october-2025/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>Welcome to a monthly roundup of OCaml-related open-source work I have been involved with. If you haven't already, a quick look at <a href="https://patrick.sirref.org/icfp-2025/">my ICFP roundup</a> might be a good preface to what follows.</p>
        <section>
          <header>
            <h2>Outreachy December 2025</h2>
          </header>
          <p>The contribution period for this year's <a href="https://patrick.sirref.org/outreachy/">Outreachy</a> round took place for most of the month of October. This year I am excited to be going back to a <a href="https://patrick.sirref.org/geocaml/">Geocaml</a> project, working primarily to add writing capabilities to <a href="https://github.com/geocaml/ocaml-tiff">ocaml-tiff</a>.</p>
          <p>As per usual, I have been extremely pleased with the level of interest in the various <a href="https://www.outreachy.org/apply/project-selection/#ocaml">OCaml projects being offered</a>. Whilst we are still deliberating on our choices for interns this year, I won't say much more on the contributions, but if you want to get involved please do reach out! OCaml is a great language for geospatial work, striking a balance between reasonable performance for numerical code and also a rich type system for expressing complicated geospatial data-structures.</p>
        </section>
        <section>
          <header>
            <h2>Ppxlib and the Future of Compiler Support</h2>
          </header>
          <p><a href="https://patrick.sirref.org/nathanreb/">Nathan</a> has put a tremendous amount of effort into laying a roadmap this month for <a href="https://discuss.ocaml.org/t/ann-ppxlib-support-for-future-compilers/17430">how ppxlib, going forward, will support future compilers</a>. This is in response to the calamity that was <a href="https://patrick.sirref.org/ppxlib-5-2/">bumping the internal AST to 5.2</a>, and whilst I think we are adding a good deal more complexity, it will hopefully keep the ppx universe on an even keel for longer periods of time.</p>
          <p>The first <a href="https://github.com/ocaml-ppx/ppxlib/pull/607">substantial PR</a> for this modern world of ppxlib is in review!</p>
          <p>Aside from that I also debugged an issue that lead to <a href="https://github.com/ocaml-ppx/ppxlib/pull/604">ppxlib OOM-ing</a> machines... of course, any recursive fold-like loop where the accumulator keeps growing is likely to do that! It was nice to be able to crack out <a href="https://blog.janestreet.com/finding-memory-leaks-with-memtrace/">memtrace</a> to be able to hunt it down:</p>
          <img src="https://patrick.sirref.org/bafkrmignyxory52fgqvdsqxqcd6dfifpiqrerqwcl6lbdy3gbj4ck46zee.png" />
        </section>
        <section>
          <header>
            <h2>Incremental Directory Reading for Eio</h2>
          </header>
          <p>A common tasks for many a CLI tool is to scan a directory of files, filter out the ones you are looking for and apply some transformation to said files. In fact, that is what <a href="https://patrick.sirref.org/graft/">Graft</a> and <a href="https://patrick.sirref.org/forester/">Forester</a> both do! A standard approach to this involves a recursive dance of <code>readdir</code> and <code>stat</code>, the former lists the entries in a directory whilst the latter lets you know what kind of file is at a particular path (e.g. symbolic link, directory etc.). This has a few downsides:</p>
          <ol>
            <li>
              <p>We're making <strong>two</strong> systems calls (pretty much one of the most expensive things your program can do).</p>
            </li>
            <li>
              <p>If a directory contains thousands of files, we end up allocating a big list of strings after returning from <code>readdir</code>.</p>
            </li>
          </ol>
          <p>On Linux, we can get around most of that with <a href="https://linux.die.net/man/2/getdents64">getdents64(2)</a> which allows us to <em>incrementally</em> read a directory. Whatsomore, this system call also returns the file type so there's no need to do an extra <code>stat</code>!</p>
          <p>I prototyped <a href="https://github.com/ocaml-multicore/eio/pull/821">an implementation</a> of this called <code>Eio.Path.walk</code> which looks like:</p>
          <pre class="hilite">
            <code>
              <span class="ocaml-keyword-other">val</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">walk</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language">_</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">t</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-constant-language-capital-identifier">File</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">Stat</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">kind</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">*</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-support-type">string</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Seq</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">t</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-storage-type">'a</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-storage-type">'a</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-comment-doc"><![CDATA[(**]]></span>
              <span class="ocaml-comment-doc"><![CDATA[ [walk t] traverses the directory [t] producing a sequence of results.]]></span>
              <span class="ocaml-comment-doc"><![CDATA[*)]]></span>
              <span class="ocaml-source">
</span>
            </code>
          </pre>
          <p>We effectively halve the number of system calls. In a benchmark that traverse deeply-nested directories with plenty of files, a full traversal whent from <code>1.46s</code> to <code>110ms</code>. I have since rejigged the implementation to automatically recurse for the user into subdirectories (not that the signature is unchanged) which does make it tricky to control the number of open file descriptors compared to if the user were in control.</p>
        </section>
        <section>
          <header>
            <h2>OxCaml Experiments </h2>
          </header>
          <p>I have included here a transclusion from my <a href="https://patrick.sirref.org/icfp-2025/">ICFP</a> post about an experiment using unboxed 32-bit integers in OCaml's Uring library.</p>
          <section>
            <header>
              <h3>OxCaml and Uring</h3>
            </header>
            <p>Jane Street were a big presence at ICFP 2025, carting along with them a shiny new OCaml compiler: <a href="https://oxcaml.org/">OxCaml</a>. If have been <a href="https://patrick.sirref.org/try-oxcaml/">playing around with OxCaml recently</a> but nothing outside toplevels in Javascript. Until now!</p>
            <p>After talking to <a href="https://patrick.sirref.org/dra27/">David</a>, I spent some time converting a small corner of the <a href="https://github.com/ocaml-multicore/ocaml-uring">ocaml-uring</a> library to use a part of <a href="https://patrick.sirref.org/oxcaml/">OxCaml</a>. In particular making the following change:</p>
            <pre class="hilite">
              <code>
                <span class="ocaml-source">  </span>
                <span class="ocaml-keyword-other">module</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">Heap</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other">struct</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">    </span>
                <span class="ocaml-keyword-other">type</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">ptr</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-support-type">int32</span>
                <span class="ocaml-keyword-other">#</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">    </span>
                <span class="ocaml-comment-block"><![CDATA[(*]]></span>
                <span class="ocaml-comment-block"> ... </span>
                <span class="ocaml-comment-block"><![CDATA[*)]]></span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">  </span>
                <span class="ocaml-keyword-other">end</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">  </span>
                <span class="ocaml-keyword-other">type</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">cqe</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[{]]></span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">    </span>
                <span class="ocaml-source">user_data_id</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">Heap</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source">ptr</span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">    </span>
                <span class="ocaml-source">res</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-support-type">int32</span>
                <span class="ocaml-keyword-other">#</span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">  </span>
                <span class="ocaml-source"><![CDATA[}]]></span>
                <span class="ocaml-source">
</span>
              </code>
            </pre>
            <p>The idea being that a completion queue entry (a notification that some operation has completed) could be fully represented using 64 bits (two 32-bit, <a href="https://oxcaml.org/documentation/unboxed-types/01-intro/">unboxed values</a>). You can <a href="https://github.com/ocaml-multicore/ocaml-uring/compare/main...patricoferris:ocaml-uring:oxcaml?expand=1">see how this impacted the library</a>! I'm not certain about this change (and I'm sure I did it wrong) but it was nice to realise <a href="https://patrick.sirref.org/oxcaml/">OxCaml</a> gives you this kind of control. However, I am worried about the ergonomics of manipulating values like <code>int32#</code> and the temptation to case it into an <code>int</code> (presumably losing a good portion of the value of having an unboxed value in the first place).</p>
          </section>
          <section>
            <header>
              <h3>x-ocaml with OxCaml</h3>
            </header>
            <p>I sent <a href="https://github.com/oxcaml/opam-repository/pull/19">a few PRs</a> to the OxCaml repository to get the toplevel working again and lucky the underlying culprit for why patches were disappearing was found. Watch this space for a new toplevel in the browser soon.</p>
          </section>
        </section>
        <section>
          <header>
            <h2>Geospatial OCaml</h2>
          </header>
          <p>In addition to the <a href="https://patrick.sirref.org/outreachy/">Outreachy</a> work I mentioned above, I also found the time to keep the <a href="https://patrick.sirref.org/geocaml/">Geocaml</a> project ticking along. A few projects saw some much-needed love including:</p>
          <section>
            <header>
              <h3>PROJ in OCaml</h3>
            </header>
            <p>A <a href="https://github.com/geocaml/ocaml-proj">modernisation of the bindings</a> to <a href="https://proj.org/en/stable/">PROJ</a>. PROJ is probably the most used and tested code for working with geospatial projections. Any time you get a sateillite image or a blob of <a href="https://github.com/geocaml/ocaml-geojson">GeoJSON</a>, the geospatial data will normally have some coordinate reference system (CRS) with it detailing exactly what the numbers that tell you <em>where</em> something is mean. One of the most common being <a href="https://en.wikipedia.org/wiki/World_Geodetic_System">WGS84</a> (used by GPS and GeoJSON for example). Each CRS has its benefits and drawbacks, and often you will need to convert between them. That is what PROJ does.</p>
          </section>
          <section>
            <header>
              <h3>WKT in OCaml</h3>
            </header>
            <p>Well-known Text (WKT) is a very simple encoding of geospatial objects and CRSs. For example, a polygon might look like:</p>
            <pre><![CDATA[Polygon ((10 10, 10 20, 20 20, 20 15, 10 10))]]></pre>
            <p>I used <a href="https://ocaml.org/p/bytesrw">bytesrw</a> to build a <a href="https://github.com/geocaml/ocaml-wkt">simple codec for the WKT format</a>. It is probably about time to write the basic geospatial object library too, something similar to <a href="https://github.com/georust/geo">Rust's geo</a> library.</p>
          </section>
          <section>
            <header>
              <h3>Geotessera</h3>
            </header>
            <p>A lot of people in <a href="https://www.cst.cam.ac.uk/research/eeg">my group</a> are excited about <a href="https://patrick.sirref.org/tessera2025/">Tessera</a>. They have made it easy to used the Tessera embeddings via a python library called <a href="https://github.com/ucam-eo/geotessera">geotessera</a>. In true OCaml-at-heart spirit, I tried my hand at <a href="https://tangled.org/@patrick.sirref.org/ocaml-geotessera">porting this library</a>. I had a good deal of success, converting the data into <a href="https://ocaml.org/p/nx">Nx array</a>, extracting the CRS and transform out of the GeoTIFF landmasks using <a href="https://github.com/geocaml/ocaml-tiff">ocaml-tiff</a>, reading datasets using <a href="https://github.com/geocaml/ocaml-geojson">ocaml-geojson</a> etc. This made me excited but also keen to improve the APIs of most of these libraries too.</p>
            <p>I feel <a href="https://patrick.sirref.org/geocaml/">geocaml</a> is at a critical mass where we can start to have this useful feedback loop for the libraries because there is enough functionality to actually use them!</p>
          </section>
        </section>
      </div>
    </content>
  </entry>
  <entry>
    <title>OCaml Weekly 2025 w32 to w35</title>
    <published>2025-09-02T00:00:00-00:00</published>
    <updated>2025-09-02T00:00:00-00:00</updated>
    <author>
      <name>https://patrick.sirref.org/Patrick Ferris/</name>
      <uri>https://patrick.sirref.org/Patrick%20Ferris/</uri>
    </author>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/ocaml-weekly-2025-w32-w35/" />
    <id>https://patrick.sirref.org/ocaml-weekly-2025-w32-w35/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>I have been working on a few different OCaml-related projects over the last few weeks. This is also coinciding with my partner and I moving across the UK, which has made finding time to write <a href="https://patrick.sirref.org/weeklies/">weeklies</a> and <a href="https://patrick.sirref.org/posts/">posts</a> a little tricky. Nevertheless, here are some of the things I have been thinking about and working on!</p>
        <p>I managed to publish one signficant post this month: a <a href="https://patrick.sirref.org/irmin-retro/">retrospective on Irmin</a>.</p>
        <section>
          <header>
            <h2>Eio</h2>
          </header>
          <p>Increasingly, I'm feeling the dream of a unified framework for asynchronous IO slipping through the OCaml community's fingers. It is perhaps not such a bad thing, and I think with the right library authoring we can at least get to a place where it isn't so bad, for example <a href="https://github.com/geocaml/ocaml-tiff/blob/0dd98659642d1d9741068bb1eb943b4edeb5b5d6/src/tiff.ml#L2">providing read functions</a> as opposed to using an opinionated IO library directly.</p>
          <p>That being said, I am a very happy user of <a href="https://patrick.sirref.org/eio/">Eio</a> when those choices do not matter, as is the case in building your own application (e.g. <a href="https://patrick.sirref.org/shelter/">Shelter</a>). To this end, I have spent a good bit of time upstreaming support for various missing pieces in Eio's API including:</p>
          <ul>
            <li>
              <p><a href="https://github.com/ocaml-multicore/eio/pull/803">Setuid and setgid</a> fork action's for the process API.</p>
            </li>
            <li>
              <p><a href="https://github.com/ocaml-multicore/eio/pull/802">Set process group</a> support for job control in the process API.</p>
            </li>
            <li>
              <p><a href="https://github.com/ocaml-multicore/eio/pull/796">Responding to <code>Buf_write.of_flow</code></a> request, and tinkering with the example there. I think this does highlight the awkwardness of making code portable across concurrency mechanisms, particularly with Eio's structured concurrency.</p>
            </li>
            <li>
              <p>I did <a href="https://github.com/ocaml-multicore/eio/issues/788#issuecomment-3224454812">some investigating into <code>EINTR</code> bug</a> which seems to be stemming from a known-issue on Uring in that writes are not buffered which usually does not matter except perhaps when there are parallel writes to <code>stdout</code>.</p>
            </li>
            <li>
              <p><a href="https://github.com/ocaml-multicore/eio/issues/807">Spent some time thinking about the fiber local storage across domains issue</a>, I've passed on some thoughts to folks working on this.</p>
            </li>
          </ul>
        </section>
        <section>
          <header>
            <h2>Vpnkit</h2>
          </header>
          <p>You might recall <a href="https://patrick.sirref.org/vpnkit-upgrade/">I was interested in using vpnkit</a>. <a href="https://hannes.robur.coop/">Hannes</a> has done an amazing amount of work (patching and releasing) a series of packages to get this into a place that is much better and could be considered soon for merging. This defunctorisation is actually very useful for the Eio port I wrote a long time ago.</p>
          <section>
            <header>
              <h3>Papers and Talks at ICFP</h3>
            </header>
            <p>Somehow, I have ended up on lots of papers and talks at ICFP and the co-located events in October. The vaguely OCaml-related ones include:</p>
            <ul>
              <li>
                <p>Essentially a <a href="https://icfp25.sigplan.org/details/icfp-2025-papers/21/Functional-Networking-for-Millions-of-Docker-Desktops-Experience-Report-">Vpnkit Experience Report</a>.</p>
              </li>
              <li>
                <p>An extended abstract on generating a corpus of ill-typed Hazel programs was accepted into <a href="https://conf.researchr.org/home/icfp-splash-2025/tyde-2025">TyDe workshop</a>.</p>
              </li>
              <li>
                <p>Relatedly, the work that project supported was accepted into HATRA which was the <a href="https://patrick.sirref.org/part-ii-hazel/">Part II project I supervised</a>: <a href="https://conf.researchr.org/details/icfp-splash-2025/hatra-2025-papers/2/Decomposable-Type-Highlighting-for-Bidirectional-Type-and-Cast-Systems">Decomposable Type Highlighting for Bidirectional Type and Cast Systems</a>.</p>
              </li>
              <li>
                <p>And <a href="https://conf.researchr.org/home/icfp-splash-2025/propl-2025">two PROPL talks</a>!</p>
              </li>
            </ul>
          </section>
        </section>
        <section>
          <header>
            <h2>Outreachy</h2>
          </header>
          <p>We have come to the end of another Outreachy round! I will write more on this soon in its own separate post. But for now I am very grateful to this round's mentors <a href="https://www.gridbugs.org/">gridbugs</a> and <a href="https://patrick.sirref.org/mdales/">mdales</a>, and also our fantastic interns. If you are interested, please do watch our demo day presentations.</p>
          <div style="text-align: center">
    <iframe title="Outreachy May 2025 Demo Day" width="560" height="315" src="https://watch.ocaml.org/videos/embed/kZJRFM6iw9ug9BLNjEgKeH" frameborder="0" allowfullscreen="" sandbox="allow-same-origin allow-scripts allow-popups allow-forms" />
</div>
          <p>The next round is fast approaching and we still need to work out the logistics. But I had a good conversation with <a href="https://patrick.sirref.org/mdales/">mdales</a> about possible <a href="https://patrick.sirref.org/geocaml/">Geocaml</a> projects that I intend to submit!</p>
        </section>
      </div>
    </content>
  </entry>
  <entry>
    <title>Irmin Retrospective</title>
    <published>2025-08-07T00:00:00-00:00</published>
    <updated>2025-08-07T00:00:00-00:00</updated>
    <author>
      <name>https://patrick.sirref.org/Patrick Ferris/</name>
      <uri>https://patrick.sirref.org/Patrick%20Ferris/</uri>
    </author>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/irmin-retro/" />
    <id>https://patrick.sirref.org/irmin-retro/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p><a href="https://patrick.sirref.org/irmin/">Irmin</a> is an OCaml library for building <em>branchable</em> and <em>mergeable</em> data stores. The data is <em>mergeable</em> in the sense of <a href="https://patrick.sirref.org/kcrsk-mrdts-2022/">mergeable replicated data types</a>.</p>
        <p>I have been using Irmin for over five years to build different kinds of interesting data stores including:</p>
        <ul>
          <li>
            <p>A <a href="https://github.com/patricoferris/omditor">simple markdown-based note-taking web application</a>.</p>
          </li>
          <li>
            <p>A <a href="https://github.com/carboncredits/retirement-db">content-addressed database</a>.</p>
          </li>
          <li>
            <p>Mentoring an intern who <a href="https://tarides.com/blog/2022-08-02-irmin-in-the-browser/">worked on Irmin in the browser</a>.</p>
          </li>
          <li>
            <p>Most recently, an <a href="https://patrick.sirref.org/shelter/">Irmin-backed shell session manager</a>.</p>
          </li>
        </ul>
        <p>I was asked to provide some feedback recently on <a href="https://patrick.sirref.org/irmin/">Irmin</a>, so I thought writing a little retrospective here would be a good way to do that. The remit for the retrospective was about improving <a href="https://patrick.sirref.org/irmin/">Irmin</a>, so the content is focussed on pain points and areas of improvement.</p>
        <pre class="hilite">
          <code>
            <span class="ocaml-comment-block"><![CDATA[(*]]></span>
            <span class="ocaml-comment-block"> An in-memory Irmin store </span>
            <span class="ocaml-comment-block"><![CDATA[*)]]></span>
            <span class="ocaml-source">
</span>
            <span class="ocaml-keyword-other">module</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-constant-language-capital-identifier">Store</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-keyword-operator">=</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-constant-language-capital-identifier">Irmin_mem</span>
            <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
            <span class="ocaml-constant-language-capital-identifier">KV</span>
            <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
            <span class="ocaml-constant-language-capital-identifier">Make</span>
            <span class="ocaml-source"><![CDATA[(]]></span>
            <span class="ocaml-constant-language-capital-identifier">Irmin</span>
            <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
            <span class="ocaml-constant-language-capital-identifier">Contents</span>
            <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
            <span class="ocaml-constant-language-capital-identifier">String</span>
            <span class="ocaml-source"><![CDATA[)]]></span>
            <span class="ocaml-source">
</span>
          </code>
        </pre>
        <section>
          <header>
            <h2>What is Irmin?</h2>
          </header>
          <p><a href="https://patrick.sirref.org/irmin/">Irmin</a>, at its simplest, is a key-value database. Users associate keys with values and can query and update these bindings.</p>
          <p>Additionally, this database supports versioning. This means independent snapshots of the database can coexist and users can switch between them and update them without fear of interfering with other versions.</p>
          <p>Different versions of the database can be combined by <em>merging</em>. When you set up your instance of an <a href="https://patrick.sirref.org/irmin/">Irmin</a> database, you also provide it with a <a href="https://patrick.sirref.org/kcrsk-mrdts-2022/">merge function</a>.</p>
          <pre class="hilite">
            <code>
              <span class="ocaml-mdx-hash">#</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other">#</span>
              <span class="ocaml-keyword-other">show_type</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Irmin</span>
              <span class="ocaml-source">.</span>
              <span class="ocaml-constant-language-capital-identifier">Merge</span>
              <span class="ocaml-source">.</span>
              <span class="ocaml-source">f</span>
              <span class="ocaml-source">;;</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword-other">type</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other">nonrec</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-storage-type">'a</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">f</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">    </span>
              <span class="ocaml-source">old</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-storage-type">'a</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Irmin</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">Merge</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">promise</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">    </span>
              <span class="ocaml-storage-type">'a</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-storage-type">'a</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-storage-type">'a</span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Irmin</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">Merge</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">conflict</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">result</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Lwt</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">t</span>
              <span class="ocaml-source">
</span>
            </code>
          </pre>
        </section>
        <section>
          <header>
            <h2>Design and API</h2>
          </header>
          <p><a href="https://patrick.sirref.org/irmin/">Irmin</a>'s API is very git-inspired. There is a large overlap of shared vocabulary and concepts: <em>repositories</em>, <em>branches</em>, <em>commits</em>, <em>heads</em> etc.</p>
          <p>Probably the most confusing aspect of this is the notion of a <code>Store</code>. When I was describing <a href="https://patrick.sirref.org/irmin/">Irmin</a> above, I used the term <em>database</em> to help distinguish between some of these concepts. In Irmin's documentation, it is used for multiple related (but different) concepts. In "<a href="https://irmin.org/tutorial/getting-started/#creating-a-store">Creating a Store</a>" stores refer to the entire database, whereas in the <a href="https://patrick.sirref.org/irmin/">Irmin</a> API docs we have that:</p>
          <blockquote>
            <p>There are two kinds of store in Irmin: the ones based on persistent named branches and the ones based temporary detached heads.</p>
          </blockquote>
          <p>For <a href="https://patrick.sirref.org/irmin/">Irmin</a> library users, a <code>Store.t</code> can be thought of as a checkout of the database at a particular revision. This may be from a branch or a specific commit.</p>
          <pre class="hilite">
            <code>
              <span class="ocaml-mdx-hash">#</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Store</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">of_branch</span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword-operator">-</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Store</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">repo</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-support-type">string</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Store</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">t</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Lwt</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">t</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">&lt;</span>
              <span class="ocaml-keyword-other">fun</span>
              <span class="ocaml-keyword-operator">&gt;</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-mdx-hash">#</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Store</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">of_commit</span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword-operator">-</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Store</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">commit</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Store</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">t</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Lwt</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">t</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">&lt;</span>
              <span class="ocaml-keyword-other">fun</span>
              <span class="ocaml-keyword-operator">&gt;</span>
              <span class="ocaml-source">
</span>
            </code>
          </pre>
          <p>The overloading of the term is confusing. I think it leaves users unsure about what other people might mean when they say "store". Being careful with these terms, and the contexts in which they are used, would help avoid this confusion.</p>
          <section>
            <header>
              <h3>Module and Functor Soup</h3>
            </header>
            <p>Undoubtedly for a majority of use-cases and users, <a href="https://patrick.sirref.org/irmin/">Irmin</a> is over-functorised. Nearly every module requires that you must apply some functor to access any useful code. In general, a user will have to interact with the <a href="https://mirage.github.io/irmin/irmin/Irmin/module-type-S/Schema/index.html"><code>Schema</code> module</a> when describing the types they want to instantiate their store with.</p>
            <p>To counteract this, Irmin has plenty of <code>KV</code> modules that provide a <code>Make</code> functor that only requires a user to provide a suitable <em>content</em> module for their store (i.e. something that provides a type, a runtime representation of that type and a merge function).</p>
            <pre class="hilite">
              <code>
                <span class="ocaml-mdx-hash">#</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other">#</span>
                <span class="ocaml-keyword-other">show_module</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">Irmin_mem</span>
                <span class="ocaml-source">.</span>
                <span class="ocaml-constant-language-capital-identifier">KV</span>
                <span class="ocaml-source">;;</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-keyword-other">module</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">KV</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">  </span>
                <span class="ocaml-keyword-other">sig</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">    </span>
                <span class="ocaml-keyword">type</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-entity-name-function-binding">endpoint</span>
                <span class="ocaml-source"> = unit
</span>
                <span class="ocaml-source">    </span>
                <span class="ocaml-keyword">type</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-entity-name-function-binding">metadata</span>
                <span class="ocaml-source"> = unit
</span>
                <span class="ocaml-source">    </span>
                <span class="ocaml-keyword">type</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-entity-name-function-binding">hash</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">    </span>
                <span class="ocaml-keyword">type</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-entity-name-function-binding">info</span>
                <span class="ocaml-source"> = Store.info
</span>
                <span class="ocaml-source">    </span>
                <span class="ocaml-keyword">type</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[('h, _)]]></span>
                <span class="ocaml-entity-name-function-binding">contents_key</span>
                <span class="ocaml-source"> = 'h
</span>
                <span class="ocaml-source">    </span>
                <span class="ocaml-keyword">type</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">'h </span>
                <span class="ocaml-entity-name-function-binding">node_key</span>
                <span class="ocaml-source"> = 'h
</span>
                <span class="ocaml-source">    </span>
                <span class="ocaml-keyword">type</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">'h </span>
                <span class="ocaml-entity-name-function-binding">commit_key</span>
                <span class="ocaml-source"> = 'h
</span>
                <span class="ocaml-source">    </span>
                <span class="ocaml-keyword-other-ocaml">module</span>
                <span class="ocaml-source"><![CDATA[ Make : (C : Irmin__.Contents.S) ->]]></span>
                <span class="ocaml-keyword-other-ocaml">sig</span>
                <span class="ocaml-source"> ... </span>
                <span class="ocaml-keyword-other">end</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">  </span>
                <span class="ocaml-keyword-other">end</span>
                <span class="ocaml-source">
</span>
              </code>
            </pre>
            <p>I think it is fair to say the documentation is hard to follow as it is a module and functor soup. For example, looking at <code>irmin.3.11.0</code>, starting at <a href="https://ocaml.org/p/irmin/latest/doc/index.html">the toplevel documentation page</a> our path to finding this paricular module and functor is as follows:</p>
            <ol>
              <li>
                <p>We jump into <a href="https://ocaml.org/p/irmin/latest/doc/irmin.mem/Irmin_mem/index.html"><code>Irmin_mem</code></a> from the nicely written landing page.</p>
              </li>
              <li>
                <p>We scroll down to find <a href="https://ocaml.org/p/irmin/latest/doc/irmin.mem/Irmin_mem/index.html#module-KV">the KV module</a>.</p>
              </li>
              <li>
                <p>We now make sense of the module's signature by following the <a href="https://ocaml.org/p/irmin/latest/doc/irmin/Irmin/module-type-KV_maker/index.html">KV_maker link</a>.</p>
              </li>
              <li>
                <p>We see a <code>Make (C : Contents.S) : sig ... end</code> at the end of the module, and <a href="https://ocaml.org/p/irmin/latest/doc/irmin/Irmin/module-type-KV_maker/Make/index.html#module-Schema">we navigate through that</a>.</p>
              </li>
              <li>
                <p>Finally we have come to our journey's end, and find the <a href="https://ocaml.org/p/irmin/latest/doc/irmin/Irmin/module-type-KV_maker/Make/index.html#module-Schema">schema module</a> with type constraints like <code>type Branch.t = string</code>.</p>
              </li>
            </ol>
            <p>There is a big assumption there that you know what the <code>Schema</code> module is telling you and how it relates to your "store".</p>
            <p>There is a counter-argument here, in that Irmin is incredibly flexible in terms of what you can use as types for your keys, branches, hashes etc. I was quite easily able to produce <a href="https://github.com/patricoferris/ocaml-cid/blob/main/test/irmin_cid.ml">Irmin stores that use CIDs (self-describing content identifiers)</a> for example.</p>
            <p>I think there is a middle ground. For Irmin to be usable it needs to reduce the complexity of the API. The complexity is due to, in large part, over-functorisation. If the functors cannot be removed then perhaps better documentation or more <a href="https://ocaml.org/p/irmin-containers/latest/doc/irmin-containers/Irmin_containers/index.html">introductory libraries like irmin-containers</a> would be helpful. Perhaps a <em>standalone</em> library that acts as an interface to Irmin stores would be helpful. I find myself time and again implementing <a href="https://github.com/fn06/shelter/blob/main/src/lib/store.ml">something like that</a>.</p>
          </section>
          <section>
            <header>
              <h3>Backends Galore</h3>
            </header>
            <p>Irmin has plenty of backends including <a href="https://ocaml.org/p/irmin-git/latest">a git-compatible one</a>, <a href="https://ocaml.org/p/irmin-mirage/latest">a MirageOS backend</a>, <a href="https://ocaml.org/p/irmin-indexeddb/latest">an in-browser IndexedDB backend</a> and even a <a href="https://github.com/andreas/irmin-fdb">FoundationDB backend</a>.</p>
            <p><a href="https://patrick.sirref.org/irmin/">Irmin</a> needs to have fewer, better tested backends. Of course, some of these are likely driven by funding and use-case specific details. However, I think by focusing on a few key backends and striving for solid performance but also strong consitency guarantees, <a href="https://patrick.sirref.org/irmin/">Irmin</a> would become a more viable candidate for potential users. I also believe the browser backend plays a key part to making this work in order to facilate <a href="https://lofi.so/">local-first applications</a>.</p>
          </section>
          <section>
            <header>
              <h3>Syncing Remote Stores</h3>
            </header>
            <p>The <a href="https://ocaml.org/p/irmin/3.11.0/doc/irmin/Irmin/Sync/index.html">synchronisation mechanisms in Irmin</a> are powerful, but often the API is very confusing. For example, with the git-compatible Unix backend, nested deep in the documentation is the function required to create a <a href="https://ocaml.org/p/irmin-git/latest/doc/irmin-git.unix/Irmin_git_unix/Maker/Make/index.html#val-remote">remote endpoint</a>. Once they have found this function, using it is not easy as it requires them to learn about the <a href="https://ocaml.org/p/mimic/latest"><code>Mimic.ctx</code></a>, which is an abstraction of the networking stack!</p>
          </section>
          <section>
            <header>
              <h3>Do Fewer Things and Do Them Well</h3>
            </header>
            <p>Irmin is simultaneously a database that supports: content-addressing, merging, key-value lookup, branches, transactions, complete OS portability etc. I think, in short, it tries to do too many things and comes up short on some of them in ways that really matter.</p>
            <p>When building the <a href="https://github.com/carboncredits/retirement-db">content-addressed database</a> I needed strong guarantees about some atomic actions to perform on the underlying store. For example, <a href="https://github.com/mirage/irmin/issues/2073">setting the value and accessing the commit associated with it</a> which was not possible with the API at that time in an atomic way. This kind of missing functionality is probably only understood after users stumble across it, but it also makes the library feel less focused and ready for production use-cases.</p>
          </section>
        </section>
        <section>
          <header>
            <h2>Documentation</h2>
          </header>
          <p>It will probably come as no surprise that one of the main limitations of using <a href="https://patrick.sirref.org/irmin/">Irmin</a> is the lack of documentation and tutorials. This is a particular pain point as the API is not very straightforward.</p>
          <p>A while back, I started an <a href="https://patricoferris.github.io/irmin-book/">Irmin book</a> intending to help document the kinds of things real-world users would need in order to use <a href="https://patrick.sirref.org/irmin/">Irmin</a> in earnest. For example: ways to <a href="https://patricoferris.github.io/irmin-book/contents/versioned-data.html">deal with type migrations</a> or <a href="https://patricoferris.github.io/irmin-book/arch/runtime-types.html">primers on runtime types</a>. I still believe this sort of work would be invaluable, but there is a large cost to completing it, and it is not clear if there is enough interest in the project to warrant such an effort.</p>
          <p>The <a href="https://irmin.org/tutorial/introduction/">tutorials on the irmin website</a> are still good starting points for most new users. But they quickly lack the depth for real-world scenarios.</p>
        </section>
        <section>
          <header>
            <h2>Feature Wishlist</h2>
          </header>
          <p>What follows are additional ideas for improving <a href="https://patrick.sirref.org/irmin/">Irmin</a>.</p>
          <section>
            <header>
              <h3>Heterogeneous Stores</h3>
            </header>
            <p><![CDATA[For all of [Irmin]'s abstraction and functorisation, there is a very clear]]> missing feature for lots of first-time users of the library: you can only store values of a single type.</p>
            <p>This leads to a few common workarounds:</p>
            <ul>
              <li>
                <p>Storing a serealised version of your values, essentially escaping the type-system and implementing a form of dynamic typing.</p>
              </li>
              <li>
                <p>Growing your value to hold lots of different types via some large variant type.</p>
              </li>
            </ul>
            <p>Both of these options are feasible and have been used in practice. However, they are workarounds. A long time ago <a href="https://craigfe.io/">CraigFe</a> created an <a href="https://github.com/mirage/irmin/issues/909">RFC for heterogeneous stores</a>, which I think about a lot. The main idea is to augment <a href="https://patrick.sirref.org/irmin/">Irmin</a> paths (keys) to be GADTs that carry type information about the kinds of values they access (similar to <a href="https://ocaml.org/p/hmap">heterogeneuous variants of other data structures</a>). Something like this alongside a simplified API would make Irmin more appealing as a library for persistent data storage.</p>
          </section>
          <section>
            <header>
              <h3>Real-world Retrospectives</h3>
            </header>
            <p>This echos some thoughts from the <em>Documentation</em> section. There are some very real-world <a href="https://patrick.sirref.org/irmin/">Irmin</a> use-cases out there. For example, for a long time (I'm not sure if this is still the case) parts of the <a href="https://ocaml.org/p/tezos-context/latest#dependencies">Tezos blockchain were using Irmin</a> which uses the <a href="https://ocaml.org/p/irmin-pack/latest">irmin-pack</a> backend. Does this make irmin-pack the best tested backend and perhaps should be the default backend for new users? Or is it hyper-specific to the Tezos use case? There are <a href="https://tarides.com/blog/2020-09-01-introducing-irmin-pack/">blogs on tarides.com about the irmin-pack backend</a>, but they might be outdated and should not be the first place to find advice on which Irmin backend to use.</p>
          </section>
          <section>
            <header>
              <h3>Active Development and Engagement</h3>
            </header>
            <p>As far as I know, <a href="https://patrick.sirref.org/irmin/">Irmin</a> was at the forefront of technologies that have come to be described as <a href="https://lofi.so/">local-first</a>. There is a growing interest in this area (particularly as it acts as a counter-argument to an increasingly online, centralised model). I highly recommend reading <a href="https://patrick.sirref.org/ink%20&amp;%20switch's%20essay%20on%20the%20matter/">Ink &amp; Switch's essay on the matter</a>. And it would be great to see more research via <a href="https://patrick.sirref.org/irmin/">Irmin</a> at things like <a href="https://lu.ma/localfirstswunconf-stlouis">the lofi unconference</a> and the <a href="https://2023.splashcon.org/home/plf-2023">PLF workshop at SPLASH 2023</a>!</p>
            <p>Thank you for reading! And thank you to all the <a href="https://patrick.sirref.org/irmin/">Irmin</a> contributors. I hope this might be useful in the future for building the next-generation <a href="https://patrick.sirref.org/irmin/">Irmin</a>!</p>
          </section>
        </section>
      </div>
    </content>
  </entry>
  <entry>
    <title>OCaml Weekly 2025 w30 and w31</title>
    <published>2025-07-31T00:00:00-00:00</published>
    <updated>2025-07-31T00:00:00-00:00</updated>
    <author>
      <name>https://patrick.sirref.org/Patrick Ferris/</name>
      <uri>https://patrick.sirref.org/Patrick%20Ferris/</uri>
    </author>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/ocaml-weekly-2025-w30-w31/" />
    <id>https://patrick.sirref.org/ocaml-weekly-2025-w30-w31/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>A bumper edition today, a fortnightly.</p>
        <section>
          <header>
            <h2>Opam Releases</h2>
          </header>
          <p>I did a little personal spring-cleaning of packages I maintain and pushed a few releases to opam. This included a <a href="https://github.com/ocaml/opam-repository/pull/28187">0.1.0 release</a> of <a href="https://patrick.sirref.org/graft/">graft</a>! There is some light documentation online at <a href="https://graft.sirref.org/">https://graft.sirref.org</a>.</p>
          <p>Elsewhere, <a href="https://github.com/patricoferris/hilite">Hilite</a> got a <a href="https://github.com/ocaml/opam-repository/pull/28172">0.5.0 release</a>. This release makes the core syntax highlighting separate from the markdown part of the library. You can now <a href="https://ocaml.org/p/hilite/latest/doc/hilite/Hilite/index.html#val-src_code_to_pairs">generate pairs of tokens and identifiers</a> to plug into any "OCaml sourcecode to format" tool you might be building (e.g. <a href="https://patrick.sirref.org/graft/">graft</a>!).</p>
        </section>
        <section>
          <header>
            <h2>Interactive OCaml Presentations</h2>
          </header>
          <p>I had fun trying to fuse slipshow and x-ocaml!</p>
          <section>
            <header>
              <h3>Slipshow x x-ocaml</h3>
            </header>
            <p>A short, explanatory post about combining two very fun pieces of work in OCaml.</p>
            <p><a href="https://github.com/panglesd">Paul-Elliot</a> has been building <a href="https://github.com/panglesd/slipshow">Slipshow</a> for some time now where slides are <em>slips</em> and your presentations run vertically. More recently, <a href="https://patrick.sirref.org/artw/">Arthur</a> has built <a href="https://github.com/art-w/x-ocaml">x-ocaml</a>, a web component library for executable OCaml cells embedded into OCaml.</p>
            <p>Using <a href="https://github.com/patricoferris/xocmd">xocmd</a>, a small tool I built for translating markdown codeblocks to x-ocaml components, your Slipshow's can now be <em>executable</em>!</p>
            <pre><![CDATA[xocmd learn-effects.md | slipshow compile - > learn-effects.html]]></pre>
            <p>
    Take a look at 
    <a href="https://patrick.sirref.org/bafkrmictvc3ap2ah37cbcdoo6rsl7vxqu6srogmgzx6iml45bq7zz5weo4.html">an example</a>!
    (or the 
    <a href="https://patrick.sirref.org/bafkrmib3jugpkznxcftqjvhbbtfqgx4oz2m32p5xloh4nxia3lhxy2momq.md">source markdown</a>).
</p>
            <p>I really like this light-weight approach to building interactive presentations for explaining things in OCaml (e.g. over running a jupyter notebook server).</p>
          </section>
          <p>I tried using x-ocaml with <a href="https://irmin.org/">Irmin</a> and something is not quite right with some of the runtime JS code being generated (<a href="https://github.com/art-w/x-ocaml/issues/11">see the issue in case you can help</a>). This was intended to be used alongside a longer-form retrospective I am writing on my use of Irmin over the years.</p>
        </section>
        <section>
          <header>
            <h2>Outreachy</h2>
          </header>
          <p>I have been helping <a href="https://patrick.sirref.org/mdales/">Michael's</a> intern whilst he has been away on their project <a href="https://github.com/claudiusFX/claudius">Claudius</a>. It has reminded me, again, how inpenetretable some of OCaml's tooling is. In this case the generation of opam files from dune-project files, and in particular, the required <em>manual</em> steps when you wish to remove a dependency (1. remove it from the <code>dune-project</code> file, 2. run <code>dune build</code> to update the opam file, 3. remove all occurences of the library from <code>dune</code> files across your project).</p>
        </section>
        <section>
          <header>
            <h2>Ppxlib</h2>
          </header>
          <p>Work on <a href="https://patrick.sirref.org/ppxlib/">Ppxlib</a> has been fairly varied this past two weeks. I mentioned before about an exiting plan <a href="https://patrick.sirref.org/nathanreb/">Nathan</a> has planned to help ease the burden on ppxlib maintainers and ppx authors whenever there is an OCaml parsetree bump. That, however, is currently shelved as we are dealing with the fall out of <a href="https://patrick.sirref.org/ppxlib-5-2/">the 5.2 bump</a>. <a href="https://github.com/mirage/repr/pull/110">Repr</a> got some fixes pushed to it, but this unconvered <a href="https://github.com/ocaml-ppx/ppxlib/pull/588">more issues</a>.</p>
        </section>
        <section>
          <header>
            <h2>Misc.</h2>
          </header>
          <p>I spent some time cleaning up <a href="https://github.com/quantifyearth/container-image">container-image</a>, a tool primarily written by <a href="https://github.com/samoht">Thomas G.</a> to fetch OCI images from repositories. The <a href="https://github.com/quantifyearth/container-image/pull/5">tidy up</a> went surprisingly well, except for some spurious HTTP errors with AWS. Maybe I'll spend some proper time trying to help the state of HTTP clients in OCaml (of which there are many, but few that work very well out of the box in my experience).</p>
        </section>
      </div>
    </content>
  </entry>
  <entry>
    <title>Slipshow x x-ocaml</title>
    <published>2025-07-23T00:00:00-00:00</published>
    <updated>2025-07-23T00:00:00-00:00</updated>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/slipshow-x-xocaml/" />
    <id>https://patrick.sirref.org/slipshow-x-xocaml/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>A short, explanatory post about combining two very fun pieces of work in OCaml.</p>
        <p><a href="https://github.com/panglesd">Paul-Elliot</a> has been building <a href="https://github.com/panglesd/slipshow">Slipshow</a> for some time now where slides are <em>slips</em> and your presentations run vertically. More recently, <a href="https://patrick.sirref.org/artw/">Arthur</a> has built <a href="https://github.com/art-w/x-ocaml">x-ocaml</a>, a web component library for executable OCaml cells embedded into OCaml.</p>
        <p>Using <a href="https://github.com/patricoferris/xocmd">xocmd</a>, a small tool I built for translating markdown codeblocks to x-ocaml components, your Slipshow's can now be <em>executable</em>!</p>
        <pre><![CDATA[xocmd learn-effects.md | slipshow compile - > learn-effects.html]]></pre>
        <p>
    Take a look at 
    <a href="https://patrick.sirref.org/bafkrmictvc3ap2ah37cbcdoo6rsl7vxqu6srogmgzx6iml45bq7zz5weo4.html">an example</a>!
    (or the 
    <a href="https://patrick.sirref.org/bafkrmib3jugpkznxcftqjvhbbtfqgx4oz2m32p5xloh4nxia3lhxy2momq.md">source markdown</a>).
</p>
        <p>I really like this light-weight approach to building interactive presentations for explaining things in OCaml (e.g. over running a jupyter notebook server).</p>
      </div>
    </content>
  </entry>
  <entry>
    <title>Quarterly OCaml Q2</title>
    <published>2025-07-18T00:00:00-00:00</published>
    <updated>2025-07-18T00:00:00-00:00</updated>
    <author>
      <name>https://patrick.sirref.org/Patrick Ferris/</name>
      <uri>https://patrick.sirref.org/Patrick%20Ferris/</uri>
    </author>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/ocaml-quarterly-q2/" />
    <id>https://patrick.sirref.org/ocaml-quarterly-q2/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>Thanks to <a href="https://patrick.sirref.org/tarides/">Tarides</a> sponsorship, I get to work on open-source OCaml. This quarterly is a companion to my <a href="https://patrick.sirref.org/weeklies/">weeklies</a>, summarising the last three months of development, peppered with ideas and thoughts about OCaml, its community and its future.</p>
        <section>
          <header>
            <h2>What I wanted to work on?</h2>
          </header>
          <p>There were two main things I hoped to <em>continue</em> working on: <strong>ppxlib</strong> and <strong>outreachy</strong>. These are projects that I was previously working on, and in the case of Outreachy I have now been involved for many years.</p>
          <p>In addition to this, all of my <a href="https://patrick.sirref.org/part-ii-2024/">Part II</a> projects this year used OCaml in some regard. In general, I want to see more adoption of OCaml. Over the years this has taken many forms including <a href="https://ocaml-explore.netlify.app/">my initial work on developing workflows for OCaml that just turned five years old</a>. This directly fed into the rebranding and rethinking of <a href="https://ocaml.org/">ocaml.org</a> itself.</p>
        </section>
        <section>
          <header>
            <h2>What I worked on?</h2>
          </header>
          <section>
            <header>
              <h3>Ppxlib</h3>
            </header>
            <p><a href="https://patrick.sirref.org/ppxlib/">Ppxlib</a> is the de facto standard library for building OCaml preprocessors. At the time of writing, <code>opam list --depends-on=ppxlib</code> informs me that there are 267 reverse dependencies. <a href="https://www.janestreet.com/">Janestreet</a> is a heavy user of ppxes and has <a href="https://github.com/orgs/janestreet/repositories?language=&amp;amp%3Bq=ppx&amp;amp%3Bsort=&amp;amp%3Btype=all">authored many</a>.</p>
            <p>One of the main accomplishments this quarter was <a href="https://patrick.sirref.org/ppxlib-5-2/">bumping the internal AST to 5.2</a>. This allows ppx authors to use new OCaml language features in their ppxes. In bumping the AST, we knowingly broke compatability for pretty much every single reverse dependency. As best we can, we have been sending patches to ppx libraries and helping users migrate to the latest <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a>.</p>
            <p>There is an interesting dicussion to had about the nature of open-source, and its interaction with industrial monorepos and community tended package repositories. Package ecosystems thrive whenever there is a dedicated community creating, maintaining and publishing packages. The idea is that the published world should be healthy. The publishing medium can act as natural limiting factor in the churn of breaking changes (in the case of OCaml this is via <a href="https://github.com/ocaml/opam-repository/">PRs to the opam-repository</a>). This, I have come to notice, reacts poorly to changes coming from internally consistent monorepos where introducing breaking changes is easily fixed by applying patches there and then. Whatsmore, OCaml is often stated as an incredibly safe language to perform large refactorings thanks to its type system.</p>
            <p><a href="https://patrick.sirref.org/ppxlib/">Ppxlib</a> sits awkwardly in the space of possible breaking changes. Tied to OCaml's parsetree, impacts of changes there ripple down to <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a>. The compiler itself can remain internally consistent, and is protected as it need only parse source code. <a href="https://patrick.sirref.org/ppxlib/">Ppxlib</a>, on the other hand, exposes the parsetree to users and thus any changes to the parsetree will likely be felt by ppx authors. Since I started working on <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a>, it feels as though the number of syntax changes has gone up (primarily from Janestreet work). Unless we make changes to how we provide support for these, maintainers of <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> will forever be stuck doing busy work! Thankfully, <a href="https://patrick.sirref.org/nathanreb/">Nathan</a> <a href="https://patrick.sirref.org/ocaml-weekly-2025-w29/">has thoughts on how to improve this</a>.</p>
            <p>There are a slew of other features I have added to <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> including:</p>
            <ul>
              <li>
                <p>Support for deriving from classes.</p>
              </li>
              <li>
                <p>Support for deriving from module bindings and signatures.</p>
              </li>
              <li>
                <p>Fixing compiler and ppxlib dummy locations.</p>
              </li>
              <li>
                <p>Bumping to 5.3.</p>
              </li>
              <li>
                <p>Migrations for 5.4.</p>
              </li>
            </ul>
          </section>
          <section>
            <header>
              <h3>Outreachy</h3>
            </header>
            <p>Our two projects this year, one on <a href="https://github.com/claudiusFX/claudius">claudius</a> and one on <a href="https://github.com/ocaml/dune">dune</a>, are going extremely well. At the time of writing, we just had <a href="https://patrick.sirref.org/ocaml-weekly-2025-w29/">a mid-internship call to catch up</a>, and I was blown away by the progress each intern has made. Unfortunately, <a href="https://patrick.sirref.org/outreachy/">Outreachy</a> is struggling with funding and the next round is perhaps not going to happen. This is a real shame and I am hoping that it will not be the case.</p>
            <p>Outreachy has been a wonderful source of new, committed OCaml developers. If you haven't already, do peruse the <a href="https://ocaml.org/outreachy">webpage on OCaml.org</a> to see past internships or <a href="https://watch.ocaml.org/c/outreachy_ocaml/videos">watch the demo day presentations</a>. For the mentors involved, I believe it has also been a rewarding experience (though at times a challenging one). We are always looking for new mentors and project ideas, please <a href="https://patrick.sirref.org/patrickferris/">do reach out to me</a> if you are interested.</p>
          </section>
          <section>
            <header>
              <h3>Hazel</h3>
            </header>
            <p>OCaml's feature set allows it to shine at writing programming languages (and things of that ilk: compilers, interpretters, static analysis tools). <a href="https://patrick.sirref.org/hazel/">Hazel</a> is a research programming language with typed holes written completely in OCaml (via the <a href="https://reasonml.github.io/">reason dialect</a>).</p>
            <p>Relating this back to the original intent of my work, to improve OCaml adoption, I believe this also means keeping existing users happy. In the last quarter I developed a compiler from <a href="https://patrick.sirref.org/hazel_of_ocaml/">OCaml to Hazel</a>. Whilst new features are still being added to <a href="https://patrick.sirref.org/hazel/">Hazel</a>, I hope this could serve as a tool to help develop test-suites and standard library functions using existing OCaml solutions. In a student's work (<a href="https://patrick.sirref.org/part-ii-hazel/">Typed Debugging for Hazel</a>), we used this tool to build a corpus of ill-typed <a href="https://patrick.sirref.org/hazel/">Hazel</a> programs to great effect.</p>
            <p>OCaml should continue to be a world-class programming language for building other programming languages. I hope to upstream some of this work to <a href="https://patrick.sirref.org/hazel/">Hazel</a> and provide some low effort maintenance to help keep their compiler in good shape.</p>
          </section>
          <section>
            <header>
              <h3>Systems Programming in OCaml</h3>
            </header>
            <p>In a cross-over with my own research, I have been developing many tools related to systems programming in OCaml including:</p>
            <ul>
              <li>
                <p>An eBPF-based <a href="https://patrick.sirref.org/open-trace/"><code>open</code> syscall tracing tool</a>.</p>
              </li>
              <li>
                <p>A library in OCaml for <a href="https://github.com/quantifyearth/void">spawning void processes</a>.</p>
              </li>
              <li>
                <p>A <a href="https://patrick.sirref.org/shelter/">shell session manager</a> that uses <a href="https://irmin.org/">Irmin</a> to manage sessions. It is nice to see a new push to <a href="https://github.com/mirage/irmin/pull/2149">finally land the direct-style Irmin PR</a>!</p>
              </li>
            </ul>
            <p>This work is means to develop the underlying libraries that support it. For example, I have opened a few PRs to <a href="https://github.com/ocaml-multicore/eio">Eio</a> to add new "fork actions" to the spawn API. I also investigated the feasibility of changing the underlying mechanisms in <a href="https://patrick.sirref.org/eio/">Eio</a> to use <a href="https://github.com/ocaml-multicore/picos">Picos</a>. In the future, I think this could be important avoid further splitting the OCaml ecosystem.</p>
            <section>
              <header>
                <h4>OxCaml</h4>
              </header>
              <p>I dabbled a little with <a href="https://oxcaml.org/">OxCaml</a> and build <a href="https://patrick.sirref.org/try-oxcaml/">try-oxcaml</a> to let people take it for a spin without having to perform opam repository gymnastics. It turned into a lot of work to track down some pretty inane bugs (type definitions differeing between js_of_ocaml and the OxCaml compiler, resulting in different Javascript runtime representations...).</p>
              <p>This unblocked a few of my colleagues to get OxCaml working on tools like <a href="https://jon.recoil.org/notebooks/foundations/foundations1.html">odoc_notebooks</a> and <a href="https://github.com/art-w/x-ocaml">x-ocaml</a>.</p>
            </section>
          </section>
          <section>
            <header>
              <h3>Forester</h3>
            </header>
            <p>A good proportion of my work this quarter has been focused on how to present the very work that I am doing. <a href="https://patrick.sirref.org/jonmsterling/">Jon Sterling</a> has been developing a tool for scientific thought called <a href="https://patrick.sirref.org/forester/">Forester</a> which seemed like a possible candidate for writing and sharing my work.</p>
            <p>Porting my existing blog posts and website content from markdown to Forester's LaTeX-inspired syntax didn't seem like an option. In particular, many of my posts made use of additional markdown-based tools (like <a href="https://github.com/realworldocaml/mdx">ocaml-mdx</a>).</p>
            <p>This lead to the development of <a href="https://patrick.sirref.org/graft/">Graft</a>: a preprocessor for Forester forests, converting markdown and bibtex to trees.</p>
          </section>
        </section>
        <section>
          <header>
            <h2>What's next?</h2>
          </header>
          <p>So, I worked on most of what I wanted to work on and then some! Going forward I hope to keep maintaining <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> in some capacity and coordinating the OCaml community's <a href="https://patrick.sirref.org/outreachy/">Outreachy</a> efforts.</p>
          <p>I hope to continue my small experiments (e.g. converting Eio to Picos). My own research makes heavy use of Irmin, and I would be interested to help with that too. More recently, a new library has been released for working with numerical data in OCaml called <a href="https://github.com/raven-ml/">Raven</a>: I am interested to use this library in <a href="https://patrick.sirref.org/geocaml/">Geocaml</a>, a suite of geospatial tools written in OCaml that I maintain.</p>
          <p>I feel conflicted about the <a href="https://patrick.sirref.org/oxcaml/">OxCaml</a> efforts. I admit, I am not fully aware of the full benefits of the features, but I worry about some proliferation of modes that make the type system in OCaml unbearable to use. On top of this, with my <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> hat on, I worry about the impact of changing the compiler so frequently, placing strain on an already small community. That being said, by releasing <a href="https://patrick.sirref.org/oxcaml/">OxCaml</a> separately I do believe running it as an experimental set of packages will help understand the tool better. But I would not be building anything I intend to maintain or research with right now as that ecosystem is far too volatile.</p>
          <p>Finally, over the past two years I have done a lot of teaching. From <a href="https://patrick.sirref.org/part-ii/">Part II projects</a> to <a href="https://patrick.sirref.org/focs/">supervisions</a>. Going into next (academic) year, I intend to reduce my in-person teaching to focus on my research. However, I am interested in producing more materials for learning, maybe some of this in OCaml, perhaps something similar to <a href="https://beautifulracket.com/">Beautiful Racket</a>. I have tried in the past to do these sorts of things, for example <a href="https://patricoferris.github.io/irmin-book/">The Irmin Book</a>.</p>
        </section>
        <section>
          <header>
            <h2>Thank you</h2>
          </header>
          <p>Thank you for reading this wrap up! And thank you again to <a href="https://patrick.sirref.org/tarides/">Tarides</a> for letting me work so freely on things that I think are good for the OCaml community.</p>
        </section>
      </div>
    </content>
  </entry>
  <entry>
    <title>OCaml Weekly 2025 w29</title>
    <published>2025-07-15T00:00:00-00:00</published>
    <updated>2025-07-15T00:00:00-00:00</updated>
    <author>
      <name>https://patrick.sirref.org/Patrick Ferris/</name>
      <uri>https://patrick.sirref.org/Patrick%20Ferris/</uri>
    </author>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/ocaml-weekly-2025-w29/" />
    <id>https://patrick.sirref.org/ocaml-weekly-2025-w29/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <section>
          <header>
            <h2>Ppxlib</h2>
          </header>
          <p>I met with <a href="https://patrick.sirref.org/nathanreb/">Nathan</a> this week to discuss future plans for <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a>. The current state of affairs is that <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> is becoming unmaintainable. This is primarily a knock-on effect from changes being made to OCaml's parsetree (e.g. labelled tuples being added in 5.4). <a href="https://patrick.sirref.org/nathanreb/">Nathan</a> has a plan that will provide two key properties.</p>
          <ol>
            <li>
              <p>Migrations, which allow old compilers to be used with new <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> releases, will be more compatible. For example, we will be able to migrate new features downwards and back up without raising an error.</p>
            </li>
            <li>
              <p>Ppx authors will be able to use new features in an opt-in workflow, rather than <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> bumping the internal AST (like we did <a href="https://patrick.sirref.org/ppxlib-5-2/">in ppxlib.0.36.0</a>). This will reduce the maintenance burden significantly whilst still allowing users to write ppxes for new OCaml features.</p>
            </li>
          </ol>
          <p>I also started looking into some older issues in <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> related to performance. This is work-in-progress, but I am trying to improve the performance of some passes done by <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a>. To better understand what was making <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> slow, I wanted to use <a href="https://github.com/tarides/runtime_events_tools">runtime_events_tools</a> but I was dismayed to see it wanting to install over 100 packages! I <a href="https://github.com/tarides/runtime_events_tools/pull/57">opened a PR to reduce the number of packages</a>. I think this kind of work goes a little unrecognised as it is not very glamorous. However, I think it really benefits the OCaml community in the long run.</p>
        </section>
        <section>
          <header>
            <h2>Outreachy</h2>
          </header>
          <p>In <a href="https://patrick.sirref.org/outreachy/">Outreachy</a> news, we had a wonderful mid-internship video call with all the interns and mentors to catch-up on how everyone is getting along. Seeing the progress everyone has made was great! I am very grateful for the work that <a href="https://patrick.sirref.org/mdales/">Michael</a> and <a href="https://github.com/gridbugs">Steve</a> have put in so far to make this a very successful Outreachy round for OCaml.</p>
          <p>In sadder news, an email was shared with all <a href="https://patrick.sirref.org/outreachy/">Outreachy</a> mentors detailing the increasingly critical financial situation the project finds itself in. There are ongoing discussions about how costs can be cut including potentially only running a single round a year.</p>
        </section>
        <section>
          <header>
            <h2>Graft</h2>
          </header>
          <p>With the release of <a href="https://patrick.sirref.org/Forester/">Forester.5.0</a>, I made a plan to make a release of <a href="https://patrick.sirref.org/Graft/">Graft.0.1</a>. Unfortunately this is blocked by a new release of <a href="https://github.com/ocaml/opam-repository/pull/28172">hilite</a>, a tool I built for doing build-time syntax highlighting for OCaml code. This powers the syntax highlighting on <a href="https://ocaml.org/">ocaml.org</a>.</p>
        </section>
      </div>
    </content>
  </entry>
  <entry>
    <title>Opentrace</title>
    <published>2025-05-19T00:00:00-00:00</published>
    <updated>2025-05-19T00:00:00-00:00</updated>
    <author>
      <name>https://patrick.sirref.org/Patrick Ferris/</name>
      <uri>https://patrick.sirref.org/Patrick%20Ferris/</uri>
    </author>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/open-trace/" />
    <id>https://patrick.sirref.org/open-trace/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>Thanks to <a href="https://github.com/koonwen/">Koonwen's</a> excellent <a href="https://github.com/koonwen/ocaml-libbpf">libbpf bindings in OCaml</a>, I have been building a little tool called <code>opentrace</code> to make it easier to track an executable's inputs and outputs.</p>
        <p>This work was inspired my <a href="https://patrick.sirref.org/mdales/">Michael's</a> self-proclaimed "gross hack": <a href="https://github.com/quantifyearth/pyshark">pyshark</a>. Whilst pyshark achieves its goals by injecting code into commonly used python objects and methods, <a href="https://patrick.sirref.org/opentrace/">opentrace</a> uses <a href="https://ebpf.io/">eBPF</a>. By using a lower-level API (hooks in the kernel), <a href="https://patrick.sirref.org/opentrace/">opentrace</a> can remain programming language agnostic. However, less information is none about the user's intent compared to something like pyshark.</p>
        <section>
          <header>
            <h2>Monitoring the System</h2>
          </header>
          <p><a href="https://patrick.sirref.org/opentrace/">opentrace</a> has an <code>all</code> command that will trace the entire system.</p>
          <pre><![CDATA[$ sudo opentrace all --flags=O_WRONLY
pid,cgid,comm,kind,flags,mode,filename,return
16324,4417,".nheko-wrapped",openat,577,438,"/home/patrick/.cache/nheko/nheko/curl_alt_svc_cache.txt",47
16324,4417,".nheko-wrapped",openat,193,33188,"/home/patrick/.cache/nheko/nheko/cr3ZUHqBErIOe3PlwJ1SuU8zFKKxL12VzrRoHYMH.tmp",47
16324,4417,".nheko-wrapped",openat,577,438,"/home/patrick/.cache/nheko/nheko/curl_alt_svc_cache.txt",47
16324,4417,".nheko-wrapped",openat,193,33188,"/home/patrick/.cache/nheko/nheko/QfZTdZSuC56NdcDQ3aMxJc3BhMhAj8PmtYW1zFDP.tmp",47
2530,4235,"systemd",openat,524865,438,"/sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/app.slice/gammastep.service/cgroup.subtree_control",41
2530,4235,"systemd",openat,524545,0,"/sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/app.slice/gammastep.service/memory.min",41
2530,4235,"systemd",openat,524545,0,"/sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/app.slice/gammastep.service/memory.low",41
2530,4235,"systemd",openat,524545,0,"/sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/app.slice/gammastep.service/memory.high",41
2530,4235,"systemd",openat,524545,0,"/sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/app.slice/gammastep.service/memory.max",41]]></pre>
          <p>The <code>--flags=O_WRONLY</code> argument filters the events where the <code>O_WRONLY</code> flag was set in the call to <code>open</code>.</p>
          <p>We also get the name of the current executable linked to the task (<code>comm</code>). The <code>-wrapped</code> is an artefact of using Nix.</p>
        </section>
        <section>
          <header>
            <h2>Tracing an Executable</h2>
          </header>
          <p>The primary use case for this tool is to inspect what files your program might be reading and writing.</p>
          <pre><![CDATA[$ sudo opentrace exec --format=json --flags=O_CREAT -- opam list
$ cat trace.json | jq ".[] | .fname"
"/home/patrick/.opam/cshell/.opam-switch/packages/cache"
"/home/patrick/.opam/log/log-118747-29da3d.out"
"/home/patrick/.opam/log/log-118747-29da3d.err"
"/home/patrick/.opam/log/log-118747-29da3d.env"
"/home/patrick/.opam/log/log-118747-29da3d.info"]]></pre>
          <p>The "flags" argument can specify a small boolean formula for checking the open flags of a particular event with <code>|</code> (or), <code>&amp;</code> (and), and <code>~</code> (not). Parentheses can be used for precedence.</p>
          <pre><![CDATA[$ sudo opentrace exec --flags="O_WRONLY|O_RDONLY" -- ocaml --version]]></pre>
        </section>
        <section>
          <header>
            <h2>Spawning Subprocesses</h2>
          </header>
          <p>One feature <a href="https://patrick.sirref.org/opentrace/">opentrace</a> needs (in this proof-of-concept phase) is the ability to also trace subprocesses.</p>
          <p><a href="https://patrick.sirref.org/opentrace/">opentrace</a> is primarily an eBPF program that is loaded into the kernel and communicates with an OCaml program. Events are communicated via a ring buffer and most of the post-processing happens in OCaml. To capture subprocesses, <a href="https://patrick.sirref.org/opentrace/">opentrace</a> creates a new control group (cgroup) and places the new process into that group. This gives <a href="https://patrick.sirref.org/opentrace/">opentrace</a> a new identifier to track, namely the cgroup.</p>
          <p>So consider the following program.</p>
          <pre class="hilite">
            <code>
              <span class="ocaml-keyword-other">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-unit"><![CDATA[()]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-constant-language-capital-identifier">Eio_posix</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">run</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">@@</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other">fun</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">env</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-constant-language-capital-identifier">Eio</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">Path</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source">save</span>
              <span class="ocaml-source"> ~</span>
              <span class="ocaml-source">create</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-constant-language-polymorphic-variant">`Or_truncate</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-numeric-octal-integer">0o664</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source">env</span>
              <span class="ocaml-keyword-other">#</span>
              <span class="ocaml-source">fs</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">/</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">hello.txt</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">hello</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-constant-language-capital-identifier">Eio</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">Process</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">run</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">env</span>
              <span class="ocaml-keyword-other">#</span>
              <span class="ocaml-source">process_mgr</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">    </span>
              <span class="ocaml-source"><![CDATA[[]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">/bin/bash</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">-c</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">echo 'heya' &gt; heya.txt</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[]]]></span>
              <span class="ocaml-source">
</span>
            </code>
          </pre>
          <p>It first creates a file using direct calls to functions like <code>openat</code>. Then it spawns a process which creates a new file called <code>heya.txt</code>. This happens in a separate process. However, with the <code>--cgroups</code> flag we can capture both interactions with the operating system.</p>
          <pre><![CDATA[$ sudo opentrace exec --cgroups --flags="O_CREAT|O_TRUNC" ./main.exe
pid,cgid,comm,kind,flags,mode,filename,return
153187,530807,"main.exe",openat,526914,436,"hello.txt",5
153192,530807,"bash",openat,577,438,"heya.txt",3]]></pre>
          <section>
            <header>
              <h3>Eio's Process API</h3>
            </header>
            <p>I have used the <code>Eio_unix</code> <a href="https://ocaml.org/p/eio/latest/doc/Eio_unix/Process/index.html">fork action process API</a> to be able to extend what happens in the child process. Loading most eBPF programs into the kernel requires special privileges hence the need for <code>sudo</code>. When a user requests for a particular program to be executed and traced, <a href="https://patrick.sirref.org/opentrace/">opentrace</a> spawns a process via the Eio Process API. <a href="https://patrick.sirref.org/opentrace/">Opentrace</a> defines a few new so-called "fork actions", little fragments of C code that are run after the call to <code>fork</code> (<code>clone</code>). Most likely this ends with a call to <code>execve</code>, but other calls are possible for example <code>setuid</code> allowing <a href="https://patrick.sirref.org/opentrace/">opentrace</a> to change the user of the child process so it does not run as <code>root</code>. Similarly, this is where (if used) we create the cgroup and place the process into that group.</p>
          </section>
        </section>
        <section>
          <header>
            <h2>Limitations: Io_uring</h2>
          </header>
          <p>Whilst testing <code>opentrace</code> against some of the tools I use nearly daily, I noticed some events were being missed. I tried tracing <a href="https://patrick.sirref.org/forester/">forester</a>, and only the initial read of <code>forest.toml</code> was logged. It dawned on me that the reason for this was that <a href="https://patrick.sirref.org/forester/">forester</a> (via <a href="https://patrick.sirref.org/eio/">eio</a>) was using <a href="https://patrick.sirref.org/io_uring/">io_uring</a> to perform most of the IO. Most attempts to open files were bypassing the open system calls, and instead they were being performed by the kernel after reading a submission request for an <code>openat2</code>-style call!</p>
          <p>This is not news to seasoned, Linux systems programmers. Io_uring <a href="https://blog.0x74696d.com/posts/iouring-and-seccomp/">bypasses <code>SECCOMP</code> filters</a> for exactly the same reasons.</p>
          <pre><![CDATA[$ sudo opentrace exec -- forester build
$ cat trace.csv
pid,cgid,comm,kind,flags,mode,filename,return
155007,535570,"forester",openat,524288,0,"forest.toml",5
155007,535570,"forester",Uring,2621440,0,"",0
155021,535570,"cp",openat,131072,0,"/home/patrick/documents/forest/theme/favicon-32x32.png",4
155007,535570,"forester",Uring,2686976,0,"",0
155007,535570,"iou-wrk-155007",Uring,557634,420,"",0
155007,535570,"iou-wrk-155007",Uring,557634,420,"",0
155007,535570,"iou-wrk-155007",Uring,557634,420,"",0]]></pre>
          <p>It is interesting to note two things here:</p>
          <ol>
            <li>
              <p>We can tell that <a href="https://patrick.sirref.org/forester/">forester</a> reads the configuration file probably using something like <code>In_channel</code> in OCaml (<a href="https://git.sr.ht/~jonsterling/ocaml-forester/tree/7f275290e211db2590b0d715d8fb47fc1de36550/item/lib/frontend/Config.ml#L22">it does</a>).</p>
            </li>
            <li>
              <p>It appears that Uring is performing IO in both worker threads and directly.</p>
            </li>
          </ol>
          <p>The file paths are empty at the moment as I cannot find a clean way to trace openat submission requests into Uring without it sometimes going very wrong. I have tried quite a few methods (e.g. tracing <code>do_filp_open</code>) and at the moment I am tracing <code>io_openat2</code>, but this seems quite brittle, and often the filename is completely garbled, so I do not set it. If anyone has any ideas to trace Io_uring more reliably, I am all ears!</p>
        </section>
      </div>
    </content>
  </entry>
  <entry>
    <title>Try OxCaml</title>
    <published>2025-05-09T00:00:00-00:00</published>
    <updated>2025-05-09T00:00:00-00:00</updated>
    <author>
      <name>https://patrick.sirref.org/Patrick Ferris/</name>
      <uri>https://patrick.sirref.org/Patrick%20Ferris/</uri>
    </author>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/try-oxcaml/" />
    <id>https://patrick.sirref.org/try-oxcaml/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>This week, I have been trying out Janestreet's <a href="https://blog.janestreet.com/oxidizing-ocaml-locality/">Oxidised OCaml</a> (see their <a href="https://patrick.sirref.org/oxcaml-2024/">ICFP paper</a>). This adds a system of <em>modes</em> to OCaml for expressing things like locality.</p>
        <blockquote>
          <p>...we’re introducing a system of modes, which track properties like the locality and uniqueness of OCaml values. Modes allow the compiler to emit better, lower-allocation code, empower users to write safer APIs, and with the advent of multicore, statically guarantee data race freedom—all in a lightweight way that only affects those in need.</p>
        </blockquote>
        <p>For example, you might say:</p>
        <pre class="hilite">
          <code>
            <span class="ocaml-keyword">let</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-entity-name-function-binding">is_empty</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-source"><![CDATA[(]]></span>
            <span class="ocaml-source">s</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-support-type">string</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-keyword-operator">@@</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-source">local</span>
            <span class="ocaml-source"><![CDATA[)]]></span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-keyword-operator">=</span>
            <span class="ocaml-source">
</span>
            <span class="ocaml-source">  </span>
            <span class="ocaml-constant-language-capital-identifier">String</span>
            <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
            <span class="ocaml-source">length</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-source">s</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-keyword-operator">=</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-constant-numeric-decimal-integer">0</span>
            <span class="ocaml-source">
</span>
          </code>
        </pre>
        <p>To get a feel for how this changes the language, you can follow their <a href="https://github.com/janestreet/opam-repository/tree/with-extensions">instructions on their custom opam-repository</a>. Alternatively, you can <a href="https://patrick.sirref.org/oxcaml">give it a go in your browser</a>! This is a full toplevel running with <code>Base</code> installed (which has plenty of OxCaml annotations on Stdlib-like functions).</p>
        <p>Happy OxCamling!</p>
      </div>
    </content>
  </entry>
  <entry>
    <title>A Transpiler from OCaml to Hazel</title>
    <published>2025-05-02T00:00:00-00:00</published>
    <updated>2025-05-02T00:00:00-00:00</updated>
    <author>
      <name>https://patrick.sirref.org/Patrick Ferris/</name>
      <uri>https://patrick.sirref.org/Patrick%20Ferris/</uri>
    </author>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/hazel-of-ocaml/" />
    <id>https://patrick.sirref.org/hazel-of-ocaml/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>Over the past few months, I have been piecing together a transpiler from <a href="https://patrick.sirref.org/hazel/">Hazel</a> to OCaml. This is, in part, to help one of my third-year undergraduate students who is working on <a href="https://patrick.sirref.org/part-ii-hazel/">type error debugging in Hazel</a>.</p>
        <section>
          <header>
            <h2>Typed Holes</h2>
          </header>
          <p><a href="https://patrick.sirref.org/hazel/">Hazel</a> is a <a href="https://patrick.sirref.org/omar-hazel-2017/">functional programming language with typed holes</a>. Holes are pieces of your program that have not yet been filled in. Holes can appear anywhere in your program both as expression or types. Hazel can still evaluate your program in the presence of holes.</p>
          <p>To get a flavour of Hazel, take a regular map function for lists.</p>
          <pre><![CDATA[let map = fun f -> fun xs -> case xs
  | [] => []
  | x :: xs => f (x) :: map(f)(xs) 
end in
map(fun x -> ?)([1, 2, 3])]]></pre>
          <p>The question mark (<code>?</code>) is a hole. The program evaluates to the following expression of type <code><![CDATA[[?]]]></code> (for people more familiar with OCaml types <code>? list</code>).</p>
          <pre><![CDATA[[ ?, ?, ? ]]]></pre>
          <p>Hazel supports <a href="https://patrick.sirref.org/zhao-typeerror-2024/">local type inference</a> but nothing involving unification variables. For example, a simple <code>add_one</code> function in <a href="https://patrick.sirref.org/hazel/">Hazel</a> (<code>fun x -&gt; x + 1</code>) has type <code>? -&gt; Int</code>.</p>
        </section>
        <section>
          <header>
            <h2>From OCaml to Hazel</h2>
          </header>
          <p>The ability to transpile OCaml programs to Hazel programs is motivated by one simple thought: there are more OCaml programs than there are Hazel programs. This could help bootstrap projects by alleviating the need to rewrite boilerplate code (e.g. URI parsing or standard library functions for strings).</p>
          <section>
            <header>
              <h3>A Transformation of Syntax</h3>
            </header>
            <p>Hazel markets itself as an "Elm/ML-like functional programming language". From the previous example of <code>map</code>, it should be apparent just how close to OCaml the language is.</p>
            <p>It turns out that a majority of the transpiler is a <em>transformation of syntax</em>. Take a simple ADT for an arithmetic programming language.</p>
            <pre class="hilite">
              <code>
                <span class="ocaml-keyword-other">type</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">expr</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">  </span>
                <span class="ocaml-keyword-other">|</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">Float</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other">of</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-support-type">float</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">  </span>
                <span class="ocaml-keyword-other">|</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">Add</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other">of</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">expr</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">*</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">expr</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">  </span>
                <span class="ocaml-keyword-other">|</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">Sub</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other">of</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">expr</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">*</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">expr</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">  </span>
                <span class="ocaml-keyword-other">|</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">Mul</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other">of</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">expr</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">*</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">expr</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">  </span>
                <span class="ocaml-keyword-other">|</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">Div</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other">of</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">expr</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">*</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">expr</span>
                <span class="ocaml-source">
</span>
              </code>
            </pre>
            <p>And when we run <a href="https://patrick.sirref.org/hazel_of_ocaml/">hazel_of_ocaml</a> over this OCaml type declaration.</p>
            <pre><![CDATA[type expr =
  + Float(Float)
  + Add((expr, expr))
  + Sub((expr, expr))
  + Mul((expr, expr))
  + Div((expr, expr))
 in ?]]></pre>
            <p>Not much has changed expect some syntax. <a href="https://patrick.sirref.org/hazel/">Hazel</a> does not have a notion of top-level expression so <a href="https://patrick.sirref.org/hazel_of_ocaml/">hazel_of_ocaml</a> wraps the program into one set of value bindings. For the most part, Hazel acts as a subset of the pure, functional part of OCaml. At the time of writing, this subset is fairly limited with no support for modules or labelled records out of the box (there are plenty of development branches with these features).</p>
            <p>If we try out the same <code>map</code> function but written in OCaml and transpiled to Hazel we get.</p>
            <pre class="hilite">
              <code>
                <span class="ocaml-keyword">let</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword">rec </span>
                <span class="ocaml-entity-name-function-binding">map</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">f</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other">function</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">  </span>
                <span class="ocaml-keyword-other">|</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-list"><![CDATA[[]]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">-&gt;</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-list"><![CDATA[[]]]></span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">  </span>
                <span class="ocaml-keyword-other">|</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">x</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">xs</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">-&gt;</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">f</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">x</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">map</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">f</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">xs</span>
                <span class="ocaml-source">
</span>
              </code>
            </pre>
            <p>Which becomes the following hazel program.</p>
            <pre><![CDATA[let map = fun f -> fun x1 -> case x1
  | [] => []
  | x :: xs => f(x) :: map(f)(xs)
end in ?]]></pre>
            <p>We could have a field day discussing the syntax of OCaml and Hazel (parentheses for function arguments, well-scoped cases for pattern-matching, a different arrow for pattern-matching etc.). What would be more interesting is taking a look at how to handle polymorphism in Hazel.</p>
          </section>
          <section>
            <header>
              <h3>Explicit Polymorphism</h3>
            </header>
            <p>Hazel has <em>explicit polymorphism</em>. So far, we have not seen it as we have let the types have holes in them. The <code>map</code> function in OCaml has the following type.</p>
            <pre class="hilite">
              <code>
                <span class="ocaml-keyword-other">val</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">map</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-source"> 
</span>
                <span class="ocaml-source">  </span>
                <span class="ocaml-source"><![CDATA[(]]></span>
                <span class="ocaml-storage-type">'a</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">-&gt;</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-storage-type">'b</span>
                <span class="ocaml-source"><![CDATA[)]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">-&gt;</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-storage-type">'a</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">list</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">-&gt;</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-storage-type">'b</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">list</span>
                <span class="ocaml-source">
</span>
              </code>
            </pre>
            <p>We must remind ourselves (by reading <a href="https://www.craigfe.io/posts/polymorphic-type-constraints">Craig's excellent blogpost on the matter</a>) that in OCaml</p>
            <blockquote>
              <p>... type variables in signatures are implicitly universally-quantified</p>
            </blockquote>
            <p>So in reality, we have that <code>map</code> has the following type.</p>
            <pre><![CDATA[val map : ∀ a b. (a ->  b) -> a list -> b list]]></pre>
            <p>In Hazel, we have to explicitly type our <code>map</code> function to be polymorphic. Not only does this mean the type annotation requires universally quantified type variables, but we must also perform type application wherever we choose to apply the <code>map</code> function (whether that be recursively or somewhere later in our program).</p>
            <pre><![CDATA[let map : forall a -> forall b -> (a -> b) -> [a] -> [b] =
  typfun a -> typfun b -> fun f -> fun xs -> case xs
    | [] => []
    | x :: xs => f (x) :: map@<a>@<b>(f)(xs) 
end in
map@<Int>@<Int>(fun x -> ?)([1, 2, 3])]]></pre>
            <p><code>forall</code> introduces a universally quantified type variable into our type annotation, and <code>typfun</code> introduces it into the function itself (à la System F). Type application requires <code>@&lt;T&gt;</code> where <code>T</code> is some type. This allows hazel to quite easily support higher rank polymorphism, but we will not worry too much about that.</p>
          </section>
          <section>
            <header>
              <h3>Propagating OCaml Types into Hazel</h3>
            </header>
            <p>Most often, OCaml users interact with <em>prenex</em> polymorphism (rank-1) where the universal quantifiers are at the front of the type. <a href="https://ocaml.org/manual/5.2/polymorphism.html#s:higher-rank-poly">OCaml does support quantifiers inside certain types like records</a>.</p>
            <p>What this means for the transpiler is that we can <strong>reuse OCaml's type inference</strong> to safely instantiate the correct type annotations and type applications in Hazel! To do this, <code>hazel_of_ocaml</code> uses <a href="https://ocaml.github.io/merlin/">Merlin</a> to inspect the type of the function in either a value binding or at the point of a function application.</p>
            <p>Take a simple, polymorphic <code>length</code> function.</p>
            <pre class="hilite">
              <code>
                <span class="ocaml-keyword">let</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword">rec </span>
                <span class="ocaml-entity-name-function-binding">length</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other">function</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other">|</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-list"><![CDATA[[]]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">-&gt;</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-integer">0</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other">|</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language">_</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">xs</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">-&gt;</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-integer">1</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">+</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">length</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">xs</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-keyword">let</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-entity-name-function-binding">int_len</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">length</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[[]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-integer">1</span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-integer">2</span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-integer">3</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[]]]></span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-keyword">let</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-entity-name-function-binding">str_len</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">length</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[[]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-string-quoted-double">"</span>
                <span class="ocaml-string-quoted-double">only</span>
                <span class="ocaml-string-quoted-double">"</span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-string-quoted-double">"</span>
                <span class="ocaml-string-quoted-double">two</span>
                <span class="ocaml-string-quoted-double">"</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[]]]></span>
                <span class="ocaml-source">
</span>
              </code>
            </pre>
            <p>When we run this through <code>hazel_of_ocaml</code> with the <code>-type</code> flag we get.</p>
            <pre><![CDATA[let length : forall a -> [a] -> Int = typfun a -> fun x1 -> case x1
  | [] => 0
  | _ :: xs => 1 + length@<a>(xs)
end in
let int_len : Int = length@<Int>(1 :: 2 :: [3]) in
let str_len : Int = length@<String>("only" :: ["two"])
in ?]]></pre>
            <p><code>hazel_of_ocaml</code> has correctly instantiated the type for <code>length</code> inside the recursive function and then in each case with the integer list and the string list.</p>
          </section>
        </section>
        <section>
          <header>
            <h2>A Corpus of Hazel Programs</h2>
          </header>
          <p>The impetus for this work was to derive a corpus of ill-typed Hazel programs. Luckily, such a corpus exists for OCaml! <a href="https://patrick.sirref.org/ocaml-corpus/">Seidel et al.</a> created a corpus of OCaml programs from their undergraduate students at UC San Diego. <a href="https://github.com/patricoferris/hazel-corpus">Some of these programs have been transpiled to Hazel</a>.</p>
        </section>
        <section>
          <header>
            <h2>Future Work</h2>
          </header>
          <p><a href="https://patrick.sirref.org/hazel/">Hazel</a> is a fun, research programming language. Potential third-year students may find it interesting to take this work further. For example, how would this look in terms of a module system? From a purely engineering perspective, plenty of work would be needed to convert a multi-library OCaml project to Hazel (e.g. handling the <code>cmi</code> files).</p>
          <p>Another line of research would be to have Hazel target one of the intermediate representations in OCaml which would give Hazel a fully functioning compiler to "native" code?</p>
        </section>
      </div>
    </content>
  </entry>
  <entry>
    <title>Defunctorising VPNKit</title>
    <published>2025-02-28T00:00:00-00:00</published>
    <updated>2025-02-28T00:00:00-00:00</updated>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/vpnkit-upgrade/" />
    <id>https://patrick.sirref.org/vpnkit-upgrade/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p><a href="https://patrick.sirref.org/vpnkit/">VPNKit</a> is a core part of the Docker for Mac/Windows stack. It is tasked with translating network activity from the host to the Linux container.</p>
        <p>This short post discusses some of the recent changes to MirageOS and how they impact <a href="https://patrick.sirref.org/vpnkit/">VPNKit</a>.</p>
        <section>
          <header>
            <h2>Dune Virtual Libraries</h2>
          </header>
          <p>Dune, for quite some time, has supported <em>virtual libraries</em>. This allows library authors to define a signature without an implementation (similar to OCaml's <code>module type S = struct ... end</code>). The package is something other dune libraries can build against, still without choosing a particular implementation of the interface. An application author can make the decision about which implementation they would like to build into their program.</p>
          <p>This feature has been quite widely used in OCaml. For example, the <a href="https://github.com/mirage/digestif">excellent <code>digestif</code> library</a> of hashing algorithms provides both C and OCaml implementations individually packaged into <code>digestif.c</code> and <code>digestif.ocaml</code> respectively. Consider developing a browser application that needs some hashing algorithm (e.g. <a href="https://github.com/patricoferris/omditor">Irmin in the browser</a>). We can explicitly use the OCaml backend for digestif which <a href="https://github.com/ocsigen/js_of_ocaml">js_of_ocaml</a> will happily compile for us.</p>
          <p>There are two distinct limitations to this approach.</p>
          <ol>
            <li>
              <p>Applications can only link <em>exactly one</em> implementation.</p>
            </li>
            <li>
              <p>Implementations cannot expose additional functionality easily (see <a href="https://github.com/ocaml/dune/issues/5997">dune#5597</a>).</p>
            </li>
          </ol>
        </section>
        <section>
          <header>
            <h2>Functors in MirageOS</h2>
          </header>
          <p><a href="https://mirage.io/">MirageOS</a> is a framework for building unikernels in OCaml. It relies heavily on OCaml's functors to abstract implementation from interface. The mirage tool will then select appropriate instantiations of these functors depending on the backend that is targeted (e.g. <code>unix</code>, <code>hvt</code> etc.)</p>
          <p>Recently, <a href="https://github.com/mirage/mirage-skeleton/pull/407/">there has been a push</a> to use <a href="https://patrick.sirref.org/dune-virt-libs/">dune virtual libraries</a> instead.</p>
        </section>
        <section>
          <header>
            <h2>VPNKit's Fake Clock &amp; Time</h2>
          </header>
          <p>We need to be able to overcome the limitation that implementations cannot expose additional functionality very easily using dune virtual libraries. As it stands, we need to make Mirage's virtual libraries unwrapped (i.e. set <code>(wrapped false)</code>). This allows implementers to expose additional modules alongside the implementation of the virtual library.</p>
          <p>For VPNkit, we need this to port some of the DNS forwarding tests which use a fake clock and sleep module. Previously, they could be provided directly as functor arguments to the various DNS modules e.g.</p>
          <pre class="hilite">
            <code>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword">module</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">R</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-constant-language-capital-identifier">Dns_forward</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">Resolver</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">Make</span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-constant-language-capital-identifier">Proto_client</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-constant-language-capital-identifier">Fake</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">Time</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-constant-language-capital-identifier">Fake</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">Clock</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
            </code>
          </pre>
          <p>In this new world of <a href="https://patrick.sirref.org/dune-virt-libs/">dune virtual libraries</a>, our <code>Resolver</code> is significantly more simple.</p>
          <pre class="hilite">
            <code>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword">module</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">R</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Dns_forward</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">Resolver</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">Make</span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-constant-language-capital-identifier">Proto_client</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">
</span>
            </code>
          </pre>
          <p>The flexibility of time and clock implementation has been pushed to a build-time decision in a dune file. This means that in order to provide the same fake clock and time we will need to create a private dune library that (a) implements the respective signatures of the virtual libraries and (b) provides the extended interface to allow the test suite to modify the internals of the implementations.</p>
          <p>The first thing I had to do was make the <code>mirage-mtime</code> and <code>mirage-sleep</code> virtual libraries unwrapped. This allowed me to make a new private dune library called <code>fake_time</code> with <em>two</em> public modules: the normal interface required by <code>mirage-mtime</code> and another module called <code>Fake_time_state</code> containing:</p>
          <pre class="hilite">
            <code>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-entity-name-function-binding">timeofday</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">ref</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-numeric-decimal-integer">0L</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-entity-name-function-binding">c</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Lwt_condition</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">create</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-unit"><![CDATA[()]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-entity-name-function-binding">advance</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">nsecs</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-source">timeofday</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Int64</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">add</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">!</span>
              <span class="ocaml-source">timeofday</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">nsecs</span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-constant-language-capital-identifier">Lwt_condition</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">broadcast</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">c</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-unit"><![CDATA[()]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-entity-name-function-binding">reset</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-unit"><![CDATA[()]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-source">timeofday</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-numeric-decimal-integer">0L</span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-constant-language-capital-identifier">Lwt_condition</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">broadcast</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">c</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-unit"><![CDATA[()]]></span>
              <span class="ocaml-source">
</span>
            </code>
          </pre>
          <p>I did the same for <code>fake_sleep</code> which depended on the state from the <code>fake_time</code> library (something a normal library wouldn't).</p>
          <p>Once I had the implementations for the virtual libraries in place, all that remained was to tell the executable (in this case the test suite) to select these new implementations instead of the defaults. Whereas before, all the tests could live in the same test suite, now they had to be split into those that needed the fake implementation and those that did not. This is another slight limitation of this virtual library approach. You can only link one implementation at a time to an executable (or test). Thus, the dune rules for running the <code>dns_forward</code> test suite became:</p>
          <pre class="hilite">
            <code>
              <span class="dune-comment-line">; Uses the default  implementations provided by virtual libraries</span>
              <span class="dune-source">
</span>
              <span class="dune-meta-stanza"><![CDATA[(]]></span>
              <span class="dune-meta-class-stanza">executable</span>
              <span class="dune-meta-stanza">
</span>
              <span class="dune-meta-stanza"> </span>
              <span class="dune-meta-stanza-library-field"><![CDATA[(]]></span>
              <span class="dune-keyword-other">name</span>
              <span class="dune-meta-stanza-library-field"> </span>
              <span class="dune-meta-atom">test</span>
              <span class="dune-meta-stanza-library-field"><![CDATA[)]]></span>
              <span class="dune-meta-stanza">
</span>
              <span class="dune-meta-stanza"> </span>
              <span class="dune-meta-stanza-lib-or-exec-buildable"><![CDATA[(]]></span>
              <span class="dune-keyword-other">libraries</span>
              <span class="dune-meta-stanza-lib-or-exec-buildable"> </span>
              <span class="dune-meta-atom">dns_forward</span>
              <span class="dune-meta-stanza-lib-or-exec-buildable"> </span>
              <span class="dune-meta-atom">alcotest</span>
              <span class="dune-meta-stanza-lib-or-exec-buildable"><![CDATA[)]]></span>
              <span class="dune-meta-stanza"><![CDATA[)]]></span>
              <span class="dune-source">
</span>
              <span class="dune-source">
</span>
              <span class="dune-comment-line">; Override the defaults and select the private fake libraries</span>
              <span class="dune-source">
</span>
              <span class="dune-meta-stanza"><![CDATA[(]]></span>
              <span class="dune-meta-class-stanza">executable</span>
              <span class="dune-meta-stanza">
</span>
              <span class="dune-meta-stanza">  </span>
              <span class="dune-meta-stanza-library-field"><![CDATA[(]]></span>
              <span class="dune-keyword-other">name</span>
              <span class="dune-meta-stanza-library-field"> </span>
              <span class="dune-meta-atom">test_fake</span>
              <span class="dune-meta-stanza-library-field"><![CDATA[)]]></span>
              <span class="dune-meta-stanza">
</span>
              <span class="dune-meta-stanza">  </span>
              <span class="dune-meta-stanza-lib-or-exec-buildable"><![CDATA[(]]></span>
              <span class="dune-keyword-other">libraries</span>
              <span class="dune-meta-stanza-lib-or-exec-buildable"> </span>
              <span class="dune-meta-atom">dns_forward</span>
              <span class="dune-meta-stanza-lib-or-exec-buildable"> </span>
              <span class="dune-meta-atom">alcotest</span>
              <span class="dune-meta-stanza-lib-or-exec-buildable"> </span>
              <span class="dune-meta-atom">fake_sleep</span>
              <span class="dune-meta-stanza-lib-or-exec-buildable"> </span>
              <span class="dune-meta-atom">fake_time</span>
              <span class="dune-meta-stanza-lib-or-exec-buildable"><![CDATA[)]]></span>
              <span class="dune-meta-stanza"><![CDATA[)]]></span>
              <span class="dune-source">
</span>
            </code>
          </pre>
          <p>With all of this machinery in place, I could now update <code>test_fake</code> to use the new modules that would provide the custom functionality for the clock and time implementations.</p>
          <pre class="hilite">
            <code>
              <span class="ocaml-comment-block"><![CDATA[(*]]></span>
              <span class="ocaml-comment-block"> The bad server should be marked offline and no-one will wait for it </span>
              <span class="ocaml-comment-block"><![CDATA[*)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-constant-language-capital-identifier">Fake_time_state</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">reset</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-unit"><![CDATA[()]]></span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-comment-block"><![CDATA[(*]]></span>
              <span class="ocaml-comment-block"> avoid the timeouts winning the race with the actual result </span>
              <span class="ocaml-comment-block"><![CDATA[*)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-constant-language-capital-identifier">Fake_time_state</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">advance</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Duration</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source">of_ms</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-numeric-decimal-integer">500</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source"> 
</span>
            </code>
          </pre>
        </section>
        <section>
          <header>
            <h2>Conclusion</h2>
          </header>
          <p>The switch to <a href="https://patrick.sirref.org/dune-virt-libs/">dune virtual libraries</a> seems to be a good one. A majority of applications only require a single clock or time implementation. However, it has become harder to inject custom implementations of various resources into your MirageOS-based applications.</p>
          <p>The <a href="https://github.com/moby/vpnkit/pull/646">pull request to upgrade VPNKit is open</a>.</p>
        </section>
      </div>
    </content>
  </entry>
  <entry>
    <title>Bumping Ppxlib's AST to 5.2</title>
    <published>2025-02-18T00:00:00-00:00</published>
    <updated>2025-02-18T00:00:00-00:00</updated>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/ppxlib-5-2/" />
    <id>https://patrick.sirref.org/ppxlib-5-2/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p><a href="https://patrick.sirref.org/ppxlib/">Ppxlib</a> is a libary for building OCaml preprocessors. Users can generate OCaml code <em>from</em> OCaml code (derivers) or replace parts of OCaml code with other OCaml code (rewriters).</p>
        <p>At the core of <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> is the OCaml parsetree; a data structure in the compiler that represents OCaml source code. <a href="https://patrick.sirref.org/ppxlib/">Ppxlib</a> makes a distinction between the source parsetree (based on the version of the OCaml compiler you are using) and <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a>'s parsetree (a copy of <em>some</em> parsetree from the compiler).</p>
        <p>In <a href="https://discuss.ocaml.org/t/ann-ppxlib-0-36-0">ppxlib.0.36.0</a>, the internal AST was bumped from the AST of OCaml 4.14.0, to the AST of OCaml 5.2.0. This post discusses some of the internal mechanisms that allows ppxlib to support multiple compilers and how this bump broke a lot of backwards compatibility.</p>
        <section>
          <header>
            <h2>Manual Migrations in Ppxlib</h2>
          </header>
          <p>It is possible to perform migrations between parsetrees manually using the <code>ppxlib.ast</code> package.</p>
          <pre class="hilite">
            <code>
              <span class="ocaml-keyword-other">open</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Ppxlib</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword-other">open</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Ast_builder</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">Make</span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-keyword-other">struct</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-entity-name-function-binding">loc</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Location</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">none</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other">end</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-entity-name-function-binding">pp_expr</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Format</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">printf</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-constant-character-printf"><![CDATA[%a]]></span>
              <span class="ocaml-constant-character-printf"><![CDATA[%!]]></span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Pp_ast</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source">expression</span>
              <span class="ocaml-source"> ?</span>
              <span class="ocaml-source">config</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-constant-language-capital-identifier">None</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-entity-name-function-binding">loc</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Location</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">none</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-entity-name-function-binding">str</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">txt</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[{]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">txt</span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">loc</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[}]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword-other">module</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">To_408</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> 
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-constant-language-capital-identifier">Ppxlib_ast</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">Convert</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-constant-language-capital-identifier">Ppxlib_ast</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">Js</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-constant-language-capital-identifier">Ppxlib_ast__</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">Versions</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">OCaml_408</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
            </code>
          </pre>
          <p>The <code>Ppxlib_ast.Js</code> module is <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a>'s AST (since <code>ppxlib.0.36.0</code> OCaml 5.2.0). We can use functions provided by the <code>Convert</code> functor to copy parts of the AST from one version to another. Usually there is very little difference between the versioned parsetrees.</p>
          <pre class="hilite">
            <code>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-entity-name-function-binding">func</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">arg</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">body</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-source">pexp_fun</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Nolabel</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">None</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source">ppat_var</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source">str</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">arg</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">body</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-entity-name-function-binding">add_expr</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">func</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">x</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source">func</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">y</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source">eapply</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source">evar</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">Int.add</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[[]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">evar</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">x</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">evar</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">y</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[]]]></span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
            </code>
          </pre>
          <p>The above excerpt of OCaml code produces an expression in the language. More accurately, a function that has two arguments. If we print the simplified AST we can see that the arguments are stored together in a list.</p>
          <pre class="hilite">
            <code>
              <span class="ocaml-mdx-hash">#</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">pp_expr</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">add_expr</span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source"> 
</span>
              <span class="ocaml-constant-language-capital-identifier">Pexp_function</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[[]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[{]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">pparam_loc</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">__loc</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">      </span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">pparam_desc</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Pparam_val</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Nolabel</span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">None</span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Ppat_var</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">x</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">      </span>
              <span class="ocaml-source"><![CDATA[}]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">    </span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[{]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">pparam_loc</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">__loc</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">      </span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">pparam_desc</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Pparam_val</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Nolabel</span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">None</span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Ppat_var</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">y</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">      </span>
              <span class="ocaml-source"><![CDATA[}]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">    </span>
              <span class="ocaml-source"><![CDATA[]]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">None</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Pfunction_body</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">      </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-constant-language-capital-identifier">Pexp_apply</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">         </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Pexp_ident</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-constant-language-capital-identifier">Ldot</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Lident</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">Int</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">add</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">         </span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[[]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Nolabel</span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Pexp_ident</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-constant-language-capital-identifier">Lident</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">x</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">           </span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Nolabel</span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Pexp_ident</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-constant-language-capital-identifier">Lident</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">y</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">           </span>
              <span class="ocaml-source"><![CDATA[]]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">         </span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword-operator">-</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-support-type">unit</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-unit"><![CDATA[()]]></span>
              <span class="ocaml-source">
</span>
            </code>
          </pre>
          <p>This is a relatively new feature of the parsetree, if we migrate the expression down to <code>4.08</code> we see it is represented differently. The output is a little too verbose to be readable, and there's no good way to show the AST, so you will just have to take my word.</p>
          <pre class="hilite">
            <code>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-entity-name-function-binding">expr_408</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">To_408</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">copy_expression</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">add_expr</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">
</span>
            </code>
          </pre>
        </section>
        <section>
          <header>
            <h2>Function Arity in the OCaml Parsetree</h2>
          </header>
          <p>OCaml 5.2 introduced a new way to represent functions. Before 5.2, all functions were represented with single arity. Functions with multiple arguments would return functions as their body. For example:</p>
          <pre class="hilite">
            <code>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-entity-name-function-binding">add</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">x</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">y</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">x</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">+</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">y</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">
</span>
            </code>
          </pre>
          <p>A two-argument <code>add</code> function would be represented in the parsetree as <code>fun x -&gt; fun y -&gt; x + y</code>. Using the nodes from the parsetree (with some details removed) it would be <code>Pexp_fun (x, Pexp_fun (y, Pexp_apply ...))</code>.</p>
          <p>Now, since OCaml 5.2, functions can be expressed with their syntactic arity intact. The function <code>add</code> would look something like <code><![CDATA[Pexp_function ([ x; y ], Pfunction_body (Pexp_apply ...))]]></code>. Both arguments are stored as a list.</p>
          <p>The constructor <code>Pexp_function</code> was not a new addition to the parsetree. It used to represent pattern-matching expressions like <code>function A -&gt; 1</code>. This can now be expressed as a function body of <code>Pfunction_cases</code>.</p>
          <p>Whilst these additions and modifications to the parsetree are arguably a better design, it has caused chaos in terms of <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a>'s reverse dependencies!</p>
        </section>
        <section>
          <header>
            <h2>Coalescing Function Arguments</h2>
          </header>
          <p>In <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> <code>0.36.0</code>, functions from <code>Ast_builder</code> will help ppx authors produce maximum arity functions. However, functions from <code>Ast_helper</code> will not do this.</p>
          <pre class="hilite">
            <code>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-entity-name-function-binding">ast_helper_func</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">arg</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">body</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-constant-language-capital-identifier">Ast_helper</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">Exp</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">fun_</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Nolabel</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">None</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source">ppat_var</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source">str</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">arg</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">body</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-entity-name-function-binding">ast_helper_expr</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">ast_helper_func</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">x</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source">ast_helper_func</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">y</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source">eapply</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source">evar</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">Int.equal</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[[]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">evar</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">x</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">evar</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">y</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[]]]></span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
            </code>
          </pre>
          <p>Here we recreate our helper function to create function expressions using <code>Ast_helper.Exp.fun_</code> instead. We can now show the difference between the <code>expr</code> expression and the <code>ast_helper_expr</code> expression.</p>
          <pre class="hilite">
            <code>
              <span class="ocaml-mdx-hash">#</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">pp_expr</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">add_expr</span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-constant-language-capital-identifier">Pexp_function</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[[]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[{]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">pparam_loc</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">__loc</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">      </span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">pparam_desc</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Pparam_val</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Nolabel</span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">None</span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Ppat_var</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">x</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">      </span>
              <span class="ocaml-source"><![CDATA[}]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">    </span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[{]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">pparam_loc</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">__loc</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">      </span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">pparam_desc</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Pparam_val</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Nolabel</span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">None</span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Ppat_var</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">y</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">      </span>
              <span class="ocaml-source"><![CDATA[}]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">    </span>
              <span class="ocaml-source"><![CDATA[]]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">None</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Pfunction_body</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">      </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-constant-language-capital-identifier">Pexp_apply</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">         </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Pexp_ident</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-constant-language-capital-identifier">Ldot</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Lident</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">Int</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">add</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">         </span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[[]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Nolabel</span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Pexp_ident</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-constant-language-capital-identifier">Lident</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">x</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">           </span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Nolabel</span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Pexp_ident</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-constant-language-capital-identifier">Lident</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">y</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">           </span>
              <span class="ocaml-source"><![CDATA[]]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">         </span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword-operator">-</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-support-type">unit</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-unit"><![CDATA[()]]></span>
              <span class="ocaml-source">
</span>
            </code>
          </pre>
          <p>Above, we see a function expression with arity <em>two</em>. Below, we see nested function expressions each with arity <em>one</em>.</p>
          <pre class="hilite">
            <code>
              <span class="ocaml-mdx-hash">#</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">pp_expr</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">ast_helper_expr</span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-constant-language-capital-identifier">Pexp_function</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[[]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[{]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">pparam_loc</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">__loc</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">      </span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">pparam_desc</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Pparam_val</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Nolabel</span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">None</span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Ppat_var</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">x</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">      </span>
              <span class="ocaml-source"><![CDATA[}]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">    </span>
              <span class="ocaml-source"><![CDATA[]]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">None</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Pfunction_body</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">      </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-constant-language-capital-identifier">Pexp_function</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">         </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[[]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[{]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">pparam_loc</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">__loc</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">             </span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">pparam_desc</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Pparam_val</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Nolabel</span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">None</span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Ppat_var</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">y</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">             </span>
              <span class="ocaml-source"><![CDATA[}]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">           </span>
              <span class="ocaml-source"><![CDATA[]]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">         </span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">None</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">         </span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Pfunction_body</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">             </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-constant-language-capital-identifier">Pexp_apply</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">                </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Pexp_ident</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-constant-language-capital-identifier">Ldot</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Lident</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">Int</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">equal</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">                </span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[[]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Nolabel</span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Pexp_ident</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-constant-language-capital-identifier">Lident</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">x</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">                  </span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Nolabel</span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Pexp_ident</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-constant-language-capital-identifier">Lident</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">y</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">                  </span>
              <span class="ocaml-source"><![CDATA[]]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">                </span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">         </span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword-operator">-</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-support-type">unit</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-unit"><![CDATA[()]]></span>
              <span class="ocaml-source">
</span>
            </code>
          </pre>
        </section>
        <section>
          <header>
            <h2>Ramifications for Ppxlib Users</h2>
          </header>
          <p>Many, many, <em>many</em> ppxes broke after migrating the <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> AST to 5.2. Mostly, this is due to pattern-matching. Downstream users of <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> frequently pattern-match directly against the parsetree. However, nodes such as <code>Pexp_fun</code> no longer exist and <code>Pexp_function</code> has completely different constructor arguments!</p>
          <p>Patching all the ppxes has been quite difficult. Most ppxes only deal with single arguments at a time (e.g. <code>Pexp_fun x</code>) but now they must handle zero or more arguments at a time. (In the zero case, this will always correspond to a pattern-matching <code>function</code>).</p>
          <p>Here is a non-exhaustive list of some of the ppxes that have been patched. It may useful for other ppx authors who wish to upgrade to <code>ppxlib.0.36.0</code>:</p>
          <ul>
            <li>
              <p>
                <a href="https://github.com/patricoferris/ppx_deriving_yaml/pull/58">https://github.com/patricoferris/ppx_deriving_yaml/pull/58</a>
              </p>
            </li>
            <li>
              <p>
                <a href="https://github.com/mirage/ocaml-rpc/pull/181">https://github.com/mirage/ocaml-rpc/pull/181</a>
              </p>
            </li>
            <li>
              <p>
                <a href="https://gitlab.com/o-labs/ppx_deriving_jsoo/-/merge_requests/1">https://gitlab.com/o-labs/ppx_deriving_jsoo/-/merge_requests/1</a>
              </p>
            </li>
            <li>
              <p>
                <a href="https://github.com/ocaml-community/sedlex/pull/160">https://github.com/ocaml-community/sedlex/pull/160</a>
              </p>
            </li>
            <li>
              <p>
                <a href="https://github.com/ocaml-sys/config.ml/pull/22">https://github.com/ocaml-sys/config.ml/pull/22</a>
              </p>
            </li>
            <li>
              <p>
                <a href="https://github.com/vogler/ppx_distr_guards/pull/2">https://github.com/vogler/ppx_distr_guards/pull/2</a>
              </p>
            </li>
            <li>
              <p>
                <a href="https://github.com/ocaml-gospel/gospel/pull/424">https://github.com/ocaml-gospel/gospel/pull/424</a>
              </p>
            </li>
            <li>
              <p>
                <a href="https://github.com/teamwalnut/graphql-ppx/pull/299">https://github.com/teamwalnut/graphql-ppx/pull/299</a>
              </p>
            </li>
            <li>
              <p>
                <a href="https://github.com/ocsigen/lwt/pull/1033">https://github.com/ocsigen/lwt/pull/1033</a>
              </p>
            </li>
            <li>
              <p>
                <a href="https://gitlab.com/gopiandcode/ppx-inline-alcotest/-/merge_requests/3">https://gitlab.com/gopiandcode/ppx-inline-alcotest/-/merge_requests/3</a>
              </p>
            </li>
            <li>
              <p>
                <a href="https://github.com/dariusf/ppx_interact/pull/3">https://github.com/dariusf/ppx_interact/pull/3</a>
              </p>
            </li>
            <li>
              <p>
                <a href="https://github.com/ocaml-ppx/ppx_deriving_yojson/pull/160">https://github.com/ocaml-ppx/ppx_deriving_yojson/pull/160</a>
              </p>
            </li>
            <li>
              <p>
                <a href="https://github.com/lpcic/elpi/pull/276">https://github.com/LPCIC/elpi/pull/276</a>
              </p>
            </li>
            <li>
              <p>
                <a href="https://github.com/mirage/repr/pull/110">https://github.com/mirage/repr/pull/110</a>
              </p>
            </li>
            <li>
              <p>
                <a href="https://github.com/programingisthefuture/ppx_default/pull/3">https://github.com/ProgramingIsTheFuture/ppx_default/pull/3</a>
              </p>
            </li>
            <li>
              <p>
                <a href="https://github.com/codinuum/vlt/pull/3">https://github.com/codinuum/vlt/pull/3</a>
              </p>
            </li>
            <li>
              <p>
                <a href="https://github.com/sim642/ppx_deriving_hash/pull/6">https://github.com/sim642/ppx_deriving_hash/pull/6</a>
              </p>
            </li>
            <li>
              <p>
                <a href="https://github.com/ocsigen/tyxml/pull/340">https://github.com/ocsigen/tyxml/pull/340</a>
              </p>
            </li>
            <li>
              <p>
                <a href="https://github.com/sim642/ppx_viewpattern/pull/2">https://github.com/sim642/ppx_viewpattern/pull/2</a>
              </p>
            </li>
            <li>
              <p>
                <a href="https://github.com/little-arhat/ppx_jsobject_conv/pull/11">https://github.com/little-arhat/ppx_jsobject_conv/pull/11</a>
              </p>
            </li>
            <li>
              <p>
                <a href="https://github.com/robur-coop/lun/pull/1">https://github.com/robur-coop/lun/pull/1</a>
              </p>
            </li>
            <li>
              <p>
                <a href="https://gitlab.com/o-labs/ppx_deriving_encoding/-/merge_requests/4">https://gitlab.com/o-labs/ppx_deriving_encoding/-/merge_requests/4</a>
              </p>
            </li>
            <li>
              <p>
                <a href="https://github.com/francoisthire/bam/pull/12">https://github.com/francoisthire/bam/pull/12</a>
              </p>
            </li>
            <li>
              <p>
                <a href="https://github.com/xguerin/bitstring/pull/36">https://github.com/xguerin/bitstring/pull/36</a>
              </p>
            </li>
          </ul>
          <p>This release has emphasised the tension between using pattern-matching on algebraic datatypes and wanting to reduce downstream breakages (e.g. using abstract datatypes). This <a href="https://www.cambridge.org/core/journals/journal-of-functional-programming/article/pattern-matching-with-abstract-data-types1/04DD26A0E6CA3A1E87E0E6AE8BC02EED">tension is not new</a>.</p>
        </section>
        <section>
          <header>
            <h2>The Future of Ppxlib</h2>
          </header>
          <p><a href="https://patrick.sirref.org/ppxlib/">Ppxlib</a> is not going anywhere anytime soon. We have committed to trying to keep the internal AST up to date with the latest OCaml release. In fact, there is already a PR for <a href="https://github.com/ocaml-ppx/ppxlib/pull/558">the 5.3 bump</a>!</p>
          <p>There have been many discussions about simplifying this process, but so far the time and effort to build a <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> that will result in fewer breakages is too high (see <a href="https://github.com/ocaml-ppx/ppx">an attempt using views</a>).</p>
          <p>Thank you to Tarides and Jane Street for funding my time to work on this release and all the chaos it has caused.</p>
          <p>Happy preprocessing!</p>
        </section>
      </div>
    </content>
  </entry>
  <entry>
    <title>Reviving OCaml R-Tree</title>
    <published>2023-08-09T00:00:00-00:00</published>
    <updated>2023-08-09T00:00:00-00:00</updated>
    <author>
      <name>https://patrick.sirref.org/Patrick Ferris/</name>
      <uri>https://patrick.sirref.org/Patrick%20Ferris/</uri>
    </author>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/ocaml-rtree/" />
    <id>https://patrick.sirref.org/ocaml-rtree/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>Antonin Guttman <a href="http://www-db.deis.unibo.it/courses/SI-LS/papers/Gut84.pdf">first proposed R-Trees in 1984</a>.</p>
        <blockquote>
          <p>In order to handle spatial data efficiently, as required in computer aided design and geo-data applications, a database system needs an index mechanism that will help it retrieve data items quickly according to their spatial locations...</p>
        </blockquote>
        <p>There are lots of excellent resources for understanding more about R-Trees and all of the wonderful variations there of (e.g. <a href="http://www.cs.ucr.edu/~ravi/CS236Papers/rstar.pdf">R*-trees</a>). This <a href="https://www.bartoszsypytkowski.com/r-tree/">blog post</a> seems to be the most popular introduction.</p>
        <section>
          <header>
            <h2>An OCaml Rtree Implementation</h2>
          </header>
          <p>In the <a href="https://www.cst.cam.ac.uk/research/eeg">Energy and Environment Group</a> we are working on various geospatial tools, one of which is written in OCaml and needed a geospatial index to speedup spatial queries over a dataset. Searching Github revealed <a href="https://github.com/mariusae/ocaml-rtree">an implementation in pure OCaml</a>. After reaching out to the author, they were more than happy for their work to be maintained in the <a href="https://github.com/geocaml">Geocaml organisation</a>, updated to the latest OCaml tools and <a href="https://github.com/ocaml/opam-repository/pull/24227">hopefully released on opam</a>.</p>
          <p>The <a href="https://github.com/geocaml/ocaml-rtree/commit/073d79ad34de15f0671f2faafb24b1edc5c2d8c7">dunification</a> went smoothly whilst fast-forwarding 15 OCaml compiler versions with no changes or problems (just dune unused variable warnings).</p>
        </section>
        <section>
          <header>
            <h2>OCaml Rtree Examples</h2>
          </header>
          <p>An R-Tree in OCaml is created from an envelope (the kind of bounding box) and a value (for storing in the tree). The value depends on the envelope as you have to provide a function to calculate an envelope from a value. Here is one way we might define a line using the provided two-dimensional <code>Rectangle</code> envelope.</p>
          <pre class="hilite">
            <code>
              <span class="ocaml-keyword-other">module</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Line</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other">struct</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-keyword-other">type</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">t</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">    </span>
              <span class="ocaml-source"><![CDATA[{]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">p0</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-support-type">float</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">*</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-support-type">float</span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">p1</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-support-type">float</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">*</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-support-type">float</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[}]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-entity-name-function-binding">t</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">    </span>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword">open</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Repr</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other">in</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">    </span>
              <span class="ocaml-source">record</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">line</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-keyword-other">fun</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">p0</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">p1</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[{]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">p0</span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">p1</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[}]]></span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">    </span>
              <span class="ocaml-keyword-operator">|+</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">field</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">p0</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source">pair</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-support-type">float</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-support-type">float</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-keyword-other">fun</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">t</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">t</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">p0</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">    </span>
              <span class="ocaml-keyword-operator">|+</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">field</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">p1</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source">pair</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-support-type">float</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-support-type">float</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-keyword-other">fun</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">t</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">t</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">p1</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">    </span>
              <span class="ocaml-keyword-operator">|&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">sealr</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-keyword-other">type</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">envelope</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Rtree</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">Rectangle</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">t</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-entity-name-function-binding">envelope</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[{]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">p0</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source">x1</span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">y1</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">p1</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source">x2</span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">y2</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[}]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">    </span>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-entity-name-function-binding">x0</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Float</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">min</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">x1</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">x2</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other">in</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">    </span>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-entity-name-function-binding">x1</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Float</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">max</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">x1</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">x2</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other">in</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">    </span>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-entity-name-function-binding">y0</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Float</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">min</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">y1</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">y2</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other">in</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">    </span>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-entity-name-function-binding">y1</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Float</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">max</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">y1</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">y2</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other">in</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">    </span>
              <span class="ocaml-constant-language-capital-identifier">Rtree</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">Rectangle</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">v</span>
              <span class="ocaml-source"> ~</span>
              <span class="ocaml-source">x0</span>
              <span class="ocaml-source"> ~</span>
              <span class="ocaml-source">y0</span>
              <span class="ocaml-source"> ~</span>
              <span class="ocaml-source">x1</span>
              <span class="ocaml-source"> ~</span>
              <span class="ocaml-source">y1</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword-other">end</span>
              <span class="ocaml-source">
</span>
            </code>
          </pre>
          <p>In addition to the <code>envelope</code> function, we also need to provide a runtime representation using <code>Repr</code>. In the example, we've constructed it by hand but I recommend using <a href="https://ocaml.org/p/ppx_repr/latest">ppx_repr</a> to derive it for you. From here we can create our index.</p>
          <pre class="hilite">
            <code>
              <span class="ocaml-keyword-other">module</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">R</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Rtree</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">Make</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-constant-language-capital-identifier">Rtree</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">Rectangle</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-constant-language-capital-identifier">Line</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">
</span>
            </code>
          </pre>
          <section>
            <header>
              <h3>Inserting Values</h3>
            </header>
            <p>There are two ways to insert values into the index -- either by inserting them one-by-one or by bulk loading them. The latter is the recommended approach where possible as the resulting layout of the R-Tree is much better.</p>
            <pre class="hilite">
              <code>
                <span class="ocaml-mdx-hash">#</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword">let</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-entity-name-function-binding">r</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">    </span>
                <span class="ocaml-keyword">let</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-entity-name-function-binding">i</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">R</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source">empty</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-integer">4</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other">in</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">    </span>
                <span class="ocaml-constant-language-capital-identifier">R</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source">insert</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">i</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">Line</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source"><![CDATA[{]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">p0</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[(]]></span>
                <span class="ocaml-constant-numeric-decimal-float">1.</span>
                <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-float">1.</span>
                <span class="ocaml-source"><![CDATA[)]]></span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">p1</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[(]]></span>
                <span class="ocaml-constant-numeric-decimal-float">2.</span>
                <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-float">2.</span>
                <span class="ocaml-source"><![CDATA[)]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[}]]></span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-keyword-other">val</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">r</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">R</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source">t</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">&lt;</span>
                <span class="ocaml-source">abstr</span>
                <span class="ocaml-keyword-operator">&gt;</span>
                <span class="ocaml-source">
</span>
              </code>
            </pre>
            <p>As you might expect, bulk loading takes a list of values instead.</p>
            <pre class="hilite">
              <code>
                <span class="ocaml-mdx-hash">#</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword">let</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-entity-name-function-binding">r</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">    </span>
                <span class="ocaml-keyword">let</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-entity-name-function-binding">lines</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">        </span>
                <span class="ocaml-constant-language-capital-identifier">Line</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source"><![CDATA[[]]></span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">        </span>
                <span class="ocaml-source"><![CDATA[{]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">p0</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[(]]></span>
                <span class="ocaml-constant-numeric-decimal-float">0.</span>
                <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-float">0.</span>
                <span class="ocaml-source"><![CDATA[)]]></span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">p1</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[(]]></span>
                <span class="ocaml-constant-numeric-decimal-float">1.</span>
                <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-float">1.</span>
                <span class="ocaml-source"><![CDATA[)]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[}]]></span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">        </span>
                <span class="ocaml-source"><![CDATA[{]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">p0</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[(]]></span>
                <span class="ocaml-constant-numeric-decimal-float">1.</span>
                <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-float">1.</span>
                <span class="ocaml-source"><![CDATA[)]]></span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">p1</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[(]]></span>
                <span class="ocaml-constant-numeric-decimal-float">2.</span>
                <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-float">2.</span>
                <span class="ocaml-source"><![CDATA[)]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[}]]></span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">        </span>
                <span class="ocaml-source"><![CDATA[{]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">p0</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[(]]></span>
                <span class="ocaml-constant-numeric-decimal-float">2.</span>
                <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-float">2.</span>
                <span class="ocaml-source"><![CDATA[)]]></span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">p1</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[(]]></span>
                <span class="ocaml-constant-numeric-decimal-float">3.</span>
                <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-float">3.</span>
                <span class="ocaml-source"><![CDATA[)]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[}]]></span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">        </span>
                <span class="ocaml-source"><![CDATA[{]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">p0</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[(]]></span>
                <span class="ocaml-constant-numeric-decimal-float">3.</span>
                <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-float">3.</span>
                <span class="ocaml-source"><![CDATA[)]]></span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">p1</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[(]]></span>
                <span class="ocaml-constant-numeric-decimal-float">4.</span>
                <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-float">4.</span>
                <span class="ocaml-source"><![CDATA[)]]></span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[}]]></span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">        </span>
                <span class="ocaml-source"><![CDATA[]]]></span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">    </span>
                <span class="ocaml-keyword-other">in</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source">    </span>
                <span class="ocaml-constant-language-capital-identifier">R</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source">load</span>
                <span class="ocaml-source"> ~</span>
                <span class="ocaml-source">max_node_load</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-constant-numeric-decimal-integer">4</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">lines</span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-keyword-other">val</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">r</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">R</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source">t</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">&lt;</span>
                <span class="ocaml-source">abstr</span>
                <span class="ocaml-keyword-operator">&gt;</span>
                <span class="ocaml-source">
</span>
              </code>
            </pre>
          </section>
          <section>
            <header>
              <h3>Spatial Queries</h3>
            </header>
            <p>The lines we loaded into the last index are really just four segments of the line <code>y = x</code>. Let's spatially query for the first two segments.</p>
            <pre class="hilite">
              <code>
                <span class="ocaml-mdx-hash">#</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">R</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source">find</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">r</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[(]]></span>
                <span class="ocaml-constant-language-capital-identifier">Rtree</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-constant-language-capital-identifier">Rectangle</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source">v</span>
                <span class="ocaml-source"> ~</span>
                <span class="ocaml-source">x0</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-constant-numeric-decimal-float">0.</span>
                <span class="ocaml-source"> ~</span>
                <span class="ocaml-source">y0</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-constant-numeric-decimal-float">0.</span>
                <span class="ocaml-source"> ~</span>
                <span class="ocaml-source">x1</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-constant-numeric-decimal-float">2.</span>
                <span class="ocaml-source"> ~</span>
                <span class="ocaml-source">y1</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-constant-numeric-decimal-float">2.</span>
                <span class="ocaml-source"><![CDATA[)]]></span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-keyword-operator">-</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-language-capital-identifier">Line</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source">t</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">list</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source"><![CDATA[[]]></span>
                <span class="ocaml-source"><![CDATA[{]]></span>
                <span class="ocaml-constant-language-capital-identifier">Line</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source">p0</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[(]]></span>
                <span class="ocaml-constant-numeric-decimal-float">0.</span>
                <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-float">0.</span>
                <span class="ocaml-source"><![CDATA[)]]></span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">p1</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[(]]></span>
                <span class="ocaml-constant-numeric-decimal-float">1.</span>
                <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-float">1.</span>
                <span class="ocaml-source"><![CDATA[)]]></span>
                <span class="ocaml-source"><![CDATA[}]]></span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[{]]></span>
                <span class="ocaml-constant-language-capital-identifier">Line</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source">p0</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[(]]></span>
                <span class="ocaml-constant-numeric-decimal-float">1.</span>
                <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-float">1.</span>
                <span class="ocaml-source"><![CDATA[)]]></span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">p1</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[(]]></span>
                <span class="ocaml-constant-numeric-decimal-float">2.</span>
                <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-float">2.</span>
                <span class="ocaml-source"><![CDATA[)]]></span>
                <span class="ocaml-source"><![CDATA[}]]></span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source">
</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[{]]></span>
                <span class="ocaml-constant-language-capital-identifier">Line</span>
                <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
                <span class="ocaml-source">p0</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[(]]></span>
                <span class="ocaml-constant-numeric-decimal-float">2.</span>
                <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-float">2.</span>
                <span class="ocaml-source"><![CDATA[)]]></span>
                <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source">p1</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-keyword-operator">=</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-source"><![CDATA[(]]></span>
                <span class="ocaml-constant-numeric-decimal-float">3.</span>
                <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
                <span class="ocaml-source"> </span>
                <span class="ocaml-constant-numeric-decimal-float">3.</span>
                <span class="ocaml-source"><![CDATA[)]]></span>
                <span class="ocaml-source"><![CDATA[}]]></span>
                <span class="ocaml-source"><![CDATA[]]]></span>
                <span class="ocaml-source">
</span>
              </code>
            </pre>
            <p>You can see the query actually returned the first three, that's because all bound checks are inclusive.</p>
          </section>
        </section>
        <p>The <a href="https://github.com/geocaml/ocaml-rtree/blob/d0a789b8eb6c594ed8c0f9c9a6c4b5cd7c734a03/test/image.ml#L95-L106">source repository includes a fairly simple example of rendering an R-Tree</a> using <a href="https://github.com/dbuenzli/vg">Vg</a>. This can be done outside of the repository using the <code>tree</code> representation.</p>
        <pre class="hilite">
          <code>
            <span class="ocaml-mdx-hash">#</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-keyword-other">#</span>
            <span class="ocaml-keyword-other">show</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-constant-language-capital-identifier">R</span>
            <span class="ocaml-source">.</span>
            <span class="ocaml-source">tree</span>
            <span class="ocaml-source">;;</span>
            <span class="ocaml-source">
</span>
            <span class="ocaml-keyword-other">val</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-source">tree</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-constant-language-capital-identifier">R</span>
            <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
            <span class="ocaml-source">t</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-keyword-operator">-&gt;</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-constant-language-capital-identifier">R</span>
            <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
            <span class="ocaml-source">tree</span>
            <span class="ocaml-source">
</span>
            <span class="ocaml-keyword-other">type</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-keyword-other">nonrec</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-source">tree</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-keyword-operator">=</span>
            <span class="ocaml-source">
</span>
            <span class="ocaml-source">  </span>
            <span class="ocaml-constant-language-capital-identifier">R</span>
            <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
            <span class="ocaml-source">tree</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-keyword-operator">=</span>
            <span class="ocaml-source">
</span>
            <span class="ocaml-source">    </span>
            <span class="ocaml-constant-language-capital-identifier">Node</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-keyword-other">of</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-source"><![CDATA[(]]></span>
            <span class="ocaml-constant-language-capital-identifier">Line</span>
            <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
            <span class="ocaml-source">envelope</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-keyword-operator">*</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-constant-language-capital-identifier">R</span>
            <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
            <span class="ocaml-source">tree</span>
            <span class="ocaml-source"><![CDATA[)]]></span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-source">list</span>
            <span class="ocaml-source">
</span>
            <span class="ocaml-source">  </span>
            <span class="ocaml-keyword-other">|</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-constant-language-capital-identifier">Leaf</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-keyword-other">of</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-source"><![CDATA[(]]></span>
            <span class="ocaml-constant-language-capital-identifier">Line</span>
            <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
            <span class="ocaml-source">envelope</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-keyword-operator">*</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-constant-language-capital-identifier">Line</span>
            <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
            <span class="ocaml-source">t</span>
            <span class="ocaml-source"><![CDATA[)]]></span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-source">list</span>
            <span class="ocaml-source">
</span>
            <span class="ocaml-source">  </span>
            <span class="ocaml-keyword-other">|</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-constant-language-capital-identifier">Empty</span>
            <span class="ocaml-source">
</span>
          </code>
        </pre>
        <p>Here is an example rendering from the repository showing some random lines and the envelopes of the R-tree.</p>
        <p style="text-align:center">
    <img src="./rtree.svg" />
</p>
      </div>
    </content>
  </entry>
  <entry>
    <title>Modular Explicits in OCaml</title>
    <author>
      <name>https://patrick.sirref.org/Patrick Ferris/</name>
      <uri>https://patrick.sirref.org/Patrick%20Ferris/</uri>
    </author>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/modular-explicits/" />
    <id>https://patrick.sirref.org/modular-explicits/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>Abstraction, in OCaml, often refers to hiding a particular type's implementation using a <em>signature</em>. For example:</p>
        <pre class="hilite">
          <code>
            <span class="ocaml-keyword-other">module</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-constant-language-capital-identifier">S</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-keyword-other">sig</span>
            <span class="ocaml-source">
</span>
            <span class="ocaml-source">  </span>
            <span class="ocaml-keyword">type</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-entity-name-function-binding">t</span>
            <span class="ocaml-source">
</span>
            <span class="ocaml-source">  </span>
            <span class="ocaml-keyword">val</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-entity-name-function-binding">add</span>
            <span class="ocaml-source"> : t -&gt; t -&gt; t
</span>
            <span class="ocaml-keyword-other">end</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-keyword-operator">=</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-keyword-other">struct</span>
            <span class="ocaml-source">
</span>
            <span class="ocaml-source">  </span>
            <span class="ocaml-keyword-other">type</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-source">t</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-keyword-operator">=</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-support-type">int</span>
            <span class="ocaml-source">
</span>
            <span class="ocaml-source">  </span>
            <span class="ocaml-keyword">let</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-entity-name-function-binding">add</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-keyword-operator">=</span>
            <span class="ocaml-source"> </span>
            <span class="ocaml-constant-language-capital-identifier">Int</span>
            <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
            <span class="ocaml-source">add</span>
            <span class="ocaml-source">
</span>
            <span class="ocaml-keyword-other">end</span>
            <span class="ocaml-source">
</span>
          </code>
        </pre>
        <p>In this post, however, I use abstraction to refer to the notion of code-reuse. Using features of the OCaml language to allow one piece of code to be used across different implementations or instantiations of a particular kind of value.</p>
        <p>The goal of this post is to eventually discuss OCaml 5.5's <a href="https://patrick.sirref.org/abs-modular-explicits/">modular explicits</a> which is yet another feature that can allow a single piece of code to be used in various situations.</p>
        <section>
          <header>
            <h2>Polymorphism </h2>
          </header>
          <p>The most prevalent kind of abstraction is polymorphism. For example, <code>List.length</code> will work for all lists regardless of what kind of elements the list contains. However, polymorphism requires you to keep the polymorphic part of the type at arm's length. This can lead to suboptimal performance and/or limited usefulness.</p>
          <p><code>List.mem</code> is a good example; in order to be polymorphic <code>List.mem</code> relies on <code>Stdlib.(=)</code>, the polymorphic equality operator. In turn, this operator achieves its polymorphism by performing a structural comparison of the runtime representation of its arguments.</p>
          <p>A common way to overcome this is to use higher-order functions (functions that take functions as arguments).</p>
          <pre class="hilite">
            <code>
              <span class="ocaml-mdx-hash">#</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword">rec </span>
              <span class="ocaml-entity-name-function-binding">mem</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-variable-parameter-optional">?</span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-variable-parameter-optional">eq</span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-constant-language-capital-identifier">Stdlib</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">v</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other">function</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-keyword-other">|</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-list"><![CDATA[[]]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-boolean">false</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-keyword-other">|</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">x</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">xs</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">eq</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">v</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">x</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">||</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">mem</span>
              <span class="ocaml-source"> ~</span>
              <span class="ocaml-source">eq</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">v</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">xs</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword-other">val</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">mem</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> ?</span>
              <span class="ocaml-source">eq</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-storage-type">'a</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-storage-type">'a</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-support-type">bool</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-storage-type">'a</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-storage-type">'a</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">list</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-support-type">bool</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">&lt;</span>
              <span class="ocaml-keyword-other">fun</span>
              <span class="ocaml-keyword-operator">&gt;</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-mdx-hash">#</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-entity-name-function-binding">mem_int_list</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">mem</span>
              <span class="ocaml-source"> ~</span>
              <span class="ocaml-source">eq</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-constant-language-capital-identifier">Int</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">equal</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword-other">val</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">mem_int_list</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-support-type">int</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-support-type">int</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">list</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-support-type">bool</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">&lt;</span>
              <span class="ocaml-keyword-other">fun</span>
              <span class="ocaml-keyword-operator">&gt;</span>
              <span class="ocaml-source">
</span>
            </code>
          </pre>
          <p>This works well in plenty of cases (<code>List.map</code>, <code>Hashtbl.iter</code>, etc.), however, it doesn't scale well from a user's perspective if the body of the function requires lots of specific functions (e.g. <code>compare</code>, <code>length</code>, <code>pp</code>). At the same time, we want to avoid the precarious duck-typing of something like Python too.</p>
        </section>
        <section>
          <header>
            <h2>Functors </h2>
          </header>
          <p>Functors are perhaps the second most prevalent feature of OCaml when it comes to code reuse. In the OCaml sense, a functor is a module that is parameterised by other modules. <code>Set.Make</code> is a functor that requires a module adhereing to the <code>Set.OrderedType</code> interface.</p>
          <pre class="hilite">
            <code>
              <span class="ocaml-keyword-other">module</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">IntSet</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Set</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">Make</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-constant-language-capital-identifier">Int</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword-other">module</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">StringSet</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Set</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">Make</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-constant-language-capital-identifier">String</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
            </code>
          </pre>
          <p>Functors make it a lot easier to write implementations that depend on a large variety of functionality. <code>Set.OrderedType</code> is relatively tame in this sense, only needing a type <code>t</code> and a <code>compare : t -&gt; t -&gt; int</code> function.</p>
          <p><a href="https://patrick.sirref.org/irmin/">Irmin</a>, on the other hand, has functors that require users to provide <a href="https://ocaml.org/p/irmin/3.11.0/doc/irmin/Irmin/Schema/module-type-S/index.html">Schemas</a>. I have more thoughts about this API design in <a href="https://patrick.sirref.org/irmin-retro/">my Irmin retrospective</a>.</p>
          <p>It is important to consider the runtime costs of functors too. Whilst most of the time functors are instantiated at the toplevel, it does not come for free. You can have a play around with <a href="https://patricoferris.github.io/js_of_ocamlopt/#code=bGV0IGYgaSA9CiAgbGV0IG1vZHVsZSBJID0gU2V0Lk1ha2UgKEludCkgaW4KICBJLmNhcmRpbmFsIGk=">js_of_ocamlopt</a> and see the generated output for how functors are applied.</p>
        </section>
        <section>
          <header>
            <h2>First-class Modules and Existentials </h2>
          </header>
          <p>Sitting somewhere inbetween polymorphism and functors are first-class modules with existentials. This is a rather advanced use of OCaml's type system to be able to <em>pack</em> together a value of a particular type alongside a module that works with those kinds of values.</p>
          <pre class="hilite">
            <code>
              <span class="ocaml-keyword-other">type</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">set</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Set</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-keyword-other">module</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Set</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">S</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other">with</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other">type</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">t</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-storage-type">'a</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">*</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-storage-type">'a</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">set</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-entity-name-function-binding">size</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-constant-language-capital-identifier">Set</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-keyword-other">module</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">S</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">s</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">S</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">cardinal</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">s</span>
              <span class="ocaml-source">
</span>
            </code>
          </pre>
          <p>Packaging up integer sets is fairly straight-forward.</p>
          <pre class="hilite">
            <code>
              <span class="ocaml-mdx-hash">#</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-entity-name-function-binding">int_empty_set</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Set</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-keyword-other">module</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">IntSet</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">IntSet</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">empty</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword-other">val</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">int_empty_set</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">set</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Set</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-keyword-operator">&lt;</span>
              <span class="ocaml-keyword-other">module</span>
              <span class="ocaml-keyword-operator">&gt;</span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">&lt;</span>
              <span class="ocaml-source">poly</span>
              <span class="ocaml-keyword-operator">&gt;</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source">
</span>
            </code>
          </pre>
          <p>From a user's perspective we are now closer to the realm of dynamic typing. Indeed, existentials are the way to do that in OCaml.</p>
          <pre class="hilite">
            <code>
              <span class="ocaml-mdx-hash">#</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other">type</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">any</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Any</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-storage-type">'a</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">any</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword-other">type</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">any</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Any</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-storage-type">'a</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">any</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-mdx-hash">#</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-entity-name-function-binding">any</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">v</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Any</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">v</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword-other">val</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">any</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-storage-type">'a</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">any</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">&lt;</span>
              <span class="ocaml-keyword-other">fun</span>
              <span class="ocaml-keyword-operator">&gt;</span>
              <span class="ocaml-source">
</span>
            </code>
          </pre>
          <p>Getting back into a typed world often involves some <a href="https://github.com/dbuenzli/hmap/blob/e54eb3f7d7dbada0724fd023c334d0b5a29c8479/src/hmap.ml#L120-L127">type witness gymnastics</a> or runtime exceptions. Used sparingly, however, it can be very effective particularly when a user is none the wiser about the use of FCMs and existentials. I have made use of this trick to <a href="https://github.com/fn06/shelter/blob/e71d6df79ab7c43b092de145e9e80482ae3af118/src/lib/store.ml#L1-L10">package together Irmin stores with implementations</a>.</p>
          <p>You could not, however, simply return the value that was packed away inside the existential.</p>
          <pre class="hilite">
            <code>
              <span class="ocaml-mdx-hash">#</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-entity-name-function-binding">woops</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-constant-language-capital-identifier">Set</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-constant-language">_</span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">s</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">s</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-constant-language-capital-identifier">Line</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-numeric-decimal-integer">1</span>
              <span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">characters</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-numeric-decimal-integer">26</span>
              <span class="ocaml-keyword-operator">-</span>
              <span class="ocaml-constant-numeric-decimal-integer">27</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-constant-language-capital-identifier">Error</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">The</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">value</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">s</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">has</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other">type</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">$</span>
              <span class="ocaml-source">a</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">but</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">an</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">expression</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">was</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">expected</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other">of</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other">type</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-storage-type">'a</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">       </span>
              <span class="ocaml-constant-language-capital-identifier">The</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other">type</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">constructor</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">$</span>
              <span class="ocaml-source">a</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">would</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">escape</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">its</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">scope</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">       </span>
              <span class="ocaml-constant-language-capital-identifier">Hint</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">$</span>
              <span class="ocaml-source">a</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">is</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">an</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">existential</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other">type</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">bound</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">by</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">the</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">constructor</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Set</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">
</span>
            </code>
          </pre>
          <p>There is also a runtime cost to the packing (and unpacking) of the module, not to mention the need for the extra allocation to create the existential in the first place. This will likely not be too significant, but is worth considering.</p>
        </section>
        <section>
          <header>
            <h2>Modular Explicits </h2>
          </header>
          <p>OCaml 5.5 has <em>module-dependent function types</em> also known as <em>explicits modular</em>. The type of a function can now depend on types that come from a module that is also part of the function definition.</p>
          <pre class="hilite">
            <code>
              <span class="ocaml-mdx-hash">#</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-entity-name-function-binding">set_length</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-keyword-other">module</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">S</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Set</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">S</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">S</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">t</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-support-type">int</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-keyword-other">fun</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-keyword-other">module</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">S</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">v</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">S</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">cardinal</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">v</span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword-other">val</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">set_length</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-keyword-other">module</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">S</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Set</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">S</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">S</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">t</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-support-type">int</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">&lt;</span>
              <span class="ocaml-keyword-other">fun</span>
              <span class="ocaml-keyword-operator">&gt;</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-mdx-hash">#</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">set_length</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-keyword-other">module</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">IntSet</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">IntSet</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">empty</span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword-operator">-</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-support-type">int</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-numeric-decimal-integer">0</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-mdx-hash">#</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">set_length</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-keyword-other">module</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">StringSet</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">StringSet</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">empty</span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword-operator">-</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-support-type">int</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-numeric-decimal-integer">0</span>
              <span class="ocaml-source">
</span>
            </code>
          </pre>
          <p>In fact, we can now <em>return</em> values of a particular type that depends on a particular module!</p>
          <pre class="hilite">
            <code>
              <span class="ocaml-mdx-hash">#</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-entity-name-function-binding">empty_set</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-keyword-other">module</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">S</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Set</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">S</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">S</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">t</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> 
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-keyword-other">fun</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-keyword-other">module</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">S</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">S</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">empty</span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword-other">val</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">empty_set</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-keyword-other">module</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">S</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Set</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">S</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">S</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">t</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">&lt;</span>
              <span class="ocaml-keyword-other">fun</span>
              <span class="ocaml-keyword-operator">&gt;</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-mdx-hash">#</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">empty_set</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-keyword-other">module</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">IntSet</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword-operator">-</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">IntSet</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">t</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">&lt;</span>
              <span class="ocaml-source">abstr</span>
              <span class="ocaml-keyword-operator">&gt;</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-mdx-hash">#</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">empty_set</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-keyword-other">module</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">StringSet</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword-operator">-</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">StringSet</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">t</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">&lt;</span>
              <span class="ocaml-source">abstr</span>
              <span class="ocaml-keyword-operator">&gt;</span>
              <span class="ocaml-source">
</span>
            </code>
          </pre>
          <p>Or, we can dynamically select implementations and values.</p>
          <pre class="hilite">
            <code>
              <span class="ocaml-mdx-hash">#</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword">let</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-entity-name-function-binding">with_impl</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> 
</span>
              <span class="ocaml-source">    </span>
              <span class="ocaml-source">config</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-support-type">string</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-keyword-other">module</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">S</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Set</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">S</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">S</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">t</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-storage-type">'a</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-storage-type">'a</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source"> 
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-keyword-other">fun</span>
              <span class="ocaml-source"> ~</span>
              <span class="ocaml-source">config</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">fn</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-keyword-other">match</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">String</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">lowercase_ascii</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">config</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other">with</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-keyword-other">|</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">string</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">fn</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-keyword-other">module</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">StringSet</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">StringSet</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">empty</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-keyword-other">|</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-string-quoted-double">int</span>
              <span class="ocaml-string-quoted-double">"</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">fn</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-keyword-other">module</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">IntSet</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">IntSet</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">empty</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-keyword-other">|</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">c</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">invalid_arg</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">c</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-keyword-other">val</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">with_impl</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source">config</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-support-type">string</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-source"><![CDATA[(]]></span>
              <span class="ocaml-keyword-other">module</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">S</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">Set</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-constant-language-capital-identifier">S</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-constant-language-capital-identifier">S</span>
              <span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span>
              <span class="ocaml-source">t</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-storage-type">'a</span>
              <span class="ocaml-source"><![CDATA[)]]></span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">-&gt;</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-storage-type">'a</span>
              <span class="ocaml-source"> </span>
              <span class="ocaml-keyword-operator">=</span>
              <span class="ocaml-source">
</span>
              <span class="ocaml-source">  </span>
              <span class="ocaml-keyword-operator">&lt;</span>
              <span class="ocaml-keyword-other">fun</span>
              <span class="ocaml-keyword-operator">&gt;</span>
              <span class="ocaml-source">
</span>
            </code>
          </pre>
          <p>This is like a more usable version of the FCM-existential trick, though does require more manual type annotations on functions. For instance, I tried switching out <a href="https://github.com/ocurrent/obuilder">OBuilder's</a> use of existentials with modular explicits:</p>
          <pre><![CDATA[-type builder = Builder : (module Obuilder.BUILDER with type t = 'a) * 'a -> builder
-
 let log tag msg =
   match tag with
   | `Heading -> Fmt.pr "%a@." Fmt.(styled (`Fg (`Hi `Blue)) string) msg
   | `Note -> Fmt.pr "%a@." Fmt.(styled (`Fg `Yellow) string) msg
   | `Output -> output_string stdout msg; flush stdout

-let create_builder store_spec conf =
+let create_builder :
+  Store_spec.store Lwt.t -> Native_sandbox.config ->
+    ((module B : Obuilder.BUILDER) -> B.t -> 'a) -> 'a Lwt.t =
+  fun store_spec conf fn ->
   store_spec >>= fun (Store_spec.Store ((module Store), store)) ->
   let module Builder = Obuilder.Builder (Store) (Native_sandbox) (Docker_extract) in
   Native_sandbox.create ~state_dir:(Store.state_dir store / "sandbox") conf >|= fun sandbox ->
   let builder = Builder.v ~store ~sandbox in
-  Builder ((module Builder), builder)
+  fn (module Builder) builder]]></pre>
          <p>I think the code is more pragmatic; there is no longer an indirection via a type called <code>builder</code>. The extra type annotations do add a little noise. Roll on <em>modular implicits</em>.</p>
        </section>
      </div>
    </content>
  </entry>
</feed>
