<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="/default.xsl"?>
<fr:tree xmlns:fr="http://www.forester-notes.org" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:xml="http://www.w3.org/XML/1998/namespace" root="true" base-url="/">
  <fr:frontmatter>
    <fr:authors>
      <fr:author>
        <fr:link href="/patrickferris/" title="Patrick Ferris" uri="https://patrick.sirref.org/patrickferris/" display-uri="patrickferris" type="local">Patrick Ferris</fr:link>
      </fr:author>
    </fr:authors>
    <fr:uri>https://patrick.sirref.org/index/</fr:uri>
    <fr:display-uri>index</fr:display-uri>
    <fr:route>/index/</fr:route>
    <fr:title text="Patrick Ferris">Patrick Ferris</fr:title>
    <fr:meta name="related">false</fr:meta>
    <fr:meta name="author">false</fr:meta>
    <fr:meta name="show_heading">false</fr:meta>
  </fr:frontmatter>
  <fr:mainmatter>
    <html:img src="/bafkrmie6iutyggpn4llflsmeozsthsga7edsmlm747jftsymwzjh7wxrei.jpg" width="160" height="160" alt="The website author in the Tennessee mountains which are covered in snow. Next to the author there is a very small snow person." />
    <html:style>footer{ display: none }</html:style>
    <html:p><fr:link href="mailto:patrick@sirref.org" type="external">email</fr:link> - <fr:link href="https://mastodon.social/@patricoferris" type="external">mastodon</fr:link> - <fr:link href="https://github.com/patricoferris" type="external">github</fr:link></html:p>
    <html:p>I'm a PhD student in the Energy and Environment Group at the <fr:link href="/camcst/" title="Department of Computer Science and Technology, University of Cambridge" uri="https://patrick.sirref.org/camcst/" display-uri="camcst" type="local">Department of Computer Science</fr:link>, <fr:link href="/ucam/" title="University of Cambridge" uri="https://patrick.sirref.org/ucam/" display-uri="ucam" type="local">University of Cambridge</fr:link>.</html:p>
    <html:p>I'm particularly interested in:</html:p>
    <html:ul>
      <html:li>
        <html:p><![CDATA[How technology can help tackle climate change (e.g.]]> <fr:link href="/geocaml/" title="Geocaml" uri="https://patrick.sirref.org/geocaml/" display-uri="geocaml" type="local">geocaml</fr:link><![CDATA[) and potential issues it creates.]]></html:p>
      </html:li>
    </html:ul>
    <html:ul>
      <html:li>
        <html:p><![CDATA[Communicating science effectively to a wide audience (e.g.]]> <fr:link href="/ni-forests/" title="Northern Irish Forests" uri="https://patrick.sirref.org/ni-forests/" display-uri="ni-forests" type="local">NI Forests</fr:link><![CDATA[) and improving diversity and inclusion in tech (see]]> <fr:link href="/outreachy/" title="Outreachy" uri="https://patrick.sirref.org/outreachy/" display-uri="outreachy" type="local">Outreachy</fr:link><![CDATA[).]]></html:p>
      </html:li>
    </html:ul>
    <fr:tree show-metadata="false" expanded="false" toc="false">
      <fr:frontmatter>
        <fr:authors />
        <fr:uri>https://patrick.sirref.org/posts/</fr:uri>
        <fr:display-uri>posts</fr:display-uri>
        <fr:route>/posts/</fr:route>
        <fr:title text="Posts">Posts</fr:title>
      </fr:frontmatter>
      <fr:mainmatter>
        <html:p>Occasionally I write posts, mostly about OCaml or something related.</html:p>
        <html:p><fr:link href="/posts/atom.xml" type="external">An RSS feed is available</fr:link>.</html:p>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2026</fr:year>
              <fr:month>3</fr:month>
              <fr:day>9</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/vibecoding-etiquette/</fr:uri>
            <fr:display-uri>vibecoding-etiquette</fr:display-uri>
            <fr:route>/vibecoding-etiquette/</fr:route>
            <fr:title text="Vibecoding Etiquette">Vibecoding Etiquette</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html: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.</html:p>
            <html: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 <![CDATA[US Department of War (I struggle to find the meaningful difference between]]>  <fr:link href="https://www.anthropic.com/news/where-stand-department-war" type="external">"opertational planning" vs. "operational decision-making" given the leaders of the US DoW</fr:link><![CDATA[),]]>  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.</html:p>
            <html:p>Everybody can draw their line where they want, and I am, in good faith, trying to find where mine should be.</html:p>
            <html: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.</html:p>
            <html: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. <fr:link href="https://github.com/ocaml-multicore/eio/blob/main/HACKING.md#ai-generated-code" type="external">Eio's "AI-generated Code"</fr:link> subsection is succinct and prohibits contributions that <html:em>solely</html:em> use AI.</html:p>
            <html:blockquote>
              <html: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.</html:p>
              <html: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.</html:p>
              <html: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.</html:p>
            </html:blockquote>
            <html:p>Additionally, I plead to other developers to <html:em>own</html:em> their use of these tools. Please, make Claude a co-author of the commits where Claude has generated <html:em>any</html: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 <fr:link href="https://github.com/ocaml/ocaml/blob/trunk/AI.md" type="external">OCaml compiler's AI notice</fr:link> which includes:</html:p>
            <html:blockquote>
              <html: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.</html:p>
            </html:blockquote>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>10</fr:month>
              <fr:day>24</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/icfp-2025/</fr:uri>
            <fr:display-uri>icfp-2025</fr:display-uri>
            <fr:route>/icfp-2025/</fr:route>
            <fr:title text="ICFP 2025">ICFP 2025</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>Two weeks ago I was fortunate enough to attend the <fr:link href="https://icfp25.sigplan.org/" type="external">International Conference on Functional Programming</fr:link> in Singapore. My first time in Asia and my second time at the conference, what follows are some thoughts and presentations I enjoyed whilst I was there.</html:p>
            <html:p><![CDATA[I must thank my office mate (and friend!)]]> <fr:link href="https://ryan.freumh.org/" type="external">Ryan Gibb</fr:link> for his camaraderie and sage advice: "the best track is <html:em>hallway</html:em> track". Not to mention all of his <fr:link href="https://ryan.freumh.org/photos.html" type="external">photos</fr:link> too. Thanks Ryan!</html:p>
            <html:div style="text-align: center">
  <html:img class="inner-img" src="/bafkrmid2d6u3qdufa6m5gogavtwm6uqksaicozrc5s2unrtzjtth3hpvey.jpeg" alt="Description follows image." />
</html:div>
            <html:p>From right to left, top to bottom: <fr:link href="https://patrick.sirref.org/anil madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>, <fr:link href="https://patrick.sirref.org/sadiq jaffer/" type="external">Sadiq Jaffer</fr:link>, <fr:link href="https://patrick.sirref.org/patrick ferris/" type="external">Patrick Ferris</fr:link>, <fr:link href="https://patrick.sirref.org/ryan gibb/" type="external">Ryan Gibb</fr:link> and <fr:link href="https://patrick.sirref.org/roy ang/" type="external">Roy Ang</fr:link>.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>10</fr:month>
                  <fr:day>24</fr:day>
                </fr:date>
                <fr:title text="Random Hacking">Random Hacking</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Below are just some of the pieces of random hacking I got up to whilst in Singapore.</html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:uri>https://patrick.sirref.org/oxcaml-and-uring/</fr:uri>
                    <fr:display-uri>oxcaml-and-uring</fr:display-uri>
                    <fr:route>/oxcaml-and-uring/</fr:route>
                    <fr:title text="OxCaml and Uring">OxCaml and Uring</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Jane Street were a big presence at ICFP 2025, carting along with them a shiny new OCaml compiler: <fr:link href="https://oxcaml.org/" type="external">OxCaml</fr:link>. If have been <fr:link href="/try-oxcaml/" title="Try OxCaml" uri="https://patrick.sirref.org/try-oxcaml/" display-uri="try-oxcaml" type="local">playing around with OxCaml recently</fr:link> but nothing outside toplevels in Javascript. Until now!</html:p>
                    <html:p>After talking to <fr:link href="/dra27/" title="David Allsopp" uri="https://patrick.sirref.org/dra27/" display-uri="dra27" type="local">David</fr:link>, I spent some time converting a small corner of the <fr:link href="https://github.com/ocaml-multicore/ocaml-uring" type="external">ocaml-uring</fr:link> library to use a part of <fr:link href="https://patrick.sirref.org/oxcaml/" type="external">OxCaml</fr:link>. In particular making the following change:</html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">module</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Heap</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">struct</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword-other">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">ptr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">int32</html:span><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-comment-block"><![CDATA[(*]]> </html:span><html:span class="ocaml-comment-block"> ... </html:span><html:span class="ocaml-comment-block"><![CDATA[*)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">end</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">cqe</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source">user_data_id</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Heap</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">ptr</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source">res</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">int32</html:span><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                    <html:p><![CDATA[The idea being that a completion queue entry (a notification that some]]>  <![CDATA[operation has completed) could be fully represented using 64 bits (two 32-bit,]]>  <fr:link href="https://oxcaml.org/documentation/unboxed-types/01-intro/" type="external">unboxed values</fr:link><![CDATA[).]]>  You can <fr:link href="https://github.com/ocaml-multicore/ocaml-uring/compare/main...patricoferris:ocaml-uring:oxcaml?expand=1" type="external">see how this impacted the library</fr:link>! <![CDATA[I'm not certain about this change (and I'm sure I did it wrong) but it was nice]]>  to realise <fr:link href="https://patrick.sirref.org/oxcaml/" type="external">OxCaml</fr:link> gives you this kind of control. However, I am worried about the ergonomics of manipulating values like <html:code>int32#</html:code> and the temptation to case it into an <html:code>int</html:code><![CDATA[ (presumably losing a good portion of the value of having]]>  <![CDATA[an unboxed value in the first place).]]></html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>10</fr:month>
                      <fr:day>24</fr:day>
                    </fr:date>
                    <fr:title text="Bibtex Parser">Bibtex Parser</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>On the flight over to Singapore, I started to write a post for this website. Some readers may remember that I use <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">forester</fr:link> after a preprocessing step via <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">graft</fr:link> to build this site. Part of that preprocessing consumes bibtex files and outputs forester trees. For the initial <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">graft</fr:link> release I used the excellent <fr:link href="https://github.com/Octachron/talaria_bibtex" type="external">Talaria Bibtex</fr:link> library. Unfortunately, it presented a pretty confusing API that, whilst nicely typed, felt a little cumbersome to use. Additionally, it was too specific in what it would accept as valid Bibtex. I wanted something that was a little more <![CDATA[straight-forward to use (if a little fast-and-loose when it comes to types...).]]>  And so I built <fr:link href="/bib/" title="Bib" uri="https://patrick.sirref.org/bib/" display-uri="bib" type="local">bib</fr:link>.</html:p>
                    <html:p>This was my first real attempt at using the <fr:link href="https://ocaml.org/p/bytesrw" type="external">Bytesrw</fr:link> library. I was happy with the results, although I did have to copy a substantial amount of code from <fr:link href="https://ocaml.org/p/jsont" type="external">other bytesrw-compatible libraries</fr:link>. I'd be happy to shift to this <html:code>bytes</html:code>-first world if it wasn't for the ever-present-in-my-mind issue of relocatable values in the OCaml heap!</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>10</fr:month>
                      <fr:day>24</fr:day>
                    </fr:date>
                    <fr:title text="Geocaml Libraries">Geocaml Libraries</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>There has been some excellent <fr:link href="/outreachy/" title="Outreachy" uri="https://patrick.sirref.org/outreachy/" display-uri="outreachy" type="local">outreachy</fr:link> work happening on the <fr:link href="https://github.com/geocaml/ocaml-tiff" type="external">geocaml/ocaml-tiff</fr:link> library which is a potential Outreachy internship project for December 2025. More on this in a future post.</html:p>
                    <html:p><![CDATA[On the way back (and a little during the conference), I spent some time building an OCaml]]>  counterpart to <fr:link href="https://github.com/ucam-eo/geotessera/" type="external">geotessera</fr:link>, a library for working with <fr:link href="/tessera2025/" title="TESSERA: Temporal Embeddings of Surface Spectra for Earth Representation and Analysis" uri="https://patrick.sirref.org/tessera2025/" display-uri="tessera2025" type="local">Tessera</fr:link>. The library is not ready for people to use directly, but I was working on various constituent parts including:</html:p>
                    <html:ul>
                      <html:li>
                        <html:p><fr:link href="https://github.com/geocaml/ocaml-proj" type="external">Modern OCaml bindings to PROJ</fr:link><![CDATA[ (a coordinate reference system projection library)]]></html:p>
                      </html:li>
                      <html:li>
                        <html:p>
                          <fr:link href="https://github.com/geocaml/ocaml-wkt" type="external">Further work on a WKT library for OCaml</fr:link>
                        </html:p>
                      </html:li>
                      <html:li>
                        <html:p>Coming soon... ocaml-geotessera</html:p>
                      </html:li>
                    </html:ul>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>10</fr:month>
                  <fr:day>24</fr:day>
                </fr:date>
                <fr:title text="Talks">Talks</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>10</fr:month>
                      <fr:day>24</fr:day>
                    </fr:date>
                    <fr:title text="Hazel of OCaml at TyDe">Hazel of OCaml at TyDe</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>The <html:em>type-driven development</html:em><![CDATA[ (TyDe) workshop was held on the first day of ICFP at the]]>  <fr:link href="https://www.comp.nus.edu.sg/" type="external">NUS School of Computing</fr:link>. I find the workshop name to be a little misleading, but perhaps this comes from my engineering background. The talks focused a lot on type <html:em>theory</html:em>, presenting the formal mathematics of interesting type systems with less focus on <html:em>why</html:em> it might be useful to have such an exotic type system... but then again, that was the nature of the entire conference.</html:p>
                    <html:p>I presented a talk on <fr:link href="/hazel-of-ocaml/" title="A Transpiler from OCaml to Hazel" uri="https://patrick.sirref.org/hazel-of-ocaml/" display-uri="hazel-of-ocaml" type="local">hazel_of_ocaml</fr:link>. The <fr:link href="https://patrick.sirref.org/var/tyde2025.pdf" type="external">slides are here</fr:link>, along with the <fr:link href="https://patrick.sirref.org/var/tyde2025-ea.pdf" type="external">extended abstract</fr:link>. My talk ended up focusing a lot on the pedagogical benefits of having a type system that helped explain the most important thing a type system does... catch type errors! This work represents a small piece of work inside <fr:link href="https://maxcarroll0.github.io/" type="external">Max Carroll's</fr:link> excellent <fr:link href="/part-ii-hazel/" title="Type Error Debugging in Hazel" uri="https://patrick.sirref.org/part-ii-hazel/" display-uri="part-ii-hazel" type="local">part II</fr:link> project, which he presented at the <fr:link href="https://maxcarroll0.github.io/papers/workshops/HATRA-decomposable-type-highlighting/" type="external">HATRA workshop</fr:link>: <html:em>Decomposable Type Highlighting for Bidirectional Type and Cast Systems</html:em>.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>10</fr:month>
                      <fr:day>24</fr:day>
                    </fr:date>
                    <fr:title text="Scientific Programming at PROPL">Scientific Programming at PROPL</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>I think it is important to be honest whenever you get a talk accepted that you otherwise feel should not have been. My talk "<html:em>about scientific programming what we talk about when we talk</html:em>" is one such talk. The <fr:link href="https://patrick.sirref.org/var/propl2025.pdf" type="external">slides are here</fr:link>. The talk itself was nothing to write home about, but I think there were a few nice ideas that came out of it and the conversations I had with fellow PROPL attenders.</html:p>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>10</fr:month>
                          <fr:day>24</fr:day>
                        </fr:date>
                        <fr:title text="TMF Data Discrepancies Redux">TMF Data Discrepancies Redux</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>On the eve of my talk, I decided to re-run some analysis I did a few years ago on the <fr:link href="https://forobs.jrc.ec.europa.eu/TMF/data#downloads" type="external">tropical moist forest dataset</fr:link>, knowing that since then a few more years had become available. After fighting with some bit-rot in the Google Earth Engine script I had used, the new results were not very uplifting.</html:p>
                        <html:table>
    <html:tbody>
    <html:tr>
    <html:td><html:strong>Land Use Class</html:strong></html:td>
    <html:td><html:strong>Percent Change</html:strong></html:td>
    </html:tr>
    <html:tr>
    <html:td>Undisturbed</html:td>
    <html:td> -2.9</html:td>
    </html:tr>
    <html:tr>
    <html:td>Degraded</html:td>
    <html:td> -5.5</html:td>
    </html:tr>
    <html:tr style="background: yellow">
    <html:td>Deforested</html:td>
    <html:td> 8.6</html:td>
    </html:tr>
    <html:tr>
    <html:td>Regrowth</html:td>
    <html:td> 0.5</html:td>
    </html:tr>
    <html:tr>
    <html:td>Water</html:td>
    <html:td> 0.0</html:td>
    </html:tr>
    <html:tr>
    <html:td>Other</html:td>
    <html:td>-0.6</html:td>
    </html:tr>
    </html:tbody>
</html:table>
                        <html:p>The data in the table corresponds to the land use class values in Indonesia in the year 2008. The analysis computed the difference across each of the classes between the dataset released in 2021 and the dataset released in 2024. Most notably, the amount of deforested land has gone up by <html:em>8.6</html:em> percent!</html:p>
                        <html:p>As a somewhat tangential, though related, aside, I had the pleasure of talking to <fr:link href="https://cs.nyu.edu/~shw8119/" type="external">Sam Westrick</fr:link>, <fr:link href="https://forthoney.github.io/" type="external">Seong-Heon Jung</fr:link> and <fr:link href="https://svishnus.github.io/" type="external">Sundara Vishnu Satish</fr:link> of the <fr:link href="https://nyu-parcour.github.io/" type="external">ParCour</fr:link> research group. They were telling me about <fr:link href="https://github.com/mpllang/mpl" type="external">MaPLe</fr:link>, a programming language from the MLs built for parallelism. We discussed some ideas of using real-world, geospatial algorithms as benchmarks for MaPLe. <fr:link href="/mdales/" title="Michael W. Dales" uri="https://patrick.sirref.org/mdales/" display-uri="mdales" type="local">Michael</fr:link>, if you got this far remind me to chat to you about this!</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>10</fr:month>
                          <fr:day>24</fr:day>
                        </fr:date>
                        <fr:title text="Shelter Reactions">Shelter Reactions</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>At the end of my talk, I briefly mentioned <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">shelter</fr:link>. By far, this was the topic I got the most engagement on post-talk. During the conference, this was also true when people asked what I was working on. The tag line "a shell with <html:em>undo</html:em>" seemed to capture the attention of most people.</html:p>
                        <html:p>I'm feeling a renewed sense of interest in my own work thanks to that, even if the "research" contributions are not very apparent. However, I also had a good discussion with <fr:link href="https://kcsrk.info/" type="external">KC</fr:link> about the underlying <fr:link href="https://patrick.sirref.org/mrdt/" type="external">MRDT</fr:link> in <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> and how we might think about collaborating in the future on MRDT-related work.</html:p>
                        <html:p>Related to that, I managed to spend the evening in <fr:link href="https://www.openstreetmap.org/relation/18195609#map=16/1.28090/103.84222" type="external">Chinatown</fr:link> with <fr:link href="https://dynamicaspects.org/research/" type="external">Roly Perera</fr:link>. Roly's work has focused on <fr:link href="https://f.luid.org/" type="external">Fluid</fr:link>, a transparency-based programming language that allows authors to reveal their computation to their user. Excitingly, Roly presented a <fr:link href="https://conf.researchr.org/details/icfp-splash-2025/propl-2025-papers/10/Authoring-Tools-for-Transparent-Climate-Reporting" type="external">new text-based part of the language</fr:link> at PROPL. Our work is in the same universe, loosely orbiting some notion of reproducibility and explainability, but quite different in engineering work and how users might actually interact with our systems. I thoroughly enjoyed talking about solutions or research ideas that <html:em>preserve</html:em> existing workflows. Roly was great at pulling that out of the current work I have been doing.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>10</fr:month>
                  <fr:day>24</fr:day>
                </fr:date>
                <fr:title text="Other Talks and Highlights">Other Talks and Highlights</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I was a part of, often in a very small way, some other talks that were presented at ICFP including</html:p>
                <html:ul>
                  <html:li>
                    <html:p><fr:link href="https://www.youtube.com/watch?v=j84ocjlj1JA&amp;amp;t=12880s" type="external">Functional Networking for Docker</fr:link>, I encourage you to read <fr:link href="/anilmadhavapeddy/" title="Anil Madhavapeddy" uri="https://patrick.sirref.org/anilmadhavapeddy/" display-uri="anilmadhavapeddy" type="local">Anil's</fr:link> <fr:link href="https://anil.recoil.org/notes/icfp25-ocaml5-js-docker#functional-networking-at-docker" type="external">notes on the topic</fr:link>. It is also worth mentioning <fr:link href="/anilmadhavapeddy/" title="Anil Madhavapeddy" uri="https://patrick.sirref.org/anilmadhavapeddy/" display-uri="anilmadhavapeddy" type="local">Anil's</fr:link> <fr:link href="https://anil.recoil.org/notes/icfp25-post-posix" type="external">post-posix talk</fr:link><![CDATA[ (not unrelated to my Uring musings above).]]></html:p>
                  </html:li>
                  <html:li>
                    <html:p><fr:link href="/mdales/" title="Michael W. Dales" uri="https://patrick.sirref.org/mdales/" display-uri="mdales" type="local">Michael</fr:link> gave an excellent, <html:em>very live</html:em>, talk about <fr:link href="https://conf.researchr.org/details/icfp-splash-2025/propl-2025-papers/6/Yirgacheffe-a-declarative-approach-to-geospatial-data" type="external">Yirgacheffe</fr:link> at PROPL which I thoroughly enjoyed. I'm also excited about his recent developments which I'm sure you can clue into <fr:link href="https://digitalflapjack.com/weeknotes/" type="external">over on his blog</fr:link>.</html:p>
                  </html:li>
                </html:ul>
                <html:p>Below is a non-exhaustive list of talks I enjoyed whilst at the conference. Some relevant, most of them not!</html:p>
                <html:ul>
                  <html:li>
                    <html:p>By far, one of the best talks was <fr:link href="https://icfp25.sigplan.org/details/icfp-2025-papers/13/Polynomial-Time-Program-Equivalence-for-Machine-Knitting" type="external">Polynomial-time Program Equivalence for Machine Knitting</fr:link>. I think the talk really nailed the "here's the idea, the details are in the paper"-presenting style as they described an "...algorithm that canonicalizes the algebraic representations of the topological semantics of machine knitting programs".</html:p>
                  </html:li>
                  <html:li>
                    <html:p>I attended most of the <fr:link href="https://conf.researchr.org/details/icfp-splash-2025/icfp-splash-2025-tutorials/5/A-guided-tour-through-Oxidized-OCaml" type="external">OxCaml tutorial</fr:link> presented by the incredibly friendly <fr:link href="https://gavinleroy.com/" type="external">Gavin Gray</fr:link>.</html:p>
                  </html:li>
                  <html:li>
                    <html:p><fr:link href="/ryangibb/" title="Ryan Gibb" uri="https://patrick.sirref.org/ryangibb/" display-uri="ryangibb" type="local">Ryan</fr:link>'s talk <fr:link href="https://conf.researchr.org/details/icfp-splash-2025/propl-2025-papers/13/Spatial-Programming-for-Environmental-Monitoring" type="external">Spatial Programming for Environmental Monitoring</fr:link> at PROPL was excellent.</html:p>
                  </html:li>
                </html:ul>
                <html:p>There's plenty more to talk about, and I'm sure my future posts will reference other parts of my experience at ICFP 2025. Thanks for reading, and if anybody is interested in any aspects of this do reach out!</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>8</fr:month>
              <fr:day>7</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/irmin-retro/</fr:uri>
            <fr:display-uri>irmin-retro</fr:display-uri>
            <fr:route>/irmin-retro/</fr:route>
            <fr:title text="Irmin Retrospective">Irmin Retrospective</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p><fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> is an OCaml library for building <html:em>branchable</html:em> and <html:em>mergeable</html:em> data stores. The data is <html:em>mergeable</html:em> in the sense of <fr:link href="/kcrsk-mrdts-2022/" title="Certified mergeable replicated data types" uri="https://patrick.sirref.org/kcrsk-mrdts-2022/" display-uri="kcrsk-mrdts-2022" type="local">mergeable replicated data types</fr:link>.</html:p>
            <html:p>I have been using Irmin for over five years to build different kinds of interesting data stores including:</html:p>
            <html:ul>
              <html:li>
                <html:p>A <fr:link href="https://github.com/patricoferris/omditor" type="external">simple markdown-based note-taking web application</fr:link>.</html:p>
              </html:li>
              <html:li>
                <html:p>A <fr:link href="https://github.com/carboncredits/retirement-db" type="external">content-addressed database</fr:link>.</html:p>
              </html:li>
              <html:li>
                <html:p>Mentoring an intern who <fr:link href="https://tarides.com/blog/2022-08-02-irmin-in-the-browser/" type="external">worked on Irmin in the browser</fr:link>.</html:p>
              </html:li>
              <html:li>
                <html:p>Most recently, an <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Irmin-backed shell session manager</fr:link>.</html:p>
              </html:li>
            </html:ul>
            <html:p>I was asked to provide some feedback recently on <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link>, so I thought writing a little retrospective here would be a good way to do that. The remit for the retrospective was about improving <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link>, so the content is focussed on pain points and areas of improvement.</html:p>
            <html:pre class="hilite">
              <html:code><html:span class="ocaml-comment-block"><![CDATA[(*]]> </html:span><html:span class="ocaml-comment-block"> An in-memory Irmin store </html:span><html:span class="ocaml-comment-block"><![CDATA[*)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">module</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Store</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Irmin_mem</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">KV</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Make</html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Irmin</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Contents</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">String</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
            </html:pre>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>8</fr:month>
                  <fr:day>7</fr:day>
                </fr:date>
                <fr:title text="What is Irmin?">What is Irmin?</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link>, at its simplest, is a key-value database. Users associate keys with values and can query and update these bindings.</html:p>
                <html: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.</html:p>
                <html:p>Different versions of the database can be combined by <html:em>merging</html:em>. When you set up your instance of an <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> database, you also provide it with a <fr:link href="/kcrsk-mrdts-2022/" title="Certified mergeable replicated data types" uri="https://patrick.sirref.org/kcrsk-mrdts-2022/" display-uri="kcrsk-mrdts-2022" type="local">merge function</fr:link>.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source">show_type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Irmin</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Merge</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">f</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">nonrec</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-storage-type">'a</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">f</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source">old</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-storage-type">'a</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Irmin</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Merge</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">promise</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-storage-type">'a</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-storage-type">'a</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-storage-type">'a</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Irmin</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Merge</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">conflict</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">result</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Lwt</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>8</fr:month>
                  <fr:day>7</fr:day>
                </fr:date>
                <fr:title text="Design and API">Design and API</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link>'s API is very git-inspired. There is a large overlap of shared vocabulary and concepts: <html:em>repositories</html:em>, <html:em>branches</html:em>, <html:em>commits</html:em>, <html:em>heads</html:em> etc.</html:p>
                <html:p>Probably the most confusing aspect of this is the notion of a <html:code>Store</html:code>. When I was describing <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> above, I used the term <html:em>database</html:em> to help distinguish between some of these concepts. In Irmin's documentation, it is used for multiple <![CDATA[related (but different) concepts. In "]]> <fr:link href="https://irmin.org/tutorial/getting-started/#creating-a-store" type="external">Creating a Store</fr:link>" stores refer to the entire database, whereas in the <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> API docs we have that:</html:p>
                <html:blockquote>
                  <html:p>There are two kinds of store in Irmin: the ones based on persistent named branches and the ones based temporary detached heads.</html:p>
                </html:blockquote>
                <html:p>For <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> library users, a <html:code>Store.t</html: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.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Store</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">of_branch</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-operator">-</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Store</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">repo</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">string</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Store</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Lwt</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">&lt;</html:span><html:span class="ocaml-keyword-other">fun</html:span><html:span class="ocaml-keyword-operator">&gt;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Store</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">of_commit</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-operator">-</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Store</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">commit</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Store</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Lwt</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">&lt;</html:span><html:span class="ocaml-keyword-other">fun</html:span><html:span class="ocaml-keyword-operator">&gt;</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html: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.</html:p>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>8</fr:month>
                      <fr:day>7</fr:day>
                    </fr:date>
                    <fr:title text="Module and Functor Soup">Module and Functor Soup</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Undoubtedly for a majority of use-cases and users, <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> 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 <fr:link href="https://mirage.github.io/irmin/irmin/Irmin/module-type-S/Schema/index.html" type="external"><html:code>Schema</html:code> module</fr:link> when describing the types they want to instantiate their store with.</html:p>
                    <html:p>To counteract this, Irmin has plenty of <html:code>KV</html:code> modules that provide a <html:code>Make</html:code> functor that only requires a user to provide a suitable <html:em>content</html:em> module <![CDATA[for their store (i.e. something that provides a type, a runtime representation]]>  <![CDATA[of that type and a merge function).]]></html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source">show_module</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Irmin_mem</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">KV</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">module</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">KV</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">sig</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">endpoint</html:span><html:span class="ocaml-source"> = unit
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">metadata</html:span><html:span class="ocaml-source"> = unit
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">hash</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">info</html:span><html:span class="ocaml-source"> = Store.info
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[('h, _)]]> </html:span><html:span class="ocaml-entity-name-function-binding">contents_key</html:span><html:span class="ocaml-source"> = 'h
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">'h </html:span><html:span class="ocaml-entity-name-function-binding">node_key</html:span><html:span class="ocaml-source"> = 'h
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">'h </html:span><html:span class="ocaml-entity-name-function-binding">commit_key</html:span><html:span class="ocaml-source"> = 'h
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword-other-ocaml">module</html:span><html:span class="ocaml-source"><![CDATA[ Make : (C : Irmin__.Contents.S) ->]]> </html:span><html:span class="ocaml-keyword-other-ocaml">sig</html:span><html:span class="ocaml-source"> ... </html:span><html:span class="ocaml-keyword-other">end</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">end</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                    <html: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 <html:code>irmin.3.11.0</html:code>, starting at <fr:link href="https://ocaml.org/p/irmin/latest/doc/index.html" type="external">the toplevel documentation page</fr:link> our path to finding this paricular module and functor is as follows:</html:p>
                    <html:ol>
                      <html:li>
                        <html:p>We jump into <fr:link href="https://ocaml.org/p/irmin/latest/doc/irmin.mem/Irmin_mem/index.html" type="external"><html:code>Irmin_mem</html:code></fr:link> from the nicely written landing page.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>We scroll down to find <fr:link href="https://ocaml.org/p/irmin/latest/doc/irmin.mem/Irmin_mem/index.html#module-KV" type="external">the KV module</fr:link>.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>We now make sense of the module's signature by following the <fr:link href="https://ocaml.org/p/irmin/latest/doc/irmin/Irmin/module-type-KV_maker/index.html" type="external">KV_maker link</fr:link>.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>We see a <html:code><![CDATA[Make (C : Contents.S) : sig ... end]]></html:code> at the end of the module, and <fr:link href="https://ocaml.org/p/irmin/latest/doc/irmin/Irmin/module-type-KV_maker/Make/index.html#module-Schema" type="external">we navigate through that</fr:link>.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>Finally we have come to our journey's end, and find the <fr:link href="https://ocaml.org/p/irmin/latest/doc/irmin/Irmin/module-type-KV_maker/Make/index.html#module-Schema" type="external">schema module</fr:link> with type constraints like <html:code>type Branch.t = string</html:code>.</html:p>
                      </html:li>
                    </html:ol>
                    <html:p>There is a big assumption there that you know what the <html:code>Schema</html:code> module is telling you and how it relates to your "store".</html:p>
                    <html: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 <fr:link href="https://github.com/patricoferris/ocaml-cid/blob/main/test/irmin_cid.ml" type="external"><![CDATA[Irmin stores that use CIDs (self-describing content identifiers)]]> </fr:link> for example.</html:p>
                    <html: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 <fr:link href="https://ocaml.org/p/irmin-containers/latest/doc/irmin-containers/Irmin_containers/index.html" type="external">introductory libraries like irmin-containers</fr:link> would be helpful. Perhaps a <html:em>standalone</html:em> library that acts as an interface to Irmin stores would be helpful. I find myself time and again implementing <fr:link href="https://github.com/fn06/shelter/blob/main/src/lib/store.ml" type="external">something like that</fr:link>.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>8</fr:month>
                      <fr:day>7</fr:day>
                    </fr:date>
                    <fr:title text="Backends Galore">Backends Galore</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Irmin has plenty of backends including <fr:link href="https://ocaml.org/p/irmin-git/latest" type="external">a git-compatible one</fr:link>, <fr:link href="https://ocaml.org/p/irmin-mirage/latest" type="external">a MirageOS backend</fr:link>, <fr:link href="https://ocaml.org/p/irmin-indexeddb/latest" type="external">an in-browser IndexedDB backend</fr:link> and even a <fr:link href="https://github.com/andreas/irmin-fdb" type="external">FoundationDB backend</fr:link>.</html:p>
                    <html:p><fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> 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, <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> 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 <fr:link href="https://lofi.so/" type="external">local-first applications</fr:link>.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>8</fr:month>
                      <fr:day>7</fr:day>
                    </fr:date>
                    <fr:title text="Syncing Remote Stores">Syncing Remote Stores</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>The <fr:link href="https://ocaml.org/p/irmin/3.11.0/doc/irmin/Irmin/Sync/index.html" type="external">synchronisation mechanisms in Irmin</fr:link> 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 <fr:link href="https://ocaml.org/p/irmin-git/latest/doc/irmin-git.unix/Irmin_git_unix/Maker/Make/index.html#val-remote" type="external">remote endpoint</fr:link>. Once they have found this function, using it is not easy as it requires them to learn about the <fr:link href="https://ocaml.org/p/mimic/latest" type="external"><html:code>Mimic.ctx</html:code></fr:link>, which is an abstraction of the networking stack!</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>8</fr:month>
                      <fr:day>7</fr:day>
                    </fr:date>
                    <fr:title text="Do Fewer Things and Do Them Well">Do Fewer Things and Do Them Well</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html: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.</html:p>
                    <html:p>When building the <fr:link href="https://github.com/carboncredits/retirement-db" type="external">content-addressed database</fr:link> I needed strong guarantees about some atomic actions to perform on the underlying store. For example, <fr:link href="https://github.com/mirage/irmin/issues/2073" type="external">setting the value and accessing the commit associated with it</fr:link> 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.</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>8</fr:month>
                  <fr:day>7</fr:day>
                </fr:date>
                <fr:title text="Documentation">Documentation</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>It will probably come as no surprise that one of the main limitations of using <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> is the lack of documentation and tutorials. This is a particular pain point as the API is not very straightforward.</html:p>
                <html:p>A while back, I started an <fr:link href="https://patricoferris.github.io/irmin-book/" type="external">Irmin book</fr:link> intending to help document the kinds of things real-world users would need in order to use <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> in earnest. For example: ways to <fr:link href="https://patricoferris.github.io/irmin-book/contents/versioned-data.html" type="external">deal with type migrations</fr:link> or <fr:link href="https://patricoferris.github.io/irmin-book/arch/runtime-types.html" type="external">primers on runtime types</fr:link>. 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.</html:p>
                <html:p>The <fr:link href="https://irmin.org/tutorial/introduction/" type="external">tutorials on the irmin website</fr:link> are still good starting points for most new users. But they quickly lack the depth for real-world scenarios.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>8</fr:month>
                  <fr:day>7</fr:day>
                </fr:date>
                <fr:title text="Feature Wishlist">Feature Wishlist</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>What follows are additional ideas for improving <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link>.</html:p>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>8</fr:month>
                      <fr:day>7</fr:day>
                    </fr:date>
                    <fr:title text="Heterogeneous Stores">Heterogeneous Stores</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html: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.</html:p>
                    <html:p>This leads to a few common workarounds:</html:p>
                    <html:ul>
                      <html:li>
                        <html:p>Storing a serealised version of your values, essentially escaping the type-system and implementing a form of dynamic typing.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>Growing your value to hold lots of different types via some large variant type.</html:p>
                      </html:li>
                    </html:ul>
                    <html:p>Both of these options are feasible and have been used in practice. However, they are workarounds. A long time ago <fr:link href="https://craigfe.io/" type="external">CraigFe</fr:link> created an <fr:link href="https://github.com/mirage/irmin/issues/909" type="external">RFC for heterogeneous stores</fr:link>, which I think about a lot. The main idea is to augment <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link><![CDATA[ paths (keys)]]>  to be GADTs that carry type information about the kinds of values they access <![CDATA[(similar to]]> <fr:link href="https://ocaml.org/p/hmap" type="external">heterogeneuous variants of other data structures</fr:link><![CDATA[). Something like this alongside a simplified]]>  API would make Irmin more appealing as a library for persistent data storage.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>8</fr:month>
                      <fr:day>7</fr:day>
                    </fr:date>
                    <fr:title text="Real-world Retrospectives">Real-world Retrospectives</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>This echos some thoughts from the <html:em>Documentation</html:em> section. There are some very real-world <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link><![CDATA[ use-cases out there. For example, for a long time (I'm not]]>  <![CDATA[sure if this is still the case) parts of the]]> <fr:link href="https://ocaml.org/p/tezos-context/latest#dependencies" type="external">Tezos blockchain were using Irmin</fr:link> which uses the <fr:link href="https://ocaml.org/p/irmin-pack/latest" type="external">irmin-pack</fr:link> 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 <fr:link href="https://tarides.com/blog/2020-09-01-introducing-irmin-pack/" type="external">blogs on tarides.com about the irmin-pack backend</fr:link>, but they might be outdated and should not be the first place to find advice on which Irmin backend to use.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>8</fr:month>
                      <fr:day>7</fr:day>
                    </fr:date>
                    <fr:title text="Active Development and Engagement">Active Development and Engagement</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>As far as I know, <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> was at the forefront of technologies that have come to be described as <fr:link href="https://lofi.so/" type="external">local-first</fr:link>. There is a growing interest <![CDATA[in this area (particularly as it acts as a counter-argument to an increasingly]]>  <![CDATA[online, centralised model). I highly recommend reading]]> <fr:link href="https://patrick.sirref.org/ink &amp; switch's essay on the matter/" type="external">Ink &amp; Switch's essay on the matter</fr:link>. And it would be great to see more research via <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> at things like <fr:link href="https://lu.ma/localfirstswunconf-stlouis" type="external">the lofi unconference</fr:link> and the <fr:link href="https://2023.splashcon.org/home/plf-2023" type="external">PLF workshop at SPLASH 2023</fr:link>!</html:p>
                    <html:p>Thank you for reading! And thank you to all the <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> contributors. I hope this might be useful in the future for building the next-generation <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link>!</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>7</fr:month>
              <fr:day>23</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/slipshow-x-xocaml/</fr:uri>
            <fr:display-uri>slipshow-x-xocaml</fr:display-uri>
            <fr:route>/slipshow-x-xocaml/</fr:route>
            <fr:title text="Slipshow x x-ocaml">Slipshow x x-ocaml</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>A short, explanatory post about combining two very fun pieces of work in OCaml.</html:p>
            <html:p><fr:link href="https://github.com/panglesd" type="external">Paul-Elliot</fr:link> has been building <fr:link href="https://github.com/panglesd/slipshow" type="external">Slipshow</fr:link> for some time now where slides are <html:em>slips</html:em> and your presentations run vertically. More recently, <fr:link href="/artw/" title="Arthur Wendling" uri="https://patrick.sirref.org/artw/" display-uri="artw" type="local">Arthur</fr:link> has built <fr:link href="https://github.com/art-w/x-ocaml" type="external">x-ocaml</fr:link>, a web component library for executable OCaml cells embedded into OCaml.</html:p>
            <html:p>Using <fr:link href="https://github.com/patricoferris/xocmd" type="external">xocmd</fr:link>, a small tool I built for translating markdown codeblocks to x-ocaml components, your Slipshow's can now be <html:em>executable</html:em>!</html:p>
            <html:pre><![CDATA[xocmd learn-effects.md | slipshow compile - > learn-effects.html]]></html:pre>
            <html:p>
    Take a look at 
    <html:a href="/bafkrmictvc3ap2ah37cbcdoo6rsl7vxqu6srogmgzx6iml45bq7zz5weo4.html">an example</html:a>!
    (or the 
    <html:a href="/bafkrmib3jugpkznxcftqjvhbbtfqgx4oz2m32p5xloh4nxia3lhxy2momq.md">source markdown</html:a>).
</html:p>
            <html:p>I really like this light-weight approach to building interactive presentations <![CDATA[for explaining things in OCaml (e.g. over running a jupyter notebook server).]]></html:p>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>7</fr:month>
              <fr:day>18</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/ocaml-quarterly-q2/</fr:uri>
            <fr:display-uri>ocaml-quarterly-q2</fr:display-uri>
            <fr:route>/ocaml-quarterly-q2/</fr:route>
            <fr:title text="Quarterly OCaml Q2">Quarterly OCaml Q2</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>Thanks to <fr:link href="https://patrick.sirref.org/tarides/" type="external">Tarides</fr:link> sponsorship, I get to work on open-source OCaml. This quarterly is a companion to my <fr:link href="/weeklies/" title="Patrick Ferris' Weeklies" uri="https://patrick.sirref.org/weeklies/" display-uri="weeklies" type="local">weeklies</fr:link>, summarising the last three months of development, peppered with ideas and thoughts about OCaml, its community and its future.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>7</fr:month>
                  <fr:day>18</fr:day>
                </fr:date>
                <fr:title text="What I wanted to work on?">What I wanted to work on?</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>There were two main things I hoped to <html:em>continue</html:em> working on: <html:strong>ppxlib</html:strong> and <html:strong>outreachy</html:strong>. These are projects that I was previously working on, and in the case of Outreachy I have now been involved for many years.</html:p>
                <html:p>In addition to this, all of my <fr:link href="/part-ii-2024/" title="Part II Students 2024" uri="https://patrick.sirref.org/part-ii-2024/" display-uri="part-ii-2024" type="local">Part II</fr:link> 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 <fr:link href="https://ocaml-explore.netlify.app/" type="external">my initial work on developing workflows for OCaml that just turned five years old</fr:link>. This directly fed into the rebranding and rethinking of <fr:link href="https://ocaml.org/" type="external">ocaml.org</fr:link> itself.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>7</fr:month>
                  <fr:day>18</fr:day>
                </fr:date>
                <fr:title text="What I worked on?">What I worked on?</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>7</fr:month>
                      <fr:day>18</fr:day>
                    </fr:date>
                    <fr:title text="Ppxlib">Ppxlib</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p><fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">Ppxlib</fr:link> is the de facto standard library for building OCaml preprocessors. At the time of writing, <html:code>opam list --depends-on=ppxlib</html:code> informs me that there are 267 reverse dependencies. <fr:link href="https://www.janestreet.com/" type="external">Janestreet</fr:link> is a heavy user of ppxes and has <fr:link href="https://github.com/orgs/janestreet/repositories?language=&amp;amp;q=ppx&amp;amp;sort=&amp;amp;type=all" type="external">authored many</fr:link>.</html:p>
                    <html:p>One of the main accomplishments this quarter was <fr:link href="/ppxlib-5-2/" title="Bumping Ppxlib's AST to 5.2" uri="https://patrick.sirref.org/ppxlib-5-2/" display-uri="ppxlib-5-2" type="local">bumping the internal AST to 5.2</fr:link>. 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 <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link>.</html:p>
                    <html: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 <![CDATA[factor in the churn of breaking changes (in the case of OCaml this is via]]> <fr:link href="https://github.com/ocaml/opam-repository/" type="external">PRs to the opam-repository</fr:link><![CDATA[). 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.</html:p>
                    <html:p><fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">Ppxlib</fr:link> sits awkwardly in the space of possible breaking changes. Tied to OCaml's parsetree, impacts of changes there ripple down to <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link>. The compiler itself can remain internally consistent, and is protected as it need only parse source code. <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">Ppxlib</fr:link>, 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 <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link>, it feels as though the number of syntax changes <![CDATA[has gone up (primarily from Janestreet work). Unless we make changes to how we provide]]>  support for these, maintainers of <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> will forever be stuck doing busy work! Thankfully, <fr:link href="/nathanreb/" title="Nathan Rebours" uri="https://patrick.sirref.org/nathanreb/" display-uri="nathanreb" type="local">Nathan</fr:link> <fr:link href="/ocaml-weekly-2025-w29/" title="OCaml Weekly 2025 w29" uri="https://patrick.sirref.org/ocaml-weekly-2025-w29/" display-uri="ocaml-weekly-2025-w29" type="local">has thoughts on how to improve this</fr:link>.</html:p>
                    <html:p>There are a slew of other features I have added to <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> including:</html:p>
                    <html:ul>
                      <html:li>
                        <html:p>Support for deriving from classes.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>Support for deriving from module bindings and signatures.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>Fixing compiler and ppxlib dummy locations.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>Bumping to 5.3.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>Migrations for 5.4.</html:p>
                      </html:li>
                    </html:ul>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>7</fr:month>
                      <fr:day>18</fr:day>
                    </fr:date>
                    <fr:title text="Outreachy">Outreachy</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Our two projects this year, one on <fr:link href="https://github.com/claudiusFX/claudius" type="external">claudius</fr:link> and one on <fr:link href="https://github.com/ocaml/dune" type="external">dune</fr:link>, are going extremely well. At the time of writing, we just had <fr:link href="/ocaml-weekly-2025-w29/" title="OCaml Weekly 2025 w29" uri="https://patrick.sirref.org/ocaml-weekly-2025-w29/" display-uri="ocaml-weekly-2025-w29" type="local">a mid-internship call to catch up</fr:link>, and I was blown away by the progress each intern has made. Unfortunately, <fr:link href="/outreachy/" title="Outreachy" uri="https://patrick.sirref.org/outreachy/" display-uri="outreachy" type="local">Outreachy</fr:link> 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.</html:p>
                    <html:p>Outreachy has been a wonderful source of new, committed OCaml developers. If you haven't already, do peruse the <fr:link href="https://ocaml.org/outreachy" type="external">webpage on OCaml.org</fr:link> to see past internships or <fr:link href="https://watch.ocaml.org/c/outreachy_ocaml/videos" type="external">watch the demo day presentations</fr:link>. For the mentors involved, <![CDATA[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 <fr:link href="/patrickferris/" title="Patrick Ferris" uri="https://patrick.sirref.org/patrickferris/" display-uri="patrickferris" type="local">do reach out to me</fr:link> if you are interested.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>7</fr:month>
                      <fr:day>18</fr:day>
                    </fr:date>
                    <fr:title text="Hazel">Hazel</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p><![CDATA[OCaml's feature set allows it to shine at writing programming languages (and]]>  <![CDATA[things of that ilk: compilers, interpretters, static analysis tools).]]> <fr:link href="/hazel/" title="Hazel" uri="https://patrick.sirref.org/hazel/" display-uri="hazel" type="local">Hazel</fr:link> is a research programming language with typed holes written completely in OCaml <![CDATA[(via the]]> <fr:link href="https://reasonml.github.io/" type="external">reason dialect</fr:link><![CDATA[).]]></html:p>
                    <html: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 <fr:link href="/hazel_of_ocaml/" title="hazel_of_ocaml" uri="https://patrick.sirref.org/hazel_of_ocaml/" display-uri="hazel_of_ocaml" type="local">OCaml to Hazel</fr:link>. Whilst new features are still being added to <fr:link href="/hazel/" title="Hazel" uri="https://patrick.sirref.org/hazel/" display-uri="hazel" type="local">Hazel</fr:link>, I hope this could serve as a tool to help develop test-suites and standard library functions using existing <![CDATA[OCaml solutions. In a student's work (]]> <fr:link href="/part-ii-hazel/" title="Type Error Debugging in Hazel" uri="https://patrick.sirref.org/part-ii-hazel/" display-uri="part-ii-hazel" type="local">Typed Debugging for Hazel</fr:link><![CDATA[), we used this tool to build a corpus of ill-typed]]>  <fr:link href="/hazel/" title="Hazel" uri="https://patrick.sirref.org/hazel/" display-uri="hazel" type="local">Hazel</fr:link> programs to great effect.</html:p>
                    <html: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 <fr:link href="/hazel/" title="Hazel" uri="https://patrick.sirref.org/hazel/" display-uri="hazel" type="local">Hazel</fr:link> and provide some low effort maintenance to help keep their compiler in good shape.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>7</fr:month>
                      <fr:day>18</fr:day>
                    </fr:date>
                    <fr:title text="Systems Programming in OCaml">Systems Programming in OCaml</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>In a cross-over with my own research, I have been developing many tools related to systems programming in OCaml including:</html:p>
                    <html:ul>
                      <html:li>
                        <html:p>An eBPF-based <fr:link href="/open-trace/" title="Opentrace" uri="https://patrick.sirref.org/open-trace/" display-uri="open-trace" type="local"><html:code>open</html:code> syscall tracing tool</fr:link>.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>A library in OCaml for <fr:link href="https://github.com/quantifyearth/void" type="external">spawning void processes</fr:link>.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>A <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">shell session manager</fr:link> that uses <fr:link href="https://irmin.org/" type="external">Irmin</fr:link> to manage sessions. It is nice to see a new push to <fr:link href="https://github.com/mirage/irmin/pull/2149" type="external">finally land the direct-style Irmin PR</fr:link>!</html:p>
                      </html:li>
                    </html:ul>
                    <html:p>This work is means to develop the underlying libraries that support it. For example, I have opened a few PRs to <fr:link href="https://github.com/ocaml-multicore/eio" type="external">Eio</fr:link> to add new "fork actions" to the spawn API. I also investigated the feasibility of changing the underlying mechanisms in <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link> to use <fr:link href="https://github.com/ocaml-multicore/picos" type="external">Picos</fr:link>. In the future, I think this could be important avoid further splitting the OCaml ecosystem.</html:p>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>7</fr:month>
                          <fr:day>18</fr:day>
                        </fr:date>
                        <fr:title text="OxCaml">OxCaml</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>I dabbled a little with <fr:link href="https://oxcaml.org/" type="external">OxCaml</fr:link> and build <fr:link href="/try-oxcaml/" title="Try OxCaml" uri="https://patrick.sirref.org/try-oxcaml/" display-uri="try-oxcaml" type="local">try-oxcaml</fr:link> 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 <![CDATA[(type definitions differeing between js_of_ocaml and the OxCaml compiler, resulting]]>  <![CDATA[in different Javascript runtime representations...).]]></html:p>
                        <html:p>This unblocked a few of my colleagues to get OxCaml working on tools like <fr:link href="https://jon.recoil.org/notebooks/foundations/foundations1.html" type="external">odoc_notebooks</fr:link> and <fr:link href="https://github.com/art-w/x-ocaml" type="external">x-ocaml</fr:link>.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>7</fr:month>
                      <fr:day>18</fr:day>
                    </fr:date>
                    <fr:title text="Forester">Forester</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>A good proportion of my work this quarter has been focused on how to present the very work that I am doing. <fr:link href="/jonmsterling/" title="Jon Sterling" uri="https://patrick.sirref.org/jonmsterling/" display-uri="jonmsterling" type="local">Jon Sterling</fr:link> has been developing a tool for scientific thought called <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link> which seemed like a possible candidate for writing and sharing my work.</html:p>
                    <html: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 <![CDATA[made use of additional markdown-based tools (like]]> <fr:link href="https://github.com/realworldocaml/mdx" type="external">ocaml-mdx</fr:link><![CDATA[).]]></html:p>
                    <html:p>This lead to the development of <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">Graft</fr:link>: a preprocessor for Forester forests, converting markdown and bibtex to trees.</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>7</fr:month>
                  <fr:day>18</fr:day>
                </fr:date>
                <fr:title text="What's next?">What's next?</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>So, I worked on most of what I wanted to work on and then some! Going forward I hope to keep maintaining <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> in some capacity and coordinating the OCaml community's <fr:link href="/outreachy/" title="Outreachy" uri="https://patrick.sirref.org/outreachy/" display-uri="outreachy" type="local">Outreachy</fr:link> efforts.</html:p>
                <html:p><![CDATA[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 <fr:link href="https://github.com/raven-ml/" type="external">Raven</fr:link>: I am interested to use this library in <fr:link href="/geocaml/" title="Geocaml" uri="https://patrick.sirref.org/geocaml/" display-uri="geocaml" type="local">Geocaml</fr:link>, a suite of geospatial tools written in OCaml that I maintain.</html:p>
                <html:p>I feel conflicted about the <fr:link href="https://patrick.sirref.org/oxcaml/" type="external">OxCaml</fr:link> 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 <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> 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 <fr:link href="https://patrick.sirref.org/oxcaml/" type="external">OxCaml</fr:link> 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.</html:p>
                <html:p>Finally, over the past two years I have done a lot of teaching. From <fr:link href="/part-ii/" title="Part II Projects" uri="https://patrick.sirref.org/part-ii/" display-uri="part-ii" type="local">Part II projects</fr:link> to <fr:link href="/focs/" title="Foundations of Computer Science" uri="https://patrick.sirref.org/focs/" display-uri="focs" type="local">supervisions</fr:link><![CDATA[. 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 <fr:link href="https://beautifulracket.com/" type="external">Beautiful Racket</fr:link>. I have tried in the past to do these sorts of things, for example <fr:link href="https://patricoferris.github.io/irmin-book/" type="external">The Irmin Book</fr:link>.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>7</fr:month>
                  <fr:day>18</fr:day>
                </fr:date>
                <fr:title text="Thank you">Thank you</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Thank you for reading this wrap up! And thank you again to <fr:link href="https://patrick.sirref.org/tarides/" type="external">Tarides</fr:link> for letting me work so freely on things that I think are good for the OCaml community.</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>5</fr:month>
              <fr:day>19</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/open-trace/</fr:uri>
            <fr:display-uri>open-trace</fr:display-uri>
            <fr:route>/open-trace/</fr:route>
            <fr:title text="Opentrace">Opentrace</fr:title>
            <fr:meta name="external">https://tangled.sh/@patrick.sirref.org/opentrace</fr:meta>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>Thanks to <fr:link href="https://github.com/koonwen/" type="external">Koonwen's</fr:link> excellent <fr:link href="https://github.com/koonwen/ocaml-libbpf" type="external">libbpf bindings in OCaml</fr:link>, I have been building a little tool called <html:code>opentrace</html:code> to make it easier to track an executable's inputs and outputs.</html:p>
            <html:p>This work was inspired my <fr:link href="/mdales/" title="Michael W. Dales" uri="https://patrick.sirref.org/mdales/" display-uri="mdales" type="local">Michael's</fr:link> self-proclaimed "gross hack": <fr:link href="https://github.com/quantifyearth/pyshark" type="external">pyshark</fr:link>. Whilst pyshark achieves its goals by injecting code into commonly used python objects and methods, <fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">opentrace</fr:link> uses <fr:link href="https://ebpf.io/" type="external">eBPF</fr:link><![CDATA[. By using a lower-level API (hooks in the kernel),]]> <fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">opentrace</fr:link> can remain programming language agnostic. However, less information is none about the user's intent compared to something like pyshark.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>5</fr:month>
                  <fr:day>19</fr:day>
                </fr:date>
                <fr:title text="Monitoring the System">Monitoring the System</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">opentrace</fr:link> has an <html:code>all</html:code> command that will trace the entire system.</html:p>
                <html: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]]></html:pre>
                <html:p>The <html:code>--flags=O_WRONLY</html:code> argument filters the events where the <html:code>O_WRONLY</html:code> flag was set in the call to <html:code>open</html:code>.</html:p>
                <html:p><![CDATA[We also get the name of the current executable linked to the task (]]> <html:code>comm</html:code><![CDATA[). The]]> <html:code>-wrapped</html:code> is an artefact of using Nix.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>5</fr:month>
                  <fr:day>19</fr:day>
                </fr:date>
                <fr:title text="Tracing an Executable">Tracing an Executable</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>The primary use case for this tool is to inspect what files your program might be reading and writing.</html:p>
                <html: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"]]></html:pre>
                <html:p>The "flags" argument can specify a small boolean formula for checking the open flags of a particular event with <html:code>|</html:code><![CDATA[ (or),]]> <html:code>&amp;</html:code><![CDATA[ (and), and]]> <html:code>~</html:code><![CDATA[ (not).]]>  Parentheses can be used for precedence.</html:p>
                <html:pre><![CDATA[$ sudo opentrace exec --flags="O_WRONLY|O_RDONLY" -- ocaml --version]]></html:pre>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>5</fr:month>
                  <fr:day>19</fr:day>
                </fr:date>
                <fr:title text="Spawning Subprocesses">Spawning Subprocesses</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>One feature <fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">opentrace</fr:link><![CDATA[ needs (in this proof-of-concept phase) is the ability to also trace subprocesses.]]></html:p>
                <html:p><fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">opentrace</fr:link> 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, <fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">opentrace</fr:link><![CDATA[ creates a new control group (cgroup) and places the new process into that group.]]>  This gives <fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">opentrace</fr:link> a new identifier to track, namely the cgroup.</html:p>
                <html:p>So consider the following program.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword-other">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-unit"><![CDATA[()]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-constant-language-capital-identifier">Eio_posix</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">run</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">@@</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">fun</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">env</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-constant-language-capital-identifier">Eio</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Path</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">save</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">create</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-polymorphic-variant">`Or_truncate</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-octal-integer">0o664</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">env</html:span><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source">fs</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">/</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">hello.txt</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">hello</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-constant-language-capital-identifier">Eio</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Process</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">run</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">env</html:span><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source">process_mgr</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">/bin/bash</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">-c</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">echo 'heya' &gt; heya.txt</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html:p>It first creates a file using direct calls to functions like <html:code>openat</html:code>. Then it spawns a process which creates a new file called <html:code>heya.txt</html:code>. This happens in a separate process. However, with the <html:code>--cgroups</html:code> flag we can capture both interactions with the operating system.</html:p>
                <html: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]]></html:pre>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>5</fr:month>
                      <fr:day>19</fr:day>
                    </fr:date>
                    <fr:title text="Eio's Process API">Eio's Process API</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>I have used the <html:code>Eio_unix</html:code> <fr:link href="https://ocaml.org/p/eio/latest/doc/Eio_unix/Process/index.html" type="external">fork action process API</fr:link> 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 <html:code>sudo</html:code>. When a user requests for a particular program to be executed and traced, <fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">opentrace</fr:link> spawns a process via the Eio Process API. <fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">Opentrace</fr:link> defines a few new so-called "fork actions", little fragments of C code that are run after the call to <html:code>fork</html:code><![CDATA[ (]]> <html:code>clone</html:code><![CDATA[).]]>  Most likely this ends with a call to <html:code>execve</html:code>, but other calls are possible for example <html:code>setuid</html:code> allowing <fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">opentrace</fr:link> to change the user of the child process so it does not run as <html:code>root</html:code><![CDATA[. Similarly, this is where (if used) we create the cgroup and place the process]]>  into that group.</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>5</fr:month>
                  <fr:day>19</fr:day>
                </fr:date>
                <fr:title text="Limitations: Io_uring">Limitations: Io_uring</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Whilst testing <html:code>opentrace</html:code> against some of the tools I use nearly daily, I noticed some events were being missed. I tried tracing <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">forester</fr:link>, and only the initial read of <html:code>forest.toml</html:code> was logged. It dawned on me that the reason for this was that <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">forester</fr:link><![CDATA[ (via]]> <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">eio</fr:link><![CDATA[) was using]]> <fr:link href="https://patrick.sirref.org/io_uring/" type="external">io_uring</fr:link> 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 <html:code>openat2</html:code>-style call!</html:p>
                <html:p>This is not news to seasoned, Linux systems programmers. Io_uring <fr:link href="https://blog.0x74696d.com/posts/iouring-and-seccomp/" type="external">bypasses <html:code>SECCOMP</html:code> filters</fr:link> for exactly the same reasons.</html:p>
                <html: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]]></html:pre>
                <html:p>It is interesting to note two things here:</html:p>
                <html:ol>
                  <html:li>
                    <html:p>We can tell that <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">forester</fr:link> reads the configuration file probably using something like <html:code>In_channel</html:code><![CDATA[ in OCaml (]]> <fr:link href="https://git.sr.ht/~jonsterling/ocaml-forester/tree/7f275290e211db2590b0d715d8fb47fc1de36550/item/lib/frontend/Config.ml#L22" type="external">it does</fr:link><![CDATA[).]]></html:p>
                  </html:li>
                  <html:li>
                    <html:p>It appears that Uring is performing IO in both worker threads and directly.</html:p>
                  </html:li>
                </html:ol>
                <html: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. <![CDATA[I have tried quite a few methods (e.g. tracing]]> <html:code>do_filp_open</html:code><![CDATA[) and at the moment I am tracing]]> <html:code>io_openat2</html: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!</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>5</fr:month>
              <fr:day>9</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/try-oxcaml/</fr:uri>
            <fr:display-uri>try-oxcaml</fr:display-uri>
            <fr:route>/try-oxcaml/</fr:route>
            <fr:title text="Try OxCaml">Try OxCaml</fr:title>
            <fr:meta name="external">https://patrick.sirref.org/oxcaml</fr:meta>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>This week, I have been trying out Janestreet's <fr:link href="https://blog.janestreet.com/oxidizing-ocaml-locality/" type="external">Oxidised OCaml</fr:link><![CDATA[ (see their]]> <fr:link href="/oxcaml-2024/" title="Oxidizing OCaml with Modal Memory Management" uri="https://patrick.sirref.org/oxcaml-2024/" display-uri="oxcaml-2024" type="local">ICFP paper</fr:link><![CDATA[).]]>  This adds a system of <html:em>modes</html:em> to OCaml for expressing things like locality.</html:p>
            <html:blockquote>
              <html: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.</html:p>
            </html:blockquote>
            <html:p>For example, you might say:</html:p>
            <html:pre class="hilite">
              <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">is_empty</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">s</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">string</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">@@</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">local</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-constant-language-capital-identifier">String</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">length</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">s</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">0</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
            </html:pre>
            <html:p>To get a feel for how this changes the language, you can follow their <fr:link href="https://github.com/janestreet/opam-repository/tree/with-extensions" type="external">instructions on their custom opam-repository</fr:link>. Alternatively, you can <fr:link href="https://patrick.sirref.org/oxcaml" type="external">give it a go in your browser</fr:link>! This is a full toplevel running with <html:code>Base</html:code><![CDATA[ installed (which has plenty of OxCaml annotations on Stdlib-like functions).]]></html:p>
            <html:p>Happy OxCamling!</html:p>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>5</fr:month>
              <fr:day>2</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/hazel-of-ocaml/</fr:uri>
            <fr:display-uri>hazel-of-ocaml</fr:display-uri>
            <fr:route>/hazel-of-ocaml/</fr:route>
            <fr:title text="A Transpiler from OCaml to Hazel">A Transpiler from OCaml to Hazel</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>Over the past few months, I have been piecing together a transpiler from <fr:link href="/hazel/" title="Hazel" uri="https://patrick.sirref.org/hazel/" display-uri="hazel" type="local">Hazel</fr:link> to OCaml. This is, in part, to help one of my third-year undergraduate students who is working on <fr:link href="/part-ii-hazel/" title="Type Error Debugging in Hazel" uri="https://patrick.sirref.org/part-ii-hazel/" display-uri="part-ii-hazel" type="local">type error debugging in Hazel</fr:link>.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>5</fr:month>
                  <fr:day>2</fr:day>
                </fr:date>
                <fr:title text="Typed Holes">Typed Holes</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><fr:link href="/hazel/" title="Hazel" uri="https://patrick.sirref.org/hazel/" display-uri="hazel" type="local">Hazel</fr:link> is a <fr:link href="/omar-hazel-2017/" title="Hazelnut: a bidirectionally typed structure editor calculus" uri="https://patrick.sirref.org/omar-hazel-2017/" display-uri="omar-hazel-2017" type="local">functional programming language with typed holes</fr:link>. 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.</html:p>
                <html:p>To get a flavour of Hazel, take a regular map function for lists.</html:p>
                <html: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])]]></html:pre>
                <html:p><![CDATA[The question mark (]]> <html:code>?</html:code><![CDATA[) is a hole. The program evaluates to the following expression of type]]> <html:code><![CDATA[[?]]]></html:code><![CDATA[ (for people more]]>  familiar with OCaml types <html:code>? list</html:code><![CDATA[).]]></html:p>
                <html:pre><![CDATA[[ ?, ?, ? ]]]></html:pre>
                <html:p>Hazel supports <fr:link href="/zhao-typeerror-2024/" title="Total Type Error Localization and Recovery with Holes" uri="https://patrick.sirref.org/zhao-typeerror-2024/" display-uri="zhao-typeerror-2024" type="local">local type inference</fr:link> but nothing involving unification variables. For example, a simple <html:code>add_one</html:code> function in <fr:link href="/hazel/" title="Hazel" uri="https://patrick.sirref.org/hazel/" display-uri="hazel" type="local">Hazel</fr:link><![CDATA[ (]]> <html:code>fun x -&gt; x + 1</html:code><![CDATA[) has type]]> <html:code>? -&gt; Int</html:code>.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>5</fr:month>
                  <fr:day>2</fr:day>
                </fr:date>
                <fr:title text="From OCaml to Hazel">From OCaml to Hazel</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html: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 <![CDATA[boilerplate code (e.g. URI parsing or standard library functions for strings).]]></html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>5</fr:month>
                      <fr:day>2</fr:day>
                    </fr:date>
                    <fr:title text="A Transformation of Syntax">A Transformation of Syntax</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Hazel markets itself as an "Elm/ML-like functional programming language". From the previous example of <html:code>map</html:code>, it should be apparent just how close to OCaml the language is.</html:p>
                    <html:p>It turns out that a majority of the transpiler is a <html:em>transformation of syntax</html:em>. Take a simple ADT for an arithmetic programming language.</html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-keyword-other">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">expr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Float</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">of</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">float</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Add</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">of</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">expr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">*</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">expr</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Sub</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">of</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">expr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">*</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">expr</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Mul</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">of</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">expr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">*</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">expr</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Div</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">of</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">expr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">*</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">expr</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                    <html:p>And when we run <fr:link href="/hazel_of_ocaml/" title="hazel_of_ocaml" uri="https://patrick.sirref.org/hazel_of_ocaml/" display-uri="hazel_of_ocaml" type="local">hazel_of_ocaml</fr:link> over this OCaml type declaration.</html:p>
                    <html:pre><![CDATA[type expr =
  + Float(Float)
  + Add((expr, expr))
  + Sub((expr, expr))
  + Mul((expr, expr))
  + Div((expr, expr))
 in ?]]></html:pre>
                    <html:p>Not much has changed expect some syntax. <fr:link href="/hazel/" title="Hazel" uri="https://patrick.sirref.org/hazel/" display-uri="hazel" type="local">Hazel</fr:link> does not have a notion of top-level expression so <fr:link href="/hazel_of_ocaml/" title="hazel_of_ocaml" uri="https://patrick.sirref.org/hazel_of_ocaml/" display-uri="hazel_of_ocaml" type="local">hazel_of_ocaml</fr:link> 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 <![CDATA[with no support for modules or labelled records out of the box (there are plenty of development branches]]>  <![CDATA[with these features).]]></html:p>
                    <html:p>If we try out the same <html:code>map</html:code> function but written in OCaml and transpiled to Hazel we get.</html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword">rec </html:span><html:span class="ocaml-entity-name-function-binding">map</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">f</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">function</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-list"><![CDATA[[]]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-list"><![CDATA[[]]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">x</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">xs</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">f</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">x</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">map</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">f</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">xs</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                    <html:p>Which becomes the following hazel program.</html:p>
                    <html:pre><![CDATA[let map = fun f -> fun x1 -> case x1
  | [] => []
  | x :: xs => f(x) :: map(f)(xs)
end in ?]]></html:pre>
                    <html:p>We could have a field day discussing the syntax of OCaml and Hazel <![CDATA[(parentheses for function arguments, well-scoped cases for pattern-matching, a]]>  <![CDATA[different arrow for pattern-matching etc.). What would be more interesting is]]>  taking a look at how to handle polymorphism in Hazel.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>5</fr:month>
                      <fr:day>2</fr:day>
                    </fr:date>
                    <fr:title text="Explicit Polymorphism">Explicit Polymorphism</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Hazel has <html:em>explicit polymorphism</html:em>. So far, we have not seen it as we have let the types have holes in them. The <html:code>map</html:code> function in OCaml has the following type.</html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-keyword-other">val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">map</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> 
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-storage-type">'a</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-storage-type">'b</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-storage-type">'a</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">list</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-storage-type">'b</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">list</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                    <html:p><![CDATA[We must remind ourselves (by reading]]> <fr:link href="https://www.craigfe.io/posts/polymorphic-type-constraints" type="external">Craig's excellent blogpost on the matter</fr:link><![CDATA[) that in OCaml]]></html:p>
                    <html:blockquote>
                      <html:p>... type variables in signatures are implicitly universally-quantified</html:p>
                    </html:blockquote>
                    <html:p>So in reality, we have that <html:code>map</html:code> has the following type.</html:p>
                    <html:pre><![CDATA[val map : ∀ a b. (a ->  b) -> a list -> b list]]></html:pre>
                    <html:p>In Hazel, we have to explicitly type our <html:code>map</html: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 <html:code>map</html:code><![CDATA[ function (whether that be recursively or somewhere later in our]]>  <![CDATA[program).]]></html:p>
                    <html: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])]]></html:pre>
                    <html:p><html:code>forall</html:code> introduces a universally quantified type variable into our type annotation, and <html:code>typfun</html:code><![CDATA[ introduces it into the function itself (à la System F). Type application]]>  requires <html:code>@&lt;T&gt;</html:code> where <html:code>T</html:code> is some type. This allows hazel to quite easily support higher rank polymorphism, but we will not worry too much about that.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>5</fr:month>
                      <fr:day>2</fr:day>
                    </fr:date>
                    <fr:title text="Propagating OCaml Types into Hazel">Propagating OCaml Types into Hazel</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Most often, OCaml users interact with <html:em>prenex</html:em><![CDATA[ polymorphism (rank-1) where the universal quantifiers are]]>  at the front of the type. <fr:link href="https://ocaml.org/manual/5.2/polymorphism.html#s:higher-rank-poly" type="external">OCaml does support quantifiers inside certain types like records</fr:link>.</html:p>
                    <html:p>What this means for the transpiler is that we can <html:strong>reuse OCaml's type inference</html:strong> to safely instantiate the correct type annotations and type applications in Hazel! To do this, <html:code>hazel_of_ocaml</html:code> uses <fr:link href="https://ocaml.github.io/merlin/" type="external">Merlin</fr:link> to inspect the type of the function in either a value binding or at the point of a function application.</html:p>
                    <html:p>Take a simple, polymorphic <html:code>length</html:code> function.</html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword">rec </html:span><html:span class="ocaml-entity-name-function-binding">length</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">function</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-list"><![CDATA[[]]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">0</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language">_</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">xs</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">+</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">length</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">xs</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">int_len</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">length</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">1</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">2</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">3</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">str_len</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">length</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">only</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">two</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                    <html:p>When we run this through <html:code>hazel_of_ocaml</html:code> with the <html:code>-type</html:code> flag we get.</html:p>
                    <html: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 ?]]></html:pre>
                    <html:p><html:code>hazel_of_ocaml</html:code> has correctly instantiated the type for <html:code>length</html:code> inside the recursive function and then in each case with the integer list and the string list.</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>5</fr:month>
                  <fr:day>2</fr:day>
                </fr:date>
                <fr:title text="A Corpus of Hazel Programs">A Corpus of Hazel Programs</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>The impetus for this work was to derive a corpus of ill-typed Hazel programs. Luckily, such a corpus exists for OCaml! <fr:link href="/ocaml-corpus/" title="A Collection of Novice Interactions with the OCaml Top-Level System" uri="https://patrick.sirref.org/ocaml-corpus/" display-uri="ocaml-corpus" type="local">Seidel et al.</fr:link> created a corpus of OCaml programs from their undergraduate students at UC San Diego. <fr:link href="https://github.com/patricoferris/hazel-corpus" type="external">Some of these programs have been transpiled to Hazel</fr:link>.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>5</fr:month>
                  <fr:day>2</fr:day>
                </fr:date>
                <fr:title text="Future Work">Future Work</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><fr:link href="/hazel/" title="Hazel" uri="https://patrick.sirref.org/hazel/" display-uri="hazel" type="local">Hazel</fr:link> 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 <![CDATA[(e.g. handling the]]> <html:code>cmi</html:code><![CDATA[ files).]]></html:p>
                <html: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?</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>2</fr:month>
              <fr:day>18</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/ppxlib-5-2/</fr:uri>
            <fr:display-uri>ppxlib-5-2</fr:display-uri>
            <fr:route>/ppxlib-5-2/</fr:route>
            <fr:title text="Bumping Ppxlib's AST to 5.2">Bumping Ppxlib's AST to 5.2</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p><fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">Ppxlib</fr:link> is a libary for building OCaml preprocessors. Users can generate OCaml code <html:em>from</html:em><![CDATA[ OCaml code (derivers) or replace parts of OCaml code with other OCaml code (rewriters).]]></html:p>
            <html:p>At the core of <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> is the OCaml parsetree; a data structure in the compiler that represents OCaml source code. <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">Ppxlib</fr:link><![CDATA[ makes a distinction between the source parsetree (based on the version of the OCaml compiler you are using) and]]> <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link><![CDATA['s parsetree (a copy of]]> <html:em>some</html:em><![CDATA[ parsetree from the compiler).]]></html:p>
            <html:p>In <fr:link href="https://discuss.ocaml.org/t/ann-ppxlib-0-36-0" type="external">ppxlib.0.36.0</fr:link>, 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.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>2</fr:month>
                  <fr:day>18</fr:day>
                </fr:date>
                <fr:title text="Manual Migrations in Ppxlib">Manual Migrations in Ppxlib</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>It is possible to perform migrations between parsetrees manually using the <html:code>ppxlib.ast</html:code> package.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword-other">open</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Ppxlib</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">open</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Ast_builder</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Make</html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-keyword-other">struct</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">loc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Location</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">none</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">end</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">pp_expr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Format</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">printf</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-constant-character-printf"><![CDATA[%a]]> </html:span><html:span class="ocaml-constant-character-printf"><![CDATA[%!]]> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pp_ast</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">expression</html:span><html:span class="ocaml-source"> ?</html:span><html:span class="ocaml-source">config</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-constant-language-capital-identifier">None</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">loc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Location</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">none</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">str</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">txt</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">txt</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">loc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">module</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">To_408</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> 
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-constant-language-capital-identifier">Ppxlib_ast</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Convert</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Ppxlib_ast</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Js</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Ppxlib_ast__</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Versions</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">OCaml_408</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html:p>The <html:code>Ppxlib_ast.Js</html:code> module is <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link><![CDATA['s AST (since]]> <html:code>ppxlib.0.36.0</html:code><![CDATA[ OCaml 5.2.0). We can use functions]]>  provided by the <html:code>Convert</html:code> functor to copy parts of the AST from one version to another. Usually there is very little difference between the versioned parsetrees.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">func</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">arg</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">body</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source">pexp_fun</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nolabel</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">None</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">ppat_var</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">str</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">arg</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">body</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">add_expr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">func</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">x</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">func</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">y</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">eapply</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">evar</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">Int.add</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">evar</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">x</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">evar</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">y</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html: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.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pp_expr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">add_expr</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> 
</html:span>
<html:span class="ocaml-constant-language-capital-identifier">Pexp_function</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pparam_loc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">__loc</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pparam_desc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pparam_val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nolabel</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">None</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Ppat_var</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">x</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pparam_loc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">__loc</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pparam_desc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pparam_val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nolabel</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">None</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Ppat_var</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">y</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">None</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pfunction_body</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pexp_apply</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">         </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pexp_ident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Ldot</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Lident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">Int</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">add</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">         </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nolabel</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pexp_ident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Lident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">x</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">           </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nolabel</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pexp_ident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Lident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">y</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">           </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">         </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-operator">-</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">unit</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-unit"><![CDATA[()]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html:p>This is a relatively new feature of the parsetree, if we migrate the expression down to <html:code>4.08</html: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.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">expr_408</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">To_408</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">copy_expression</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">add_expr</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>2</fr:month>
                  <fr:day>18</fr:day>
                </fr:date>
                <fr:title text="Function Arity in the OCaml Parsetree">Function Arity in the OCaml Parsetree</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html: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:</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">add</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">x</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">y</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">x</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">+</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">y</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html:p>A two-argument <html:code>add</html:code> function would be represented in the parsetree as <html:code>fun x -&gt; fun y -&gt; x + y</html:code><![CDATA[. Using the nodes from the parsetree (with some details removed) it would be]]> <html:code><![CDATA[Pexp_fun (x, Pexp_fun (y, Pexp_apply ...))]]></html:code>.</html:p>
                <html:p>Now, since OCaml 5.2, functions can be expressed with their syntactic arity intact. The function <html:code>add</html:code> would look something like <html:code><![CDATA[Pexp_function ([ x; y ], Pfunction_body (Pexp_apply ...))]]></html:code>. Both arguments are stored as a list.</html:p>
                <html:p>The constructor <html:code>Pexp_function</html:code> was not a new addition to the parsetree. It used to represent pattern-matching expressions like <html:code>function A -&gt; 1</html:code>. This can now be expressed as a function body of <html:code>Pfunction_cases</html:code>.</html:p>
                <html:p>Whilst these additions and modifications to the parsetree are arguably a better design, it has caused chaos in terms of <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link>'s reverse dependencies!</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>2</fr:month>
                  <fr:day>18</fr:day>
                </fr:date>
                <fr:title text="Coalescing Function Arguments">Coalescing Function Arguments</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>In <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> <html:code>0.36.0</html:code>, functions from <html:code>Ast_builder</html:code> will help ppx authors produce maximum arity functions. However, functions from <html:code>Ast_helper</html:code> will not do this.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">ast_helper_func</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">arg</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">body</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-constant-language-capital-identifier">Ast_helper</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Exp</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">fun_</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nolabel</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">None</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">ppat_var</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">str</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">arg</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">body</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">ast_helper_expr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">ast_helper_func</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">x</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">ast_helper_func</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">y</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">eapply</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">evar</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">Int.equal</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">evar</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">x</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">evar</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">y</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html:p>Here we recreate our helper function to create function expressions using <html:code>Ast_helper.Exp.fun_</html:code> instead. We can now show the difference between the <html:code>expr</html:code> expression and the <html:code>ast_helper_expr</html:code> expression.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pp_expr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">add_expr</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-constant-language-capital-identifier">Pexp_function</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pparam_loc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">__loc</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pparam_desc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pparam_val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nolabel</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">None</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Ppat_var</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">x</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pparam_loc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">__loc</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pparam_desc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pparam_val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nolabel</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">None</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Ppat_var</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">y</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">None</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pfunction_body</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pexp_apply</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">         </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pexp_ident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Ldot</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Lident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">Int</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">add</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">         </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nolabel</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pexp_ident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Lident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">x</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">           </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nolabel</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pexp_ident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Lident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">y</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">           </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">         </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-operator">-</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">unit</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-unit"><![CDATA[()]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html:p>Above, we see a function expression with arity <html:em>two</html:em>. Below, we see nested function expressions each with arity <html:em>one</html:em>.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pp_expr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">ast_helper_expr</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-constant-language-capital-identifier">Pexp_function</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pparam_loc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">__loc</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pparam_desc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pparam_val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nolabel</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">None</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Ppat_var</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">x</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">None</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pfunction_body</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pexp_function</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">         </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pparam_loc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">__loc</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">             </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pparam_desc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pparam_val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nolabel</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">None</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Ppat_var</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">y</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">             </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">           </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">         </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">None</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">         </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pfunction_body</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">             </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pexp_apply</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">                </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pexp_ident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Ldot</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Lident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">Int</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">equal</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">                </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nolabel</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pexp_ident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Lident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">x</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">                  </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nolabel</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pexp_ident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Lident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">y</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">                  </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">                </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">         </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-operator">-</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">unit</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-unit"><![CDATA[()]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>2</fr:month>
                  <fr:day>18</fr:day>
                </fr:date>
                <fr:title text="Ramifications for Ppxlib Users">Ramifications for Ppxlib Users</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Many, many, <html:em>many</html:em> ppxes broke after migrating the <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> AST to 5.2. Mostly, this is due to pattern-matching. Downstream users of <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> frequently pattern-match directly against the parsetree. However, nodes such as <html:code>Pexp_fun</html:code> no longer exist and <html:code>Pexp_function</html:code> has completely different constructor arguments!</html:p>
                <html:p><![CDATA[Patching all the ppxes has been quite difficult. Most ppxes only deal with single arguments at a time (e.g.]]> <html:code>Pexp_fun x</html:code><![CDATA[) but now they must handle zero or more arguments at a time. (In the zero case, this will always correspond to a pattern-matching]]> <html:code>function</html:code><![CDATA[).]]></html:p>
                <html: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 <html:code>ppxlib.0.36.0</html:code>:</html:p>
                <html:ul>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/patricoferris/ppx_deriving_yaml/pull/58" type="external">https://github.com/patricoferris/ppx_deriving_yaml/pull/58</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/mirage/ocaml-rpc/pull/181" type="external">https://github.com/mirage/ocaml-rpc/pull/181</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://gitlab.com/o-labs/ppx_deriving_jsoo/-/merge_requests/1" type="external">https://gitlab.com/o-labs/ppx_deriving_jsoo/-/merge_requests/1</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/ocaml-community/sedlex/pull/160" type="external">https://github.com/ocaml-community/sedlex/pull/160</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/ocaml-sys/config.ml/pull/22" type="external">https://github.com/ocaml-sys/config.ml/pull/22</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/vogler/ppx_distr_guards/pull/2" type="external">https://github.com/vogler/ppx_distr_guards/pull/2</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/ocaml-gospel/gospel/pull/424" type="external">https://github.com/ocaml-gospel/gospel/pull/424</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/teamwalnut/graphql-ppx/pull/299" type="external">https://github.com/teamwalnut/graphql-ppx/pull/299</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/ocsigen/lwt/pull/1033" type="external">https://github.com/ocsigen/lwt/pull/1033</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://gitlab.com/gopiandcode/ppx-inline-alcotest/-/merge_requests/3" type="external">https://gitlab.com/gopiandcode/ppx-inline-alcotest/-/merge_requests/3</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/dariusf/ppx_interact/pull/3" type="external">https://github.com/dariusf/ppx_interact/pull/3</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/ocaml-ppx/ppx_deriving_yojson/pull/160" type="external">https://github.com/ocaml-ppx/ppx_deriving_yojson/pull/160</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/lpcic/elpi/pull/276" type="external">https://github.com/LPCIC/elpi/pull/276</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/mirage/repr/pull/110" type="external">https://github.com/mirage/repr/pull/110</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/programingisthefuture/ppx_default/pull/3" type="external">https://github.com/ProgramingIsTheFuture/ppx_default/pull/3</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/codinuum/vlt/pull/3" type="external">https://github.com/codinuum/vlt/pull/3</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/sim642/ppx_deriving_hash/pull/6" type="external">https://github.com/sim642/ppx_deriving_hash/pull/6</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/ocsigen/tyxml/pull/340" type="external">https://github.com/ocsigen/tyxml/pull/340</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/sim642/ppx_viewpattern/pull/2" type="external">https://github.com/sim642/ppx_viewpattern/pull/2</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/little-arhat/ppx_jsobject_conv/pull/11" type="external">https://github.com/little-arhat/ppx_jsobject_conv/pull/11</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/robur-coop/lun/pull/1" type="external">https://github.com/robur-coop/lun/pull/1</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://gitlab.com/o-labs/ppx_deriving_encoding/-/merge_requests/4" type="external">https://gitlab.com/o-labs/ppx_deriving_encoding/-/merge_requests/4</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/francoisthire/bam/pull/12" type="external">https://github.com/francoisthire/bam/pull/12</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/xguerin/bitstring/pull/36" type="external">https://github.com/xguerin/bitstring/pull/36</fr:link>
                    </html:p>
                  </html:li>
                </html:ul>
                <html:p><![CDATA[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]]> <fr:link href="https://www.cambridge.org/core/journals/journal-of-functional-programming/article/pattern-matching-with-abstract-data-types1/04DD26A0E6CA3A1E87E0E6AE8BC02EED" type="external">tension is not new</fr:link>.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>2</fr:month>
                  <fr:day>18</fr:day>
                </fr:date>
                <fr:title text="The Future of Ppxlib">The Future of Ppxlib</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">Ppxlib</fr:link> 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 <fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/558" type="external">the 5.3 bump</fr:link>!</html:p>
                <html:p>There have been many discussions about simplifying this process, but so far the time and effort to build a <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link><![CDATA[ that will result in fewer breakages is too high (see]]> <fr:link href="https://github.com/ocaml-ppx/ppx" type="external">an attempt using views</fr:link><![CDATA[).]]></html:p>
                <html:p>Thank you to Tarides and Jane Street for funding my time to work on this release and all the chaos it has caused.</html:p>
                <html:p>Happy preprocessing!</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>2</fr:month>
              <fr:day>28</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/vpnkit-upgrade/</fr:uri>
            <fr:display-uri>vpnkit-upgrade</fr:display-uri>
            <fr:route>/vpnkit-upgrade/</fr:route>
            <fr:title text="Defunctorising VPNKit">Defunctorising VPNKit</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p><fr:link href="/vpnkit/" title="VPNKit" uri="https://patrick.sirref.org/vpnkit/" display-uri="vpnkit" type="local">VPNKit</fr:link> 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.</html:p>
            <html:p>This short post discusses some of the recent changes to MirageOS and how they impact <fr:link href="/vpnkit/" title="VPNKit" uri="https://patrick.sirref.org/vpnkit/" display-uri="vpnkit" type="local">VPNKit</fr:link>.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:uri>https://patrick.sirref.org/dune-virt-libs/</fr:uri>
                <fr:display-uri>dune-virt-libs</fr:display-uri>
                <fr:route>/dune-virt-libs/</fr:route>
                <fr:title text="Dune Virtual Libraries">Dune Virtual Libraries</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Dune, for quite some time, has supported <html:em>virtual libraries</html:em><![CDATA[. This allows library authors to define a signature without an implementation (similar to OCaml's]]> <html:code>module type S = struct ... end</html:code><![CDATA[). 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.]]></html:p>
                <html:p>This feature has been quite widely used in OCaml. For example, the <fr:link href="https://github.com/mirage/digestif" type="external">excellent <html:code>digestif</html:code> library</fr:link> of hashing algorithms provides both C and OCaml implementations individually packaged into <html:code>digestif.c</html:code> and <html:code>digestif.ocaml</html:code><![CDATA[ respectively. Consider developing a browser application that needs some hashing algorithm (e.g.]]> <fr:link href="https://github.com/patricoferris/omditor" type="external">Irmin in the browser</fr:link><![CDATA[). We can explicitly use the OCaml backend for digestif which]]> <fr:link href="https://github.com/ocsigen/js_of_ocaml" type="external">js_of_ocaml</fr:link> will happily compile for us.</html:p>
                <html:p>There are two distinct limitations to this approach.</html:p>
                <html:ol>
                  <html:li>
                    <html:p>Applications can only link <html:em>exactly one</html:em> implementation.</html:p>
                  </html:li>
                  <html:li>
                    <html:p><![CDATA[Implementations cannot expose additional functionality easily (see]]> <fr:link href="https://github.com/ocaml/dune/issues/5997" type="external">dune#5597</fr:link><![CDATA[).]]></html:p>
                  </html:li>
                </html:ol>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>2</fr:month>
                  <fr:day>28</fr:day>
                </fr:date>
                <fr:title text="Functors in MirageOS">Functors in MirageOS</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><fr:link href="https://mirage.io/" type="external">MirageOS</fr:link><![CDATA[ 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.]]> <html:code>unix</html:code>, <html:code>hvt</html:code><![CDATA[ etc.)]]></html:p>
                <html:p>Recently, <fr:link href="https://github.com/mirage/mirage-skeleton/pull/407/" type="external">there has been a push</fr:link> to use <fr:link href="/dune-virt-libs/" title="Dune Virtual Libraries" uri="https://patrick.sirref.org/dune-virt-libs/" display-uri="dune-virt-libs" type="local">dune virtual libraries</fr:link> instead.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>2</fr:month>
                  <fr:day>28</fr:day>
                </fr:date>
                <fr:title text="VPNKit's Fake Clock &amp; Time">VPNKit's Fake Clock &amp; Time</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><![CDATA[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]]> <html:code><![CDATA[(wrapped false)]]></html:code><![CDATA[). This allows implementers to expose additional modules alongside the implementation of the virtual library.]]></html:p>
                <html: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.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword">module</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">R</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-constant-language-capital-identifier">Dns_forward</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Resolver</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Make</html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Proto_client</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Fake</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Time</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Fake</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Clock</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html:p>In this new world of <fr:link href="/dune-virt-libs/" title="Dune Virtual Libraries" uri="https://patrick.sirref.org/dune-virt-libs/" display-uri="dune-virt-libs" type="local">dune virtual libraries</fr:link>, our <html:code>Resolver</html:code> is significantly more simple.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword">module</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">R</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Dns_forward</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Resolver</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Make</html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Proto_client</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html:p><![CDATA[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.]]></html:p>
                <html:p>The first thing I had to do was make the <html:code>mirage-mtime</html:code> and <html:code>mirage-sleep</html:code> virtual libraries unwrapped. This allowed me to make a new private dune library called <html:code>fake_time</html:code> with <html:em>two</html:em> public modules: the normal interface required by <html:code>mirage-mtime</html:code> and another module called <html:code>Fake_time_state</html:code> containing:</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">timeofday</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">ref</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">0L</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">c</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Lwt_condition</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">create</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-unit"><![CDATA[()]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">advance</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">nsecs</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source">timeofday</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Int64</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">add</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">!</html:span><html:span class="ocaml-source">timeofday</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">nsecs</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-constant-language-capital-identifier">Lwt_condition</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">broadcast</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">c</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-unit"><![CDATA[()]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">reset</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-unit"><![CDATA[()]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source">timeofday</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">0L</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-constant-language-capital-identifier">Lwt_condition</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">broadcast</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">c</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-unit"><![CDATA[()]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html:p>I did the same for <html:code>fake_sleep</html:code> which depended on the state from the <html:code>fake_time</html:code><![CDATA[ library (something a normal library wouldn't).]]></html:p>
                <html:p><![CDATA[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. <![CDATA[You can only link one implementation at a time to an executable (or test).]]>  Thus, the dune rules for running the <html:code>dns_forward</html:code> test suite became:</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="dune-comment-line">; Uses the default  implementations provided by virtual libraries</html:span><html:span class="dune-source">
</html:span>
<html:span class="dune-meta-stanza"><![CDATA[(]]> </html:span><html:span class="dune-meta-class-stanza">executable</html:span><html:span class="dune-meta-stanza">
</html:span>
<html:span class="dune-meta-stanza"> </html:span><html:span class="dune-meta-stanza-library-field"><![CDATA[(]]> </html:span><html:span class="dune-keyword-other">name</html:span><html:span class="dune-meta-stanza-library-field"> </html:span><html:span class="dune-meta-atom">test</html:span><html:span class="dune-meta-stanza-library-field"><![CDATA[)]]> </html:span><html:span class="dune-meta-stanza">
</html:span>
<html:span class="dune-meta-stanza"> </html:span><html:span class="dune-meta-stanza-lib-or-exec-buildable"><![CDATA[(]]> </html:span><html:span class="dune-keyword-other">libraries</html:span><html:span class="dune-meta-stanza-lib-or-exec-buildable"> </html:span><html:span class="dune-meta-atom">dns_forward</html:span><html:span class="dune-meta-stanza-lib-or-exec-buildable"> </html:span><html:span class="dune-meta-atom">alcotest</html:span><html:span class="dune-meta-stanza-lib-or-exec-buildable"><![CDATA[)]]> </html:span><html:span class="dune-meta-stanza"><![CDATA[)]]> </html:span><html:span class="dune-source">
</html:span>
<html:span class="dune-source">
</html:span>
<html:span class="dune-comment-line">; Override the defaults and select the private fake libraries</html:span><html:span class="dune-source">
</html:span>
<html:span class="dune-meta-stanza"><![CDATA[(]]> </html:span><html:span class="dune-meta-class-stanza">executable</html:span><html:span class="dune-meta-stanza">
</html:span>
<html:span class="dune-meta-stanza">  </html:span><html:span class="dune-meta-stanza-library-field"><![CDATA[(]]> </html:span><html:span class="dune-keyword-other">name</html:span><html:span class="dune-meta-stanza-library-field"> </html:span><html:span class="dune-meta-atom">test_fake</html:span><html:span class="dune-meta-stanza-library-field"><![CDATA[)]]> </html:span><html:span class="dune-meta-stanza">
</html:span>
<html:span class="dune-meta-stanza">  </html:span><html:span class="dune-meta-stanza-lib-or-exec-buildable"><![CDATA[(]]> </html:span><html:span class="dune-keyword-other">libraries</html:span><html:span class="dune-meta-stanza-lib-or-exec-buildable"> </html:span><html:span class="dune-meta-atom">dns_forward</html:span><html:span class="dune-meta-stanza-lib-or-exec-buildable"> </html:span><html:span class="dune-meta-atom">alcotest</html:span><html:span class="dune-meta-stanza-lib-or-exec-buildable"> </html:span><html:span class="dune-meta-atom">fake_sleep</html:span><html:span class="dune-meta-stanza-lib-or-exec-buildable"> </html:span><html:span class="dune-meta-atom">fake_time</html:span><html:span class="dune-meta-stanza-lib-or-exec-buildable"><![CDATA[)]]> </html:span><html:span class="dune-meta-stanza"><![CDATA[)]]> </html:span><html:span class="dune-source">
</html:span>
</html:code>
                </html:pre>
                <html:p>With all of this machinery in place, I could now update <html:code>test_fake</html:code> to use the new modules that would provide the custom functionality for the clock and time implementations.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-comment-block"><![CDATA[(*]]> </html:span><html:span class="ocaml-comment-block"> The bad server should be marked offline and no-one will wait for it </html:span><html:span class="ocaml-comment-block"><![CDATA[*)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-constant-language-capital-identifier">Fake_time_state</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">reset</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-unit"><![CDATA[()]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-comment-block"><![CDATA[(*]]> </html:span><html:span class="ocaml-comment-block"> avoid the timeouts winning the race with the actual result </html:span><html:span class="ocaml-comment-block"><![CDATA[*)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-constant-language-capital-identifier">Fake_time_state</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">advance</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Duration</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">of_ms</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">500</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> 
</html:span>
</html:code>
                </html:pre>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>2</fr:month>
                  <fr:day>28</fr:day>
                </fr:date>
                <fr:title text="Conclusion">Conclusion</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>The switch to <fr:link href="/dune-virt-libs/" title="Dune Virtual Libraries" uri="https://patrick.sirref.org/dune-virt-libs/" display-uri="dune-virt-libs" type="local">dune virtual libraries</fr:link> 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.</html:p>
                <html:p>The <fr:link href="https://github.com/moby/vpnkit/pull/646" type="external">pull request to upgrade VPNKit is open</fr:link>.</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2023</fr:year>
              <fr:month>8</fr:month>
              <fr:day>9</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/ocaml-rtree/</fr:uri>
            <fr:display-uri>ocaml-rtree</fr:display-uri>
            <fr:route>/ocaml-rtree/</fr:route>
            <fr:title text="Reviving OCaml R-Tree">Reviving OCaml R-Tree</fr:title>
            <fr:meta name="description">Fast-forwarding a decade-old OCaml implementation of the R-Tree geospatial data-structure.
</fr:meta>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>Antonin Guttman <fr:link href="http://www-db.deis.unibo.it/courses/SI-LS/papers/Gut84.pdf" type="external">first proposed R-Trees in 1984</fr:link>.</html:p>
            <html:blockquote>
              <html: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...</html:p>
            </html:blockquote>
            <html:p><![CDATA[There are lots of excellent resources for understanding more about R-Trees and all of the wonderful variations there of (e.g.]]> <fr:link href="http://www.cs.ucr.edu/~ravi/CS236Papers/rstar.pdf" type="external">R*-trees</fr:link><![CDATA[). This]]> <fr:link href="https://www.bartoszsypytkowski.com/r-tree/" type="external">blog post</fr:link> seems to be the most popular introduction.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:uri>https://patrick.sirref.org/ocaml-rtree-001/</fr:uri>
                <fr:display-uri>ocaml-rtree-001</fr:display-uri>
                <fr:route>/ocaml-rtree-001/</fr:route>
                <fr:title text="An OCaml Rtree Implementation">An OCaml Rtree Implementation</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>In the <fr:link href="https://www.cst.cam.ac.uk/research/eeg" type="external">Energy and Environment Group</fr:link> 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 <fr:link href="https://github.com/mariusae/ocaml-rtree" type="external">an implementation in pure OCaml</fr:link>. After reaching out to the author, they were more than happy for their work to be maintained in the <fr:link href="https://github.com/geocaml" type="external">Geocaml organisation</fr:link>, updated to the latest OCaml tools and <fr:link href="https://github.com/ocaml/opam-repository/pull/24227" type="external">hopefully released on opam</fr:link>.</html:p>
                <html:p>The <fr:link href="https://github.com/geocaml/ocaml-rtree/commit/073d79ad34de15f0671f2faafb24b1edc5c2d8c7" type="external">dunification</fr:link><![CDATA[ went smoothly whilst fast-forwarding 15 OCaml compiler versions with no changes or problems (just dune unused variable warnings).]]></html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:uri>https://patrick.sirref.org/ocaml-rtree-002/</fr:uri>
                <fr:display-uri>ocaml-rtree-002</fr:display-uri>
                <fr:route>/ocaml-rtree-002/</fr:route>
                <fr:title text="OCaml Rtree Examples">OCaml Rtree Examples</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><![CDATA[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]]> <html:code>Rectangle</html:code> envelope.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword-other">module</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Line</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">struct</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p0</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">float</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">*</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">float</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">float</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">*</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">float</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword">open</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Repr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">in</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source">record</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">line</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-keyword-other">fun</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p0</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p0</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword-operator">|+</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">field</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">p0</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">pair</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">float</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">float</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-keyword-other">fun</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">p0</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword-operator">|+</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">field</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">p1</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">pair</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">float</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">float</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-keyword-other">fun</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">p1</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword-operator">|&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">sealr</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">envelope</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Rtree</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Rectangle</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">envelope</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p0</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">x1</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">y1</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">x2</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">y2</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">x0</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Float</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">min</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">x1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">x2</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">in</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">x1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Float</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">max</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">x1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">x2</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">in</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">y0</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Float</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">min</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">y1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">y2</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">in</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">y1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Float</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">max</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">y1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">y2</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">in</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-constant-language-capital-identifier">Rtree</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Rectangle</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">v</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">x0</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">y0</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">x1</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">y1</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">end</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html:p>In addition to the <html:code>envelope</html:code> function, we also need to provide a runtime representation using <html:code>Repr</html:code>. In the example, we've constructed it by hand but I recommend using <fr:link href="https://ocaml.org/p/ppx_repr/latest" type="external">ppx_repr</fr:link> to derive it for you. From here we can create our index.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword-other">module</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">R</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Rtree</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Make</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Rtree</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Rectangle</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Line</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:uri>https://patrick.sirref.org/ocaml-rtree-003/</fr:uri>
                    <fr:display-uri>ocaml-rtree-003</fr:display-uri>
                    <fr:route>/ocaml-rtree-003/</fr:route>
                    <fr:title text="Inserting Values">Inserting Values</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html: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.</html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">r</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">i</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">R</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">empty</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">4</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">in</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-constant-language-capital-identifier">R</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">insert</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">i</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Line</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p0</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">1.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">1.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">2.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">2.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">r</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">R</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">&lt;</html:span><html:span class="ocaml-source">abstr</html:span><html:span class="ocaml-keyword-operator">&gt;</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                    <html:p>As you might expect, bulk loading takes a list of values instead.</html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">r</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">lines</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">        </html:span><html:span class="ocaml-constant-language-capital-identifier">Line</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">        </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p0</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">0.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">0.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">1.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">1.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">        </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p0</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">1.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">1.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">2.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">2.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">        </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p0</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">2.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">2.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">3.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">3.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">        </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p0</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">3.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">3.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">4.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">4.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">        </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword-other">in</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-constant-language-capital-identifier">R</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">load</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">max_node_load</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-constant-numeric-decimal-integer">4</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">lines</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">r</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">R</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">&lt;</html:span><html:span class="ocaml-source">abstr</html:span><html:span class="ocaml-keyword-operator">&gt;</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:uri>https://patrick.sirref.org/ocaml-rtree-004/</fr:uri>
                    <fr:display-uri>ocaml-rtree-004</fr:display-uri>
                    <fr:route>/ocaml-rtree-004/</fr:route>
                    <fr:title text="Spatial Queries">Spatial Queries</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>The lines we loaded into the last index are really just four segments of the line <html:code>y = x</html:code>. Let's spatially query for the first two segments.</html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">R</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">find</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">r</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Rtree</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Rectangle</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">v</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">x0</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-constant-numeric-decimal-float">0.</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">y0</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-constant-numeric-decimal-float">0.</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">x1</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-constant-numeric-decimal-float">2.</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">y1</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-constant-numeric-decimal-float">2.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-operator">-</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Line</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">list</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Line</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">p0</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">0.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">0.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">1.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">1.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Line</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">p0</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">1.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">1.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">2.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">2.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Line</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">p0</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">2.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">2.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">3.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">3.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                    <html:p>You can see the query actually returned the first three, that's because all bound checks are inclusive.</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <html:p>The <fr:link href="https://github.com/geocaml/ocaml-rtree/blob/d0a789b8eb6c594ed8c0f9c9a6c4b5cd7c734a03/test/image.ml#L95-L106" type="external">source repository includes a fairly simple example of rendering an R-Tree</fr:link> using <fr:link href="https://github.com/dbuenzli/vg" type="external">Vg</fr:link>. This can be done outside of the repository using the <html:code>tree</html:code> representation.</html:p>
            <html:pre class="hilite">
              <html:code><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source">show</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">R</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">tree</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">tree</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">R</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">R</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">tree</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">nonrec</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">tree</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-constant-language-capital-identifier">R</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">tree</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-constant-language-capital-identifier">Node</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">of</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Line</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">envelope</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">*</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">R</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">tree</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">list</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Leaf</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">of</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Line</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">envelope</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">*</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Line</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">list</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Empty</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
            </html:pre>
            <html:p>Here is an example rendering from the repository showing some random lines and the envelopes of the R-tree.</html:p>
            <html:p style="text-align:center">
    <html:img src="./rtree.svg" />
</html:p>
          </fr:mainmatter>
        </fr:tree>
      </fr:mainmatter>
    </fr:tree>
    <fr:tree show-metadata="false" expanded="false" toc="false">
      <fr:frontmatter>
        <fr:authors>
          <fr:author>
            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
          </fr:author>
        </fr:authors>
        <fr:uri>https://patrick.sirref.org/ocaml-blog/</fr:uri>
        <fr:display-uri>ocaml-blog</fr:display-uri>
        <fr:route>/ocaml-blog/</fr:route>
        <fr:title text="Patrick's OCaml Blog">Patrick's OCaml Blog</fr:title>
      </fr:frontmatter>
      <fr:mainmatter>
        <html:p>Welcome to the OCaml corner of my website. Here you will find long-form posts and shorter, more sporadic updates about my work in the OCaml community. This might include things about:</html:p>
        <html:ul>
          <html:li>
            <html:p><fr:link href="/outreachy/" title="Outreachy" uri="https://patrick.sirref.org/outreachy/" display-uri="outreachy" type="local">Outreachy</fr:link> where I am the current <fr:link href="https://ocaml.org/outreachy" type="external">OCaml community co-ordinator</fr:link>.</html:p>
          </html:li>
          <html:li>
            <html:p><fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">Ppxlib</fr:link> where I help <fr:link href="/nathanreb/" title="Nathan Rebours" uri="https://patrick.sirref.org/nathanreb/" display-uri="nathanreb" type="local">Nathan</fr:link> maintain the core library to build OCaml preprocessors.</html:p>
          </html:li>
          <html:li>
            <html:p><fr:link href="https://ocaml.org/packages/search?q=author:&quot;ferris&quot;" type="external">Any of the open-source tools I help maintain</fr:link>.</html:p>
          </html:li>
        </html:ul>
        <html:p><fr:link href="/ocaml-blog/atom.xml" type="external">An RSS feed is available</fr:link>.</html:p>
        <html:div>
          <html:h1>Posts</html:h1>
        </html:div>
        <html:p><![CDATA[These posts are longer form and consolidate weeklies (see below).]]></html:p>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>8</fr:month>
              <fr:day>7</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/irmin-retro/</fr:uri>
            <fr:display-uri>irmin-retro</fr:display-uri>
            <fr:route>/irmin-retro/</fr:route>
            <fr:title text="Irmin Retrospective">Irmin Retrospective</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p><fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> is an OCaml library for building <html:em>branchable</html:em> and <html:em>mergeable</html:em> data stores. The data is <html:em>mergeable</html:em> in the sense of <fr:link href="/kcrsk-mrdts-2022/" title="Certified mergeable replicated data types" uri="https://patrick.sirref.org/kcrsk-mrdts-2022/" display-uri="kcrsk-mrdts-2022" type="local">mergeable replicated data types</fr:link>.</html:p>
            <html:p>I have been using Irmin for over five years to build different kinds of interesting data stores including:</html:p>
            <html:ul>
              <html:li>
                <html:p>A <fr:link href="https://github.com/patricoferris/omditor" type="external">simple markdown-based note-taking web application</fr:link>.</html:p>
              </html:li>
              <html:li>
                <html:p>A <fr:link href="https://github.com/carboncredits/retirement-db" type="external">content-addressed database</fr:link>.</html:p>
              </html:li>
              <html:li>
                <html:p>Mentoring an intern who <fr:link href="https://tarides.com/blog/2022-08-02-irmin-in-the-browser/" type="external">worked on Irmin in the browser</fr:link>.</html:p>
              </html:li>
              <html:li>
                <html:p>Most recently, an <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Irmin-backed shell session manager</fr:link>.</html:p>
              </html:li>
            </html:ul>
            <html:p>I was asked to provide some feedback recently on <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link>, so I thought writing a little retrospective here would be a good way to do that. The remit for the retrospective was about improving <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link>, so the content is focussed on pain points and areas of improvement.</html:p>
            <html:pre class="hilite">
              <html:code><html:span class="ocaml-comment-block"><![CDATA[(*]]> </html:span><html:span class="ocaml-comment-block"> An in-memory Irmin store </html:span><html:span class="ocaml-comment-block"><![CDATA[*)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">module</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Store</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Irmin_mem</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">KV</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Make</html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Irmin</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Contents</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">String</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
            </html:pre>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>8</fr:month>
                  <fr:day>7</fr:day>
                </fr:date>
                <fr:title text="What is Irmin?">What is Irmin?</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link>, at its simplest, is a key-value database. Users associate keys with values and can query and update these bindings.</html:p>
                <html: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.</html:p>
                <html:p>Different versions of the database can be combined by <html:em>merging</html:em>. When you set up your instance of an <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> database, you also provide it with a <fr:link href="/kcrsk-mrdts-2022/" title="Certified mergeable replicated data types" uri="https://patrick.sirref.org/kcrsk-mrdts-2022/" display-uri="kcrsk-mrdts-2022" type="local">merge function</fr:link>.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source">show_type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Irmin</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Merge</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">f</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">nonrec</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-storage-type">'a</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">f</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source">old</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-storage-type">'a</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Irmin</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Merge</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">promise</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-storage-type">'a</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-storage-type">'a</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-storage-type">'a</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Irmin</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Merge</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">conflict</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">result</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Lwt</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>8</fr:month>
                  <fr:day>7</fr:day>
                </fr:date>
                <fr:title text="Design and API">Design and API</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link>'s API is very git-inspired. There is a large overlap of shared vocabulary and concepts: <html:em>repositories</html:em>, <html:em>branches</html:em>, <html:em>commits</html:em>, <html:em>heads</html:em> etc.</html:p>
                <html:p>Probably the most confusing aspect of this is the notion of a <html:code>Store</html:code>. When I was describing <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> above, I used the term <html:em>database</html:em> to help distinguish between some of these concepts. In Irmin's documentation, it is used for multiple <![CDATA[related (but different) concepts. In "]]> <fr:link href="https://irmin.org/tutorial/getting-started/#creating-a-store" type="external">Creating a Store</fr:link>" stores refer to the entire database, whereas in the <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> API docs we have that:</html:p>
                <html:blockquote>
                  <html:p>There are two kinds of store in Irmin: the ones based on persistent named branches and the ones based temporary detached heads.</html:p>
                </html:blockquote>
                <html:p>For <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> library users, a <html:code>Store.t</html: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.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Store</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">of_branch</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-operator">-</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Store</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">repo</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">string</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Store</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Lwt</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">&lt;</html:span><html:span class="ocaml-keyword-other">fun</html:span><html:span class="ocaml-keyword-operator">&gt;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Store</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">of_commit</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-operator">-</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Store</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">commit</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Store</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Lwt</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">&lt;</html:span><html:span class="ocaml-keyword-other">fun</html:span><html:span class="ocaml-keyword-operator">&gt;</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html: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.</html:p>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>8</fr:month>
                      <fr:day>7</fr:day>
                    </fr:date>
                    <fr:title text="Module and Functor Soup">Module and Functor Soup</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Undoubtedly for a majority of use-cases and users, <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> 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 <fr:link href="https://mirage.github.io/irmin/irmin/Irmin/module-type-S/Schema/index.html" type="external"><html:code>Schema</html:code> module</fr:link> when describing the types they want to instantiate their store with.</html:p>
                    <html:p>To counteract this, Irmin has plenty of <html:code>KV</html:code> modules that provide a <html:code>Make</html:code> functor that only requires a user to provide a suitable <html:em>content</html:em> module <![CDATA[for their store (i.e. something that provides a type, a runtime representation]]>  <![CDATA[of that type and a merge function).]]></html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source">show_module</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Irmin_mem</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">KV</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">module</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">KV</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">sig</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">endpoint</html:span><html:span class="ocaml-source"> = unit
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">metadata</html:span><html:span class="ocaml-source"> = unit
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">hash</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">info</html:span><html:span class="ocaml-source"> = Store.info
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[('h, _)]]> </html:span><html:span class="ocaml-entity-name-function-binding">contents_key</html:span><html:span class="ocaml-source"> = 'h
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">'h </html:span><html:span class="ocaml-entity-name-function-binding">node_key</html:span><html:span class="ocaml-source"> = 'h
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">'h </html:span><html:span class="ocaml-entity-name-function-binding">commit_key</html:span><html:span class="ocaml-source"> = 'h
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword-other-ocaml">module</html:span><html:span class="ocaml-source"><![CDATA[ Make : (C : Irmin__.Contents.S) ->]]> </html:span><html:span class="ocaml-keyword-other-ocaml">sig</html:span><html:span class="ocaml-source"> ... </html:span><html:span class="ocaml-keyword-other">end</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">end</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                    <html: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 <html:code>irmin.3.11.0</html:code>, starting at <fr:link href="https://ocaml.org/p/irmin/latest/doc/index.html" type="external">the toplevel documentation page</fr:link> our path to finding this paricular module and functor is as follows:</html:p>
                    <html:ol>
                      <html:li>
                        <html:p>We jump into <fr:link href="https://ocaml.org/p/irmin/latest/doc/irmin.mem/Irmin_mem/index.html" type="external"><html:code>Irmin_mem</html:code></fr:link> from the nicely written landing page.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>We scroll down to find <fr:link href="https://ocaml.org/p/irmin/latest/doc/irmin.mem/Irmin_mem/index.html#module-KV" type="external">the KV module</fr:link>.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>We now make sense of the module's signature by following the <fr:link href="https://ocaml.org/p/irmin/latest/doc/irmin/Irmin/module-type-KV_maker/index.html" type="external">KV_maker link</fr:link>.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>We see a <html:code><![CDATA[Make (C : Contents.S) : sig ... end]]></html:code> at the end of the module, and <fr:link href="https://ocaml.org/p/irmin/latest/doc/irmin/Irmin/module-type-KV_maker/Make/index.html#module-Schema" type="external">we navigate through that</fr:link>.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>Finally we have come to our journey's end, and find the <fr:link href="https://ocaml.org/p/irmin/latest/doc/irmin/Irmin/module-type-KV_maker/Make/index.html#module-Schema" type="external">schema module</fr:link> with type constraints like <html:code>type Branch.t = string</html:code>.</html:p>
                      </html:li>
                    </html:ol>
                    <html:p>There is a big assumption there that you know what the <html:code>Schema</html:code> module is telling you and how it relates to your "store".</html:p>
                    <html: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 <fr:link href="https://github.com/patricoferris/ocaml-cid/blob/main/test/irmin_cid.ml" type="external"><![CDATA[Irmin stores that use CIDs (self-describing content identifiers)]]> </fr:link> for example.</html:p>
                    <html: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 <fr:link href="https://ocaml.org/p/irmin-containers/latest/doc/irmin-containers/Irmin_containers/index.html" type="external">introductory libraries like irmin-containers</fr:link> would be helpful. Perhaps a <html:em>standalone</html:em> library that acts as an interface to Irmin stores would be helpful. I find myself time and again implementing <fr:link href="https://github.com/fn06/shelter/blob/main/src/lib/store.ml" type="external">something like that</fr:link>.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>8</fr:month>
                      <fr:day>7</fr:day>
                    </fr:date>
                    <fr:title text="Backends Galore">Backends Galore</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Irmin has plenty of backends including <fr:link href="https://ocaml.org/p/irmin-git/latest" type="external">a git-compatible one</fr:link>, <fr:link href="https://ocaml.org/p/irmin-mirage/latest" type="external">a MirageOS backend</fr:link>, <fr:link href="https://ocaml.org/p/irmin-indexeddb/latest" type="external">an in-browser IndexedDB backend</fr:link> and even a <fr:link href="https://github.com/andreas/irmin-fdb" type="external">FoundationDB backend</fr:link>.</html:p>
                    <html:p><fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> 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, <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> 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 <fr:link href="https://lofi.so/" type="external">local-first applications</fr:link>.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>8</fr:month>
                      <fr:day>7</fr:day>
                    </fr:date>
                    <fr:title text="Syncing Remote Stores">Syncing Remote Stores</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>The <fr:link href="https://ocaml.org/p/irmin/3.11.0/doc/irmin/Irmin/Sync/index.html" type="external">synchronisation mechanisms in Irmin</fr:link> 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 <fr:link href="https://ocaml.org/p/irmin-git/latest/doc/irmin-git.unix/Irmin_git_unix/Maker/Make/index.html#val-remote" type="external">remote endpoint</fr:link>. Once they have found this function, using it is not easy as it requires them to learn about the <fr:link href="https://ocaml.org/p/mimic/latest" type="external"><html:code>Mimic.ctx</html:code></fr:link>, which is an abstraction of the networking stack!</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>8</fr:month>
                      <fr:day>7</fr:day>
                    </fr:date>
                    <fr:title text="Do Fewer Things and Do Them Well">Do Fewer Things and Do Them Well</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html: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.</html:p>
                    <html:p>When building the <fr:link href="https://github.com/carboncredits/retirement-db" type="external">content-addressed database</fr:link> I needed strong guarantees about some atomic actions to perform on the underlying store. For example, <fr:link href="https://github.com/mirage/irmin/issues/2073" type="external">setting the value and accessing the commit associated with it</fr:link> 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.</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>8</fr:month>
                  <fr:day>7</fr:day>
                </fr:date>
                <fr:title text="Documentation">Documentation</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>It will probably come as no surprise that one of the main limitations of using <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> is the lack of documentation and tutorials. This is a particular pain point as the API is not very straightforward.</html:p>
                <html:p>A while back, I started an <fr:link href="https://patricoferris.github.io/irmin-book/" type="external">Irmin book</fr:link> intending to help document the kinds of things real-world users would need in order to use <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> in earnest. For example: ways to <fr:link href="https://patricoferris.github.io/irmin-book/contents/versioned-data.html" type="external">deal with type migrations</fr:link> or <fr:link href="https://patricoferris.github.io/irmin-book/arch/runtime-types.html" type="external">primers on runtime types</fr:link>. 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.</html:p>
                <html:p>The <fr:link href="https://irmin.org/tutorial/introduction/" type="external">tutorials on the irmin website</fr:link> are still good starting points for most new users. But they quickly lack the depth for real-world scenarios.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>8</fr:month>
                  <fr:day>7</fr:day>
                </fr:date>
                <fr:title text="Feature Wishlist">Feature Wishlist</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>What follows are additional ideas for improving <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link>.</html:p>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>8</fr:month>
                      <fr:day>7</fr:day>
                    </fr:date>
                    <fr:title text="Heterogeneous Stores">Heterogeneous Stores</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html: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.</html:p>
                    <html:p>This leads to a few common workarounds:</html:p>
                    <html:ul>
                      <html:li>
                        <html:p>Storing a serealised version of your values, essentially escaping the type-system and implementing a form of dynamic typing.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>Growing your value to hold lots of different types via some large variant type.</html:p>
                      </html:li>
                    </html:ul>
                    <html:p>Both of these options are feasible and have been used in practice. However, they are workarounds. A long time ago <fr:link href="https://craigfe.io/" type="external">CraigFe</fr:link> created an <fr:link href="https://github.com/mirage/irmin/issues/909" type="external">RFC for heterogeneous stores</fr:link>, which I think about a lot. The main idea is to augment <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link><![CDATA[ paths (keys)]]>  to be GADTs that carry type information about the kinds of values they access <![CDATA[(similar to]]> <fr:link href="https://ocaml.org/p/hmap" type="external">heterogeneuous variants of other data structures</fr:link><![CDATA[). Something like this alongside a simplified]]>  API would make Irmin more appealing as a library for persistent data storage.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>8</fr:month>
                      <fr:day>7</fr:day>
                    </fr:date>
                    <fr:title text="Real-world Retrospectives">Real-world Retrospectives</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>This echos some thoughts from the <html:em>Documentation</html:em> section. There are some very real-world <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link><![CDATA[ use-cases out there. For example, for a long time (I'm not]]>  <![CDATA[sure if this is still the case) parts of the]]> <fr:link href="https://ocaml.org/p/tezos-context/latest#dependencies" type="external">Tezos blockchain were using Irmin</fr:link> which uses the <fr:link href="https://ocaml.org/p/irmin-pack/latest" type="external">irmin-pack</fr:link> 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 <fr:link href="https://tarides.com/blog/2020-09-01-introducing-irmin-pack/" type="external">blogs on tarides.com about the irmin-pack backend</fr:link>, but they might be outdated and should not be the first place to find advice on which Irmin backend to use.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>8</fr:month>
                      <fr:day>7</fr:day>
                    </fr:date>
                    <fr:title text="Active Development and Engagement">Active Development and Engagement</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>As far as I know, <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> was at the forefront of technologies that have come to be described as <fr:link href="https://lofi.so/" type="external">local-first</fr:link>. There is a growing interest <![CDATA[in this area (particularly as it acts as a counter-argument to an increasingly]]>  <![CDATA[online, centralised model). I highly recommend reading]]> <fr:link href="https://patrick.sirref.org/ink &amp; switch's essay on the matter/" type="external">Ink &amp; Switch's essay on the matter</fr:link>. And it would be great to see more research via <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> at things like <fr:link href="https://lu.ma/localfirstswunconf-stlouis" type="external">the lofi unconference</fr:link> and the <fr:link href="https://2023.splashcon.org/home/plf-2023" type="external">PLF workshop at SPLASH 2023</fr:link>!</html:p>
                    <html:p>Thank you for reading! And thank you to all the <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> contributors. I hope this might be useful in the future for building the next-generation <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link>!</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>7</fr:month>
              <fr:day>23</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/slipshow-x-xocaml/</fr:uri>
            <fr:display-uri>slipshow-x-xocaml</fr:display-uri>
            <fr:route>/slipshow-x-xocaml/</fr:route>
            <fr:title text="Slipshow x x-ocaml">Slipshow x x-ocaml</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>A short, explanatory post about combining two very fun pieces of work in OCaml.</html:p>
            <html:p><fr:link href="https://github.com/panglesd" type="external">Paul-Elliot</fr:link> has been building <fr:link href="https://github.com/panglesd/slipshow" type="external">Slipshow</fr:link> for some time now where slides are <html:em>slips</html:em> and your presentations run vertically. More recently, <fr:link href="/artw/" title="Arthur Wendling" uri="https://patrick.sirref.org/artw/" display-uri="artw" type="local">Arthur</fr:link> has built <fr:link href="https://github.com/art-w/x-ocaml" type="external">x-ocaml</fr:link>, a web component library for executable OCaml cells embedded into OCaml.</html:p>
            <html:p>Using <fr:link href="https://github.com/patricoferris/xocmd" type="external">xocmd</fr:link>, a small tool I built for translating markdown codeblocks to x-ocaml components, your Slipshow's can now be <html:em>executable</html:em>!</html:p>
            <html:pre><![CDATA[xocmd learn-effects.md | slipshow compile - > learn-effects.html]]></html:pre>
            <html:p>
    Take a look at 
    <html:a href="/bafkrmictvc3ap2ah37cbcdoo6rsl7vxqu6srogmgzx6iml45bq7zz5weo4.html">an example</html:a>!
    (or the 
    <html:a href="/bafkrmib3jugpkznxcftqjvhbbtfqgx4oz2m32p5xloh4nxia3lhxy2momq.md">source markdown</html:a>).
</html:p>
            <html:p>I really like this light-weight approach to building interactive presentations <![CDATA[for explaining things in OCaml (e.g. over running a jupyter notebook server).]]></html:p>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>7</fr:month>
              <fr:day>18</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/ocaml-quarterly-q2/</fr:uri>
            <fr:display-uri>ocaml-quarterly-q2</fr:display-uri>
            <fr:route>/ocaml-quarterly-q2/</fr:route>
            <fr:title text="Quarterly OCaml Q2">Quarterly OCaml Q2</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>Thanks to <fr:link href="https://patrick.sirref.org/tarides/" type="external">Tarides</fr:link> sponsorship, I get to work on open-source OCaml. This quarterly is a companion to my <fr:link href="/weeklies/" title="Patrick Ferris' Weeklies" uri="https://patrick.sirref.org/weeklies/" display-uri="weeklies" type="local">weeklies</fr:link>, summarising the last three months of development, peppered with ideas and thoughts about OCaml, its community and its future.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>7</fr:month>
                  <fr:day>18</fr:day>
                </fr:date>
                <fr:title text="What I wanted to work on?">What I wanted to work on?</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>There were two main things I hoped to <html:em>continue</html:em> working on: <html:strong>ppxlib</html:strong> and <html:strong>outreachy</html:strong>. These are projects that I was previously working on, and in the case of Outreachy I have now been involved for many years.</html:p>
                <html:p>In addition to this, all of my <fr:link href="/part-ii-2024/" title="Part II Students 2024" uri="https://patrick.sirref.org/part-ii-2024/" display-uri="part-ii-2024" type="local">Part II</fr:link> 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 <fr:link href="https://ocaml-explore.netlify.app/" type="external">my initial work on developing workflows for OCaml that just turned five years old</fr:link>. This directly fed into the rebranding and rethinking of <fr:link href="https://ocaml.org/" type="external">ocaml.org</fr:link> itself.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>7</fr:month>
                  <fr:day>18</fr:day>
                </fr:date>
                <fr:title text="What I worked on?">What I worked on?</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>7</fr:month>
                      <fr:day>18</fr:day>
                    </fr:date>
                    <fr:title text="Ppxlib">Ppxlib</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p><fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">Ppxlib</fr:link> is the de facto standard library for building OCaml preprocessors. At the time of writing, <html:code>opam list --depends-on=ppxlib</html:code> informs me that there are 267 reverse dependencies. <fr:link href="https://www.janestreet.com/" type="external">Janestreet</fr:link> is a heavy user of ppxes and has <fr:link href="https://github.com/orgs/janestreet/repositories?language=&amp;amp;q=ppx&amp;amp;sort=&amp;amp;type=all" type="external">authored many</fr:link>.</html:p>
                    <html:p>One of the main accomplishments this quarter was <fr:link href="/ppxlib-5-2/" title="Bumping Ppxlib's AST to 5.2" uri="https://patrick.sirref.org/ppxlib-5-2/" display-uri="ppxlib-5-2" type="local">bumping the internal AST to 5.2</fr:link>. 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 <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link>.</html:p>
                    <html: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 <![CDATA[factor in the churn of breaking changes (in the case of OCaml this is via]]> <fr:link href="https://github.com/ocaml/opam-repository/" type="external">PRs to the opam-repository</fr:link><![CDATA[). 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.</html:p>
                    <html:p><fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">Ppxlib</fr:link> sits awkwardly in the space of possible breaking changes. Tied to OCaml's parsetree, impacts of changes there ripple down to <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link>. The compiler itself can remain internally consistent, and is protected as it need only parse source code. <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">Ppxlib</fr:link>, 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 <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link>, it feels as though the number of syntax changes <![CDATA[has gone up (primarily from Janestreet work). Unless we make changes to how we provide]]>  support for these, maintainers of <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> will forever be stuck doing busy work! Thankfully, <fr:link href="/nathanreb/" title="Nathan Rebours" uri="https://patrick.sirref.org/nathanreb/" display-uri="nathanreb" type="local">Nathan</fr:link> <fr:link href="/ocaml-weekly-2025-w29/" title="OCaml Weekly 2025 w29" uri="https://patrick.sirref.org/ocaml-weekly-2025-w29/" display-uri="ocaml-weekly-2025-w29" type="local">has thoughts on how to improve this</fr:link>.</html:p>
                    <html:p>There are a slew of other features I have added to <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> including:</html:p>
                    <html:ul>
                      <html:li>
                        <html:p>Support for deriving from classes.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>Support for deriving from module bindings and signatures.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>Fixing compiler and ppxlib dummy locations.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>Bumping to 5.3.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>Migrations for 5.4.</html:p>
                      </html:li>
                    </html:ul>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>7</fr:month>
                      <fr:day>18</fr:day>
                    </fr:date>
                    <fr:title text="Outreachy">Outreachy</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Our two projects this year, one on <fr:link href="https://github.com/claudiusFX/claudius" type="external">claudius</fr:link> and one on <fr:link href="https://github.com/ocaml/dune" type="external">dune</fr:link>, are going extremely well. At the time of writing, we just had <fr:link href="/ocaml-weekly-2025-w29/" title="OCaml Weekly 2025 w29" uri="https://patrick.sirref.org/ocaml-weekly-2025-w29/" display-uri="ocaml-weekly-2025-w29" type="local">a mid-internship call to catch up</fr:link>, and I was blown away by the progress each intern has made. Unfortunately, <fr:link href="/outreachy/" title="Outreachy" uri="https://patrick.sirref.org/outreachy/" display-uri="outreachy" type="local">Outreachy</fr:link> 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.</html:p>
                    <html:p>Outreachy has been a wonderful source of new, committed OCaml developers. If you haven't already, do peruse the <fr:link href="https://ocaml.org/outreachy" type="external">webpage on OCaml.org</fr:link> to see past internships or <fr:link href="https://watch.ocaml.org/c/outreachy_ocaml/videos" type="external">watch the demo day presentations</fr:link>. For the mentors involved, <![CDATA[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 <fr:link href="/patrickferris/" title="Patrick Ferris" uri="https://patrick.sirref.org/patrickferris/" display-uri="patrickferris" type="local">do reach out to me</fr:link> if you are interested.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>7</fr:month>
                      <fr:day>18</fr:day>
                    </fr:date>
                    <fr:title text="Hazel">Hazel</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p><![CDATA[OCaml's feature set allows it to shine at writing programming languages (and]]>  <![CDATA[things of that ilk: compilers, interpretters, static analysis tools).]]> <fr:link href="/hazel/" title="Hazel" uri="https://patrick.sirref.org/hazel/" display-uri="hazel" type="local">Hazel</fr:link> is a research programming language with typed holes written completely in OCaml <![CDATA[(via the]]> <fr:link href="https://reasonml.github.io/" type="external">reason dialect</fr:link><![CDATA[).]]></html:p>
                    <html: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 <fr:link href="/hazel_of_ocaml/" title="hazel_of_ocaml" uri="https://patrick.sirref.org/hazel_of_ocaml/" display-uri="hazel_of_ocaml" type="local">OCaml to Hazel</fr:link>. Whilst new features are still being added to <fr:link href="/hazel/" title="Hazel" uri="https://patrick.sirref.org/hazel/" display-uri="hazel" type="local">Hazel</fr:link>, I hope this could serve as a tool to help develop test-suites and standard library functions using existing <![CDATA[OCaml solutions. In a student's work (]]> <fr:link href="/part-ii-hazel/" title="Type Error Debugging in Hazel" uri="https://patrick.sirref.org/part-ii-hazel/" display-uri="part-ii-hazel" type="local">Typed Debugging for Hazel</fr:link><![CDATA[), we used this tool to build a corpus of ill-typed]]>  <fr:link href="/hazel/" title="Hazel" uri="https://patrick.sirref.org/hazel/" display-uri="hazel" type="local">Hazel</fr:link> programs to great effect.</html:p>
                    <html: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 <fr:link href="/hazel/" title="Hazel" uri="https://patrick.sirref.org/hazel/" display-uri="hazel" type="local">Hazel</fr:link> and provide some low effort maintenance to help keep their compiler in good shape.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>7</fr:month>
                      <fr:day>18</fr:day>
                    </fr:date>
                    <fr:title text="Systems Programming in OCaml">Systems Programming in OCaml</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>In a cross-over with my own research, I have been developing many tools related to systems programming in OCaml including:</html:p>
                    <html:ul>
                      <html:li>
                        <html:p>An eBPF-based <fr:link href="/open-trace/" title="Opentrace" uri="https://patrick.sirref.org/open-trace/" display-uri="open-trace" type="local"><html:code>open</html:code> syscall tracing tool</fr:link>.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>A library in OCaml for <fr:link href="https://github.com/quantifyearth/void" type="external">spawning void processes</fr:link>.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>A <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">shell session manager</fr:link> that uses <fr:link href="https://irmin.org/" type="external">Irmin</fr:link> to manage sessions. It is nice to see a new push to <fr:link href="https://github.com/mirage/irmin/pull/2149" type="external">finally land the direct-style Irmin PR</fr:link>!</html:p>
                      </html:li>
                    </html:ul>
                    <html:p>This work is means to develop the underlying libraries that support it. For example, I have opened a few PRs to <fr:link href="https://github.com/ocaml-multicore/eio" type="external">Eio</fr:link> to add new "fork actions" to the spawn API. I also investigated the feasibility of changing the underlying mechanisms in <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link> to use <fr:link href="https://github.com/ocaml-multicore/picos" type="external">Picos</fr:link>. In the future, I think this could be important avoid further splitting the OCaml ecosystem.</html:p>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>7</fr:month>
                          <fr:day>18</fr:day>
                        </fr:date>
                        <fr:title text="OxCaml">OxCaml</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>I dabbled a little with <fr:link href="https://oxcaml.org/" type="external">OxCaml</fr:link> and build <fr:link href="/try-oxcaml/" title="Try OxCaml" uri="https://patrick.sirref.org/try-oxcaml/" display-uri="try-oxcaml" type="local">try-oxcaml</fr:link> 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 <![CDATA[(type definitions differeing between js_of_ocaml and the OxCaml compiler, resulting]]>  <![CDATA[in different Javascript runtime representations...).]]></html:p>
                        <html:p>This unblocked a few of my colleagues to get OxCaml working on tools like <fr:link href="https://jon.recoil.org/notebooks/foundations/foundations1.html" type="external">odoc_notebooks</fr:link> and <fr:link href="https://github.com/art-w/x-ocaml" type="external">x-ocaml</fr:link>.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>7</fr:month>
                      <fr:day>18</fr:day>
                    </fr:date>
                    <fr:title text="Forester">Forester</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>A good proportion of my work this quarter has been focused on how to present the very work that I am doing. <fr:link href="/jonmsterling/" title="Jon Sterling" uri="https://patrick.sirref.org/jonmsterling/" display-uri="jonmsterling" type="local">Jon Sterling</fr:link> has been developing a tool for scientific thought called <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link> which seemed like a possible candidate for writing and sharing my work.</html:p>
                    <html: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 <![CDATA[made use of additional markdown-based tools (like]]> <fr:link href="https://github.com/realworldocaml/mdx" type="external">ocaml-mdx</fr:link><![CDATA[).]]></html:p>
                    <html:p>This lead to the development of <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">Graft</fr:link>: a preprocessor for Forester forests, converting markdown and bibtex to trees.</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>7</fr:month>
                  <fr:day>18</fr:day>
                </fr:date>
                <fr:title text="What's next?">What's next?</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>So, I worked on most of what I wanted to work on and then some! Going forward I hope to keep maintaining <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> in some capacity and coordinating the OCaml community's <fr:link href="/outreachy/" title="Outreachy" uri="https://patrick.sirref.org/outreachy/" display-uri="outreachy" type="local">Outreachy</fr:link> efforts.</html:p>
                <html:p><![CDATA[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 <fr:link href="https://github.com/raven-ml/" type="external">Raven</fr:link>: I am interested to use this library in <fr:link href="/geocaml/" title="Geocaml" uri="https://patrick.sirref.org/geocaml/" display-uri="geocaml" type="local">Geocaml</fr:link>, a suite of geospatial tools written in OCaml that I maintain.</html:p>
                <html:p>I feel conflicted about the <fr:link href="https://patrick.sirref.org/oxcaml/" type="external">OxCaml</fr:link> 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 <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> 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 <fr:link href="https://patrick.sirref.org/oxcaml/" type="external">OxCaml</fr:link> 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.</html:p>
                <html:p>Finally, over the past two years I have done a lot of teaching. From <fr:link href="/part-ii/" title="Part II Projects" uri="https://patrick.sirref.org/part-ii/" display-uri="part-ii" type="local">Part II projects</fr:link> to <fr:link href="/focs/" title="Foundations of Computer Science" uri="https://patrick.sirref.org/focs/" display-uri="focs" type="local">supervisions</fr:link><![CDATA[. 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 <fr:link href="https://beautifulracket.com/" type="external">Beautiful Racket</fr:link>. I have tried in the past to do these sorts of things, for example <fr:link href="https://patricoferris.github.io/irmin-book/" type="external">The Irmin Book</fr:link>.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>7</fr:month>
                  <fr:day>18</fr:day>
                </fr:date>
                <fr:title text="Thank you">Thank you</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Thank you for reading this wrap up! And thank you again to <fr:link href="https://patrick.sirref.org/tarides/" type="external">Tarides</fr:link> for letting me work so freely on things that I think are good for the OCaml community.</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>5</fr:month>
              <fr:day>19</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/open-trace/</fr:uri>
            <fr:display-uri>open-trace</fr:display-uri>
            <fr:route>/open-trace/</fr:route>
            <fr:title text="Opentrace">Opentrace</fr:title>
            <fr:meta name="external">https://tangled.sh/@patrick.sirref.org/opentrace</fr:meta>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>Thanks to <fr:link href="https://github.com/koonwen/" type="external">Koonwen's</fr:link> excellent <fr:link href="https://github.com/koonwen/ocaml-libbpf" type="external">libbpf bindings in OCaml</fr:link>, I have been building a little tool called <html:code>opentrace</html:code> to make it easier to track an executable's inputs and outputs.</html:p>
            <html:p>This work was inspired my <fr:link href="/mdales/" title="Michael W. Dales" uri="https://patrick.sirref.org/mdales/" display-uri="mdales" type="local">Michael's</fr:link> self-proclaimed "gross hack": <fr:link href="https://github.com/quantifyearth/pyshark" type="external">pyshark</fr:link>. Whilst pyshark achieves its goals by injecting code into commonly used python objects and methods, <fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">opentrace</fr:link> uses <fr:link href="https://ebpf.io/" type="external">eBPF</fr:link><![CDATA[. By using a lower-level API (hooks in the kernel),]]> <fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">opentrace</fr:link> can remain programming language agnostic. However, less information is none about the user's intent compared to something like pyshark.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>5</fr:month>
                  <fr:day>19</fr:day>
                </fr:date>
                <fr:title text="Monitoring the System">Monitoring the System</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">opentrace</fr:link> has an <html:code>all</html:code> command that will trace the entire system.</html:p>
                <html: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]]></html:pre>
                <html:p>The <html:code>--flags=O_WRONLY</html:code> argument filters the events where the <html:code>O_WRONLY</html:code> flag was set in the call to <html:code>open</html:code>.</html:p>
                <html:p><![CDATA[We also get the name of the current executable linked to the task (]]> <html:code>comm</html:code><![CDATA[). The]]> <html:code>-wrapped</html:code> is an artefact of using Nix.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>5</fr:month>
                  <fr:day>19</fr:day>
                </fr:date>
                <fr:title text="Tracing an Executable">Tracing an Executable</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>The primary use case for this tool is to inspect what files your program might be reading and writing.</html:p>
                <html: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"]]></html:pre>
                <html:p>The "flags" argument can specify a small boolean formula for checking the open flags of a particular event with <html:code>|</html:code><![CDATA[ (or),]]> <html:code>&amp;</html:code><![CDATA[ (and), and]]> <html:code>~</html:code><![CDATA[ (not).]]>  Parentheses can be used for precedence.</html:p>
                <html:pre><![CDATA[$ sudo opentrace exec --flags="O_WRONLY|O_RDONLY" -- ocaml --version]]></html:pre>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>5</fr:month>
                  <fr:day>19</fr:day>
                </fr:date>
                <fr:title text="Spawning Subprocesses">Spawning Subprocesses</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>One feature <fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">opentrace</fr:link><![CDATA[ needs (in this proof-of-concept phase) is the ability to also trace subprocesses.]]></html:p>
                <html:p><fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">opentrace</fr:link> 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, <fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">opentrace</fr:link><![CDATA[ creates a new control group (cgroup) and places the new process into that group.]]>  This gives <fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">opentrace</fr:link> a new identifier to track, namely the cgroup.</html:p>
                <html:p>So consider the following program.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword-other">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-unit"><![CDATA[()]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-constant-language-capital-identifier">Eio_posix</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">run</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">@@</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">fun</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">env</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-constant-language-capital-identifier">Eio</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Path</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">save</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">create</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-polymorphic-variant">`Or_truncate</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-octal-integer">0o664</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">env</html:span><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source">fs</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">/</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">hello.txt</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">hello</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-constant-language-capital-identifier">Eio</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Process</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">run</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">env</html:span><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source">process_mgr</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">/bin/bash</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">-c</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">echo 'heya' &gt; heya.txt</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html:p>It first creates a file using direct calls to functions like <html:code>openat</html:code>. Then it spawns a process which creates a new file called <html:code>heya.txt</html:code>. This happens in a separate process. However, with the <html:code>--cgroups</html:code> flag we can capture both interactions with the operating system.</html:p>
                <html: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]]></html:pre>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>5</fr:month>
                      <fr:day>19</fr:day>
                    </fr:date>
                    <fr:title text="Eio's Process API">Eio's Process API</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>I have used the <html:code>Eio_unix</html:code> <fr:link href="https://ocaml.org/p/eio/latest/doc/Eio_unix/Process/index.html" type="external">fork action process API</fr:link> 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 <html:code>sudo</html:code>. When a user requests for a particular program to be executed and traced, <fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">opentrace</fr:link> spawns a process via the Eio Process API. <fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">Opentrace</fr:link> defines a few new so-called "fork actions", little fragments of C code that are run after the call to <html:code>fork</html:code><![CDATA[ (]]> <html:code>clone</html:code><![CDATA[).]]>  Most likely this ends with a call to <html:code>execve</html:code>, but other calls are possible for example <html:code>setuid</html:code> allowing <fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">opentrace</fr:link> to change the user of the child process so it does not run as <html:code>root</html:code><![CDATA[. Similarly, this is where (if used) we create the cgroup and place the process]]>  into that group.</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>5</fr:month>
                  <fr:day>19</fr:day>
                </fr:date>
                <fr:title text="Limitations: Io_uring">Limitations: Io_uring</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Whilst testing <html:code>opentrace</html:code> against some of the tools I use nearly daily, I noticed some events were being missed. I tried tracing <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">forester</fr:link>, and only the initial read of <html:code>forest.toml</html:code> was logged. It dawned on me that the reason for this was that <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">forester</fr:link><![CDATA[ (via]]> <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">eio</fr:link><![CDATA[) was using]]> <fr:link href="https://patrick.sirref.org/io_uring/" type="external">io_uring</fr:link> 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 <html:code>openat2</html:code>-style call!</html:p>
                <html:p>This is not news to seasoned, Linux systems programmers. Io_uring <fr:link href="https://blog.0x74696d.com/posts/iouring-and-seccomp/" type="external">bypasses <html:code>SECCOMP</html:code> filters</fr:link> for exactly the same reasons.</html:p>
                <html: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]]></html:pre>
                <html:p>It is interesting to note two things here:</html:p>
                <html:ol>
                  <html:li>
                    <html:p>We can tell that <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">forester</fr:link> reads the configuration file probably using something like <html:code>In_channel</html:code><![CDATA[ in OCaml (]]> <fr:link href="https://git.sr.ht/~jonsterling/ocaml-forester/tree/7f275290e211db2590b0d715d8fb47fc1de36550/item/lib/frontend/Config.ml#L22" type="external">it does</fr:link><![CDATA[).]]></html:p>
                  </html:li>
                  <html:li>
                    <html:p>It appears that Uring is performing IO in both worker threads and directly.</html:p>
                  </html:li>
                </html:ol>
                <html: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. <![CDATA[I have tried quite a few methods (e.g. tracing]]> <html:code>do_filp_open</html:code><![CDATA[) and at the moment I am tracing]]> <html:code>io_openat2</html: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!</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>5</fr:month>
              <fr:day>9</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/try-oxcaml/</fr:uri>
            <fr:display-uri>try-oxcaml</fr:display-uri>
            <fr:route>/try-oxcaml/</fr:route>
            <fr:title text="Try OxCaml">Try OxCaml</fr:title>
            <fr:meta name="external">https://patrick.sirref.org/oxcaml</fr:meta>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>This week, I have been trying out Janestreet's <fr:link href="https://blog.janestreet.com/oxidizing-ocaml-locality/" type="external">Oxidised OCaml</fr:link><![CDATA[ (see their]]> <fr:link href="/oxcaml-2024/" title="Oxidizing OCaml with Modal Memory Management" uri="https://patrick.sirref.org/oxcaml-2024/" display-uri="oxcaml-2024" type="local">ICFP paper</fr:link><![CDATA[).]]>  This adds a system of <html:em>modes</html:em> to OCaml for expressing things like locality.</html:p>
            <html:blockquote>
              <html: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.</html:p>
            </html:blockquote>
            <html:p>For example, you might say:</html:p>
            <html:pre class="hilite">
              <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">is_empty</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">s</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">string</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">@@</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">local</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-constant-language-capital-identifier">String</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">length</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">s</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">0</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
            </html:pre>
            <html:p>To get a feel for how this changes the language, you can follow their <fr:link href="https://github.com/janestreet/opam-repository/tree/with-extensions" type="external">instructions on their custom opam-repository</fr:link>. Alternatively, you can <fr:link href="https://patrick.sirref.org/oxcaml" type="external">give it a go in your browser</fr:link>! This is a full toplevel running with <html:code>Base</html:code><![CDATA[ installed (which has plenty of OxCaml annotations on Stdlib-like functions).]]></html:p>
            <html:p>Happy OxCamling!</html:p>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>5</fr:month>
              <fr:day>2</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/hazel-of-ocaml/</fr:uri>
            <fr:display-uri>hazel-of-ocaml</fr:display-uri>
            <fr:route>/hazel-of-ocaml/</fr:route>
            <fr:title text="A Transpiler from OCaml to Hazel">A Transpiler from OCaml to Hazel</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>Over the past few months, I have been piecing together a transpiler from <fr:link href="/hazel/" title="Hazel" uri="https://patrick.sirref.org/hazel/" display-uri="hazel" type="local">Hazel</fr:link> to OCaml. This is, in part, to help one of my third-year undergraduate students who is working on <fr:link href="/part-ii-hazel/" title="Type Error Debugging in Hazel" uri="https://patrick.sirref.org/part-ii-hazel/" display-uri="part-ii-hazel" type="local">type error debugging in Hazel</fr:link>.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>5</fr:month>
                  <fr:day>2</fr:day>
                </fr:date>
                <fr:title text="Typed Holes">Typed Holes</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><fr:link href="/hazel/" title="Hazel" uri="https://patrick.sirref.org/hazel/" display-uri="hazel" type="local">Hazel</fr:link> is a <fr:link href="/omar-hazel-2017/" title="Hazelnut: a bidirectionally typed structure editor calculus" uri="https://patrick.sirref.org/omar-hazel-2017/" display-uri="omar-hazel-2017" type="local">functional programming language with typed holes</fr:link>. 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.</html:p>
                <html:p>To get a flavour of Hazel, take a regular map function for lists.</html:p>
                <html: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])]]></html:pre>
                <html:p><![CDATA[The question mark (]]> <html:code>?</html:code><![CDATA[) is a hole. The program evaluates to the following expression of type]]> <html:code><![CDATA[[?]]]></html:code><![CDATA[ (for people more]]>  familiar with OCaml types <html:code>? list</html:code><![CDATA[).]]></html:p>
                <html:pre><![CDATA[[ ?, ?, ? ]]]></html:pre>
                <html:p>Hazel supports <fr:link href="/zhao-typeerror-2024/" title="Total Type Error Localization and Recovery with Holes" uri="https://patrick.sirref.org/zhao-typeerror-2024/" display-uri="zhao-typeerror-2024" type="local">local type inference</fr:link> but nothing involving unification variables. For example, a simple <html:code>add_one</html:code> function in <fr:link href="/hazel/" title="Hazel" uri="https://patrick.sirref.org/hazel/" display-uri="hazel" type="local">Hazel</fr:link><![CDATA[ (]]> <html:code>fun x -&gt; x + 1</html:code><![CDATA[) has type]]> <html:code>? -&gt; Int</html:code>.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>5</fr:month>
                  <fr:day>2</fr:day>
                </fr:date>
                <fr:title text="From OCaml to Hazel">From OCaml to Hazel</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html: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 <![CDATA[boilerplate code (e.g. URI parsing or standard library functions for strings).]]></html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>5</fr:month>
                      <fr:day>2</fr:day>
                    </fr:date>
                    <fr:title text="A Transformation of Syntax">A Transformation of Syntax</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Hazel markets itself as an "Elm/ML-like functional programming language". From the previous example of <html:code>map</html:code>, it should be apparent just how close to OCaml the language is.</html:p>
                    <html:p>It turns out that a majority of the transpiler is a <html:em>transformation of syntax</html:em>. Take a simple ADT for an arithmetic programming language.</html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-keyword-other">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">expr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Float</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">of</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">float</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Add</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">of</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">expr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">*</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">expr</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Sub</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">of</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">expr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">*</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">expr</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Mul</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">of</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">expr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">*</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">expr</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Div</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">of</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">expr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">*</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">expr</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                    <html:p>And when we run <fr:link href="/hazel_of_ocaml/" title="hazel_of_ocaml" uri="https://patrick.sirref.org/hazel_of_ocaml/" display-uri="hazel_of_ocaml" type="local">hazel_of_ocaml</fr:link> over this OCaml type declaration.</html:p>
                    <html:pre><![CDATA[type expr =
  + Float(Float)
  + Add((expr, expr))
  + Sub((expr, expr))
  + Mul((expr, expr))
  + Div((expr, expr))
 in ?]]></html:pre>
                    <html:p>Not much has changed expect some syntax. <fr:link href="/hazel/" title="Hazel" uri="https://patrick.sirref.org/hazel/" display-uri="hazel" type="local">Hazel</fr:link> does not have a notion of top-level expression so <fr:link href="/hazel_of_ocaml/" title="hazel_of_ocaml" uri="https://patrick.sirref.org/hazel_of_ocaml/" display-uri="hazel_of_ocaml" type="local">hazel_of_ocaml</fr:link> 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 <![CDATA[with no support for modules or labelled records out of the box (there are plenty of development branches]]>  <![CDATA[with these features).]]></html:p>
                    <html:p>If we try out the same <html:code>map</html:code> function but written in OCaml and transpiled to Hazel we get.</html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword">rec </html:span><html:span class="ocaml-entity-name-function-binding">map</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">f</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">function</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-list"><![CDATA[[]]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-list"><![CDATA[[]]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">x</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">xs</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">f</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">x</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">map</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">f</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">xs</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                    <html:p>Which becomes the following hazel program.</html:p>
                    <html:pre><![CDATA[let map = fun f -> fun x1 -> case x1
  | [] => []
  | x :: xs => f(x) :: map(f)(xs)
end in ?]]></html:pre>
                    <html:p>We could have a field day discussing the syntax of OCaml and Hazel <![CDATA[(parentheses for function arguments, well-scoped cases for pattern-matching, a]]>  <![CDATA[different arrow for pattern-matching etc.). What would be more interesting is]]>  taking a look at how to handle polymorphism in Hazel.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>5</fr:month>
                      <fr:day>2</fr:day>
                    </fr:date>
                    <fr:title text="Explicit Polymorphism">Explicit Polymorphism</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Hazel has <html:em>explicit polymorphism</html:em>. So far, we have not seen it as we have let the types have holes in them. The <html:code>map</html:code> function in OCaml has the following type.</html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-keyword-other">val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">map</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> 
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-storage-type">'a</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-storage-type">'b</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-storage-type">'a</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">list</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-storage-type">'b</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">list</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                    <html:p><![CDATA[We must remind ourselves (by reading]]> <fr:link href="https://www.craigfe.io/posts/polymorphic-type-constraints" type="external">Craig's excellent blogpost on the matter</fr:link><![CDATA[) that in OCaml]]></html:p>
                    <html:blockquote>
                      <html:p>... type variables in signatures are implicitly universally-quantified</html:p>
                    </html:blockquote>
                    <html:p>So in reality, we have that <html:code>map</html:code> has the following type.</html:p>
                    <html:pre><![CDATA[val map : ∀ a b. (a ->  b) -> a list -> b list]]></html:pre>
                    <html:p>In Hazel, we have to explicitly type our <html:code>map</html: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 <html:code>map</html:code><![CDATA[ function (whether that be recursively or somewhere later in our]]>  <![CDATA[program).]]></html:p>
                    <html: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])]]></html:pre>
                    <html:p><html:code>forall</html:code> introduces a universally quantified type variable into our type annotation, and <html:code>typfun</html:code><![CDATA[ introduces it into the function itself (à la System F). Type application]]>  requires <html:code>@&lt;T&gt;</html:code> where <html:code>T</html:code> is some type. This allows hazel to quite easily support higher rank polymorphism, but we will not worry too much about that.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>5</fr:month>
                      <fr:day>2</fr:day>
                    </fr:date>
                    <fr:title text="Propagating OCaml Types into Hazel">Propagating OCaml Types into Hazel</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Most often, OCaml users interact with <html:em>prenex</html:em><![CDATA[ polymorphism (rank-1) where the universal quantifiers are]]>  at the front of the type. <fr:link href="https://ocaml.org/manual/5.2/polymorphism.html#s:higher-rank-poly" type="external">OCaml does support quantifiers inside certain types like records</fr:link>.</html:p>
                    <html:p>What this means for the transpiler is that we can <html:strong>reuse OCaml's type inference</html:strong> to safely instantiate the correct type annotations and type applications in Hazel! To do this, <html:code>hazel_of_ocaml</html:code> uses <fr:link href="https://ocaml.github.io/merlin/" type="external">Merlin</fr:link> to inspect the type of the function in either a value binding or at the point of a function application.</html:p>
                    <html:p>Take a simple, polymorphic <html:code>length</html:code> function.</html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword">rec </html:span><html:span class="ocaml-entity-name-function-binding">length</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">function</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-list"><![CDATA[[]]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">0</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language">_</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">xs</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">+</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">length</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">xs</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">int_len</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">length</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">1</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">2</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">3</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">str_len</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">length</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">only</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">two</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                    <html:p>When we run this through <html:code>hazel_of_ocaml</html:code> with the <html:code>-type</html:code> flag we get.</html:p>
                    <html: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 ?]]></html:pre>
                    <html:p><html:code>hazel_of_ocaml</html:code> has correctly instantiated the type for <html:code>length</html:code> inside the recursive function and then in each case with the integer list and the string list.</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>5</fr:month>
                  <fr:day>2</fr:day>
                </fr:date>
                <fr:title text="A Corpus of Hazel Programs">A Corpus of Hazel Programs</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>The impetus for this work was to derive a corpus of ill-typed Hazel programs. Luckily, such a corpus exists for OCaml! <fr:link href="/ocaml-corpus/" title="A Collection of Novice Interactions with the OCaml Top-Level System" uri="https://patrick.sirref.org/ocaml-corpus/" display-uri="ocaml-corpus" type="local">Seidel et al.</fr:link> created a corpus of OCaml programs from their undergraduate students at UC San Diego. <fr:link href="https://github.com/patricoferris/hazel-corpus" type="external">Some of these programs have been transpiled to Hazel</fr:link>.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>5</fr:month>
                  <fr:day>2</fr:day>
                </fr:date>
                <fr:title text="Future Work">Future Work</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><fr:link href="/hazel/" title="Hazel" uri="https://patrick.sirref.org/hazel/" display-uri="hazel" type="local">Hazel</fr:link> 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 <![CDATA[(e.g. handling the]]> <html:code>cmi</html:code><![CDATA[ files).]]></html:p>
                <html: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?</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>2</fr:month>
              <fr:day>18</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/ppxlib-5-2/</fr:uri>
            <fr:display-uri>ppxlib-5-2</fr:display-uri>
            <fr:route>/ppxlib-5-2/</fr:route>
            <fr:title text="Bumping Ppxlib's AST to 5.2">Bumping Ppxlib's AST to 5.2</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p><fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">Ppxlib</fr:link> is a libary for building OCaml preprocessors. Users can generate OCaml code <html:em>from</html:em><![CDATA[ OCaml code (derivers) or replace parts of OCaml code with other OCaml code (rewriters).]]></html:p>
            <html:p>At the core of <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> is the OCaml parsetree; a data structure in the compiler that represents OCaml source code. <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">Ppxlib</fr:link><![CDATA[ makes a distinction between the source parsetree (based on the version of the OCaml compiler you are using) and]]> <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link><![CDATA['s parsetree (a copy of]]> <html:em>some</html:em><![CDATA[ parsetree from the compiler).]]></html:p>
            <html:p>In <fr:link href="https://discuss.ocaml.org/t/ann-ppxlib-0-36-0" type="external">ppxlib.0.36.0</fr:link>, 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.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>2</fr:month>
                  <fr:day>18</fr:day>
                </fr:date>
                <fr:title text="Manual Migrations in Ppxlib">Manual Migrations in Ppxlib</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>It is possible to perform migrations between parsetrees manually using the <html:code>ppxlib.ast</html:code> package.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword-other">open</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Ppxlib</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">open</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Ast_builder</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Make</html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-keyword-other">struct</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">loc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Location</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">none</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">end</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">pp_expr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Format</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">printf</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-constant-character-printf"><![CDATA[%a]]> </html:span><html:span class="ocaml-constant-character-printf"><![CDATA[%!]]> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pp_ast</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">expression</html:span><html:span class="ocaml-source"> ?</html:span><html:span class="ocaml-source">config</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-constant-language-capital-identifier">None</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">loc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Location</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">none</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">str</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">txt</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">txt</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">loc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">module</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">To_408</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> 
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-constant-language-capital-identifier">Ppxlib_ast</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Convert</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Ppxlib_ast</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Js</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Ppxlib_ast__</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Versions</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">OCaml_408</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html:p>The <html:code>Ppxlib_ast.Js</html:code> module is <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link><![CDATA['s AST (since]]> <html:code>ppxlib.0.36.0</html:code><![CDATA[ OCaml 5.2.0). We can use functions]]>  provided by the <html:code>Convert</html:code> functor to copy parts of the AST from one version to another. Usually there is very little difference between the versioned parsetrees.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">func</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">arg</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">body</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source">pexp_fun</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nolabel</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">None</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">ppat_var</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">str</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">arg</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">body</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">add_expr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">func</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">x</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">func</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">y</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">eapply</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">evar</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">Int.add</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">evar</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">x</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">evar</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">y</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html: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.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pp_expr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">add_expr</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> 
</html:span>
<html:span class="ocaml-constant-language-capital-identifier">Pexp_function</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pparam_loc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">__loc</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pparam_desc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pparam_val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nolabel</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">None</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Ppat_var</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">x</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pparam_loc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">__loc</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pparam_desc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pparam_val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nolabel</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">None</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Ppat_var</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">y</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">None</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pfunction_body</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pexp_apply</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">         </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pexp_ident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Ldot</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Lident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">Int</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">add</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">         </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nolabel</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pexp_ident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Lident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">x</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">           </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nolabel</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pexp_ident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Lident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">y</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">           </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">         </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-operator">-</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">unit</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-unit"><![CDATA[()]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html:p>This is a relatively new feature of the parsetree, if we migrate the expression down to <html:code>4.08</html: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.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">expr_408</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">To_408</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">copy_expression</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">add_expr</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>2</fr:month>
                  <fr:day>18</fr:day>
                </fr:date>
                <fr:title text="Function Arity in the OCaml Parsetree">Function Arity in the OCaml Parsetree</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html: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:</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">add</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">x</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">y</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">x</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">+</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">y</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html:p>A two-argument <html:code>add</html:code> function would be represented in the parsetree as <html:code>fun x -&gt; fun y -&gt; x + y</html:code><![CDATA[. Using the nodes from the parsetree (with some details removed) it would be]]> <html:code><![CDATA[Pexp_fun (x, Pexp_fun (y, Pexp_apply ...))]]></html:code>.</html:p>
                <html:p>Now, since OCaml 5.2, functions can be expressed with their syntactic arity intact. The function <html:code>add</html:code> would look something like <html:code><![CDATA[Pexp_function ([ x; y ], Pfunction_body (Pexp_apply ...))]]></html:code>. Both arguments are stored as a list.</html:p>
                <html:p>The constructor <html:code>Pexp_function</html:code> was not a new addition to the parsetree. It used to represent pattern-matching expressions like <html:code>function A -&gt; 1</html:code>. This can now be expressed as a function body of <html:code>Pfunction_cases</html:code>.</html:p>
                <html:p>Whilst these additions and modifications to the parsetree are arguably a better design, it has caused chaos in terms of <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link>'s reverse dependencies!</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>2</fr:month>
                  <fr:day>18</fr:day>
                </fr:date>
                <fr:title text="Coalescing Function Arguments">Coalescing Function Arguments</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>In <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> <html:code>0.36.0</html:code>, functions from <html:code>Ast_builder</html:code> will help ppx authors produce maximum arity functions. However, functions from <html:code>Ast_helper</html:code> will not do this.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">ast_helper_func</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">arg</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">body</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-constant-language-capital-identifier">Ast_helper</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Exp</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">fun_</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nolabel</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">None</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">ppat_var</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">str</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">arg</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">body</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">ast_helper_expr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">ast_helper_func</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">x</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">ast_helper_func</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">y</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">eapply</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">evar</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">Int.equal</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">evar</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">x</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">evar</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">y</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html:p>Here we recreate our helper function to create function expressions using <html:code>Ast_helper.Exp.fun_</html:code> instead. We can now show the difference between the <html:code>expr</html:code> expression and the <html:code>ast_helper_expr</html:code> expression.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pp_expr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">add_expr</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-constant-language-capital-identifier">Pexp_function</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pparam_loc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">__loc</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pparam_desc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pparam_val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nolabel</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">None</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Ppat_var</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">x</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pparam_loc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">__loc</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pparam_desc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pparam_val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nolabel</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">None</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Ppat_var</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">y</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">None</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pfunction_body</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pexp_apply</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">         </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pexp_ident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Ldot</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Lident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">Int</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">add</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">         </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nolabel</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pexp_ident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Lident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">x</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">           </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nolabel</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pexp_ident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Lident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">y</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">           </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">         </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-operator">-</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">unit</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-unit"><![CDATA[()]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html:p>Above, we see a function expression with arity <html:em>two</html:em>. Below, we see nested function expressions each with arity <html:em>one</html:em>.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pp_expr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">ast_helper_expr</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-constant-language-capital-identifier">Pexp_function</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pparam_loc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">__loc</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pparam_desc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pparam_val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nolabel</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">None</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Ppat_var</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">x</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">None</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pfunction_body</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pexp_function</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">         </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pparam_loc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">__loc</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">             </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pparam_desc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pparam_val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nolabel</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">None</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Ppat_var</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">y</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">             </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">           </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">         </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">None</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">         </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pfunction_body</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">             </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pexp_apply</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">                </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pexp_ident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Ldot</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Lident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">Int</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">equal</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">                </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nolabel</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pexp_ident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Lident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">x</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">                  </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nolabel</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Pexp_ident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Lident</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">y</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">                  </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">                </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">         </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-operator">-</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">unit</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-unit"><![CDATA[()]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>2</fr:month>
                  <fr:day>18</fr:day>
                </fr:date>
                <fr:title text="Ramifications for Ppxlib Users">Ramifications for Ppxlib Users</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Many, many, <html:em>many</html:em> ppxes broke after migrating the <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> AST to 5.2. Mostly, this is due to pattern-matching. Downstream users of <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> frequently pattern-match directly against the parsetree. However, nodes such as <html:code>Pexp_fun</html:code> no longer exist and <html:code>Pexp_function</html:code> has completely different constructor arguments!</html:p>
                <html:p><![CDATA[Patching all the ppxes has been quite difficult. Most ppxes only deal with single arguments at a time (e.g.]]> <html:code>Pexp_fun x</html:code><![CDATA[) but now they must handle zero or more arguments at a time. (In the zero case, this will always correspond to a pattern-matching]]> <html:code>function</html:code><![CDATA[).]]></html:p>
                <html: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 <html:code>ppxlib.0.36.0</html:code>:</html:p>
                <html:ul>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/patricoferris/ppx_deriving_yaml/pull/58" type="external">https://github.com/patricoferris/ppx_deriving_yaml/pull/58</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/mirage/ocaml-rpc/pull/181" type="external">https://github.com/mirage/ocaml-rpc/pull/181</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://gitlab.com/o-labs/ppx_deriving_jsoo/-/merge_requests/1" type="external">https://gitlab.com/o-labs/ppx_deriving_jsoo/-/merge_requests/1</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/ocaml-community/sedlex/pull/160" type="external">https://github.com/ocaml-community/sedlex/pull/160</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/ocaml-sys/config.ml/pull/22" type="external">https://github.com/ocaml-sys/config.ml/pull/22</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/vogler/ppx_distr_guards/pull/2" type="external">https://github.com/vogler/ppx_distr_guards/pull/2</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/ocaml-gospel/gospel/pull/424" type="external">https://github.com/ocaml-gospel/gospel/pull/424</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/teamwalnut/graphql-ppx/pull/299" type="external">https://github.com/teamwalnut/graphql-ppx/pull/299</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/ocsigen/lwt/pull/1033" type="external">https://github.com/ocsigen/lwt/pull/1033</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://gitlab.com/gopiandcode/ppx-inline-alcotest/-/merge_requests/3" type="external">https://gitlab.com/gopiandcode/ppx-inline-alcotest/-/merge_requests/3</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/dariusf/ppx_interact/pull/3" type="external">https://github.com/dariusf/ppx_interact/pull/3</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/ocaml-ppx/ppx_deriving_yojson/pull/160" type="external">https://github.com/ocaml-ppx/ppx_deriving_yojson/pull/160</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/lpcic/elpi/pull/276" type="external">https://github.com/LPCIC/elpi/pull/276</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/mirage/repr/pull/110" type="external">https://github.com/mirage/repr/pull/110</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/programingisthefuture/ppx_default/pull/3" type="external">https://github.com/ProgramingIsTheFuture/ppx_default/pull/3</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/codinuum/vlt/pull/3" type="external">https://github.com/codinuum/vlt/pull/3</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/sim642/ppx_deriving_hash/pull/6" type="external">https://github.com/sim642/ppx_deriving_hash/pull/6</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/ocsigen/tyxml/pull/340" type="external">https://github.com/ocsigen/tyxml/pull/340</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/sim642/ppx_viewpattern/pull/2" type="external">https://github.com/sim642/ppx_viewpattern/pull/2</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/little-arhat/ppx_jsobject_conv/pull/11" type="external">https://github.com/little-arhat/ppx_jsobject_conv/pull/11</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/robur-coop/lun/pull/1" type="external">https://github.com/robur-coop/lun/pull/1</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://gitlab.com/o-labs/ppx_deriving_encoding/-/merge_requests/4" type="external">https://gitlab.com/o-labs/ppx_deriving_encoding/-/merge_requests/4</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/francoisthire/bam/pull/12" type="external">https://github.com/francoisthire/bam/pull/12</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/xguerin/bitstring/pull/36" type="external">https://github.com/xguerin/bitstring/pull/36</fr:link>
                    </html:p>
                  </html:li>
                </html:ul>
                <html:p><![CDATA[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]]> <fr:link href="https://www.cambridge.org/core/journals/journal-of-functional-programming/article/pattern-matching-with-abstract-data-types1/04DD26A0E6CA3A1E87E0E6AE8BC02EED" type="external">tension is not new</fr:link>.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>2</fr:month>
                  <fr:day>18</fr:day>
                </fr:date>
                <fr:title text="The Future of Ppxlib">The Future of Ppxlib</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">Ppxlib</fr:link> 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 <fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/558" type="external">the 5.3 bump</fr:link>!</html:p>
                <html:p>There have been many discussions about simplifying this process, but so far the time and effort to build a <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link><![CDATA[ that will result in fewer breakages is too high (see]]> <fr:link href="https://github.com/ocaml-ppx/ppx" type="external">an attempt using views</fr:link><![CDATA[).]]></html:p>
                <html:p>Thank you to Tarides and Jane Street for funding my time to work on this release and all the chaos it has caused.</html:p>
                <html:p>Happy preprocessing!</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>2</fr:month>
              <fr:day>28</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/vpnkit-upgrade/</fr:uri>
            <fr:display-uri>vpnkit-upgrade</fr:display-uri>
            <fr:route>/vpnkit-upgrade/</fr:route>
            <fr:title text="Defunctorising VPNKit">Defunctorising VPNKit</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p><fr:link href="/vpnkit/" title="VPNKit" uri="https://patrick.sirref.org/vpnkit/" display-uri="vpnkit" type="local">VPNKit</fr:link> 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.</html:p>
            <html:p>This short post discusses some of the recent changes to MirageOS and how they impact <fr:link href="/vpnkit/" title="VPNKit" uri="https://patrick.sirref.org/vpnkit/" display-uri="vpnkit" type="local">VPNKit</fr:link>.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:uri>https://patrick.sirref.org/dune-virt-libs/</fr:uri>
                <fr:display-uri>dune-virt-libs</fr:display-uri>
                <fr:route>/dune-virt-libs/</fr:route>
                <fr:title text="Dune Virtual Libraries">Dune Virtual Libraries</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Dune, for quite some time, has supported <html:em>virtual libraries</html:em><![CDATA[. This allows library authors to define a signature without an implementation (similar to OCaml's]]> <html:code>module type S = struct ... end</html:code><![CDATA[). 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.]]></html:p>
                <html:p>This feature has been quite widely used in OCaml. For example, the <fr:link href="https://github.com/mirage/digestif" type="external">excellent <html:code>digestif</html:code> library</fr:link> of hashing algorithms provides both C and OCaml implementations individually packaged into <html:code>digestif.c</html:code> and <html:code>digestif.ocaml</html:code><![CDATA[ respectively. Consider developing a browser application that needs some hashing algorithm (e.g.]]> <fr:link href="https://github.com/patricoferris/omditor" type="external">Irmin in the browser</fr:link><![CDATA[). We can explicitly use the OCaml backend for digestif which]]> <fr:link href="https://github.com/ocsigen/js_of_ocaml" type="external">js_of_ocaml</fr:link> will happily compile for us.</html:p>
                <html:p>There are two distinct limitations to this approach.</html:p>
                <html:ol>
                  <html:li>
                    <html:p>Applications can only link <html:em>exactly one</html:em> implementation.</html:p>
                  </html:li>
                  <html:li>
                    <html:p><![CDATA[Implementations cannot expose additional functionality easily (see]]> <fr:link href="https://github.com/ocaml/dune/issues/5997" type="external">dune#5597</fr:link><![CDATA[).]]></html:p>
                  </html:li>
                </html:ol>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>2</fr:month>
                  <fr:day>28</fr:day>
                </fr:date>
                <fr:title text="Functors in MirageOS">Functors in MirageOS</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><fr:link href="https://mirage.io/" type="external">MirageOS</fr:link><![CDATA[ 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.]]> <html:code>unix</html:code>, <html:code>hvt</html:code><![CDATA[ etc.)]]></html:p>
                <html:p>Recently, <fr:link href="https://github.com/mirage/mirage-skeleton/pull/407/" type="external">there has been a push</fr:link> to use <fr:link href="/dune-virt-libs/" title="Dune Virtual Libraries" uri="https://patrick.sirref.org/dune-virt-libs/" display-uri="dune-virt-libs" type="local">dune virtual libraries</fr:link> instead.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>2</fr:month>
                  <fr:day>28</fr:day>
                </fr:date>
                <fr:title text="VPNKit's Fake Clock &amp; Time">VPNKit's Fake Clock &amp; Time</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><![CDATA[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]]> <html:code><![CDATA[(wrapped false)]]></html:code><![CDATA[). This allows implementers to expose additional modules alongside the implementation of the virtual library.]]></html:p>
                <html: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.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword">module</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">R</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-constant-language-capital-identifier">Dns_forward</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Resolver</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Make</html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Proto_client</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Fake</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Time</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Fake</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Clock</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html:p>In this new world of <fr:link href="/dune-virt-libs/" title="Dune Virtual Libraries" uri="https://patrick.sirref.org/dune-virt-libs/" display-uri="dune-virt-libs" type="local">dune virtual libraries</fr:link>, our <html:code>Resolver</html:code> is significantly more simple.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword">module</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">R</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Dns_forward</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Resolver</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Make</html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Proto_client</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html:p><![CDATA[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.]]></html:p>
                <html:p>The first thing I had to do was make the <html:code>mirage-mtime</html:code> and <html:code>mirage-sleep</html:code> virtual libraries unwrapped. This allowed me to make a new private dune library called <html:code>fake_time</html:code> with <html:em>two</html:em> public modules: the normal interface required by <html:code>mirage-mtime</html:code> and another module called <html:code>Fake_time_state</html:code> containing:</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">timeofday</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">ref</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">0L</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">c</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Lwt_condition</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">create</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-unit"><![CDATA[()]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">advance</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">nsecs</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source">timeofday</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Int64</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">add</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">!</html:span><html:span class="ocaml-source">timeofday</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">nsecs</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-constant-language-capital-identifier">Lwt_condition</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">broadcast</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">c</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-unit"><![CDATA[()]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">reset</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-unit"><![CDATA[()]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source">timeofday</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">0L</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-constant-language-capital-identifier">Lwt_condition</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">broadcast</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">c</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-unit"><![CDATA[()]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html:p>I did the same for <html:code>fake_sleep</html:code> which depended on the state from the <html:code>fake_time</html:code><![CDATA[ library (something a normal library wouldn't).]]></html:p>
                <html:p><![CDATA[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. <![CDATA[You can only link one implementation at a time to an executable (or test).]]>  Thus, the dune rules for running the <html:code>dns_forward</html:code> test suite became:</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="dune-comment-line">; Uses the default  implementations provided by virtual libraries</html:span><html:span class="dune-source">
</html:span>
<html:span class="dune-meta-stanza"><![CDATA[(]]> </html:span><html:span class="dune-meta-class-stanza">executable</html:span><html:span class="dune-meta-stanza">
</html:span>
<html:span class="dune-meta-stanza"> </html:span><html:span class="dune-meta-stanza-library-field"><![CDATA[(]]> </html:span><html:span class="dune-keyword-other">name</html:span><html:span class="dune-meta-stanza-library-field"> </html:span><html:span class="dune-meta-atom">test</html:span><html:span class="dune-meta-stanza-library-field"><![CDATA[)]]> </html:span><html:span class="dune-meta-stanza">
</html:span>
<html:span class="dune-meta-stanza"> </html:span><html:span class="dune-meta-stanza-lib-or-exec-buildable"><![CDATA[(]]> </html:span><html:span class="dune-keyword-other">libraries</html:span><html:span class="dune-meta-stanza-lib-or-exec-buildable"> </html:span><html:span class="dune-meta-atom">dns_forward</html:span><html:span class="dune-meta-stanza-lib-or-exec-buildable"> </html:span><html:span class="dune-meta-atom">alcotest</html:span><html:span class="dune-meta-stanza-lib-or-exec-buildable"><![CDATA[)]]> </html:span><html:span class="dune-meta-stanza"><![CDATA[)]]> </html:span><html:span class="dune-source">
</html:span>
<html:span class="dune-source">
</html:span>
<html:span class="dune-comment-line">; Override the defaults and select the private fake libraries</html:span><html:span class="dune-source">
</html:span>
<html:span class="dune-meta-stanza"><![CDATA[(]]> </html:span><html:span class="dune-meta-class-stanza">executable</html:span><html:span class="dune-meta-stanza">
</html:span>
<html:span class="dune-meta-stanza">  </html:span><html:span class="dune-meta-stanza-library-field"><![CDATA[(]]> </html:span><html:span class="dune-keyword-other">name</html:span><html:span class="dune-meta-stanza-library-field"> </html:span><html:span class="dune-meta-atom">test_fake</html:span><html:span class="dune-meta-stanza-library-field"><![CDATA[)]]> </html:span><html:span class="dune-meta-stanza">
</html:span>
<html:span class="dune-meta-stanza">  </html:span><html:span class="dune-meta-stanza-lib-or-exec-buildable"><![CDATA[(]]> </html:span><html:span class="dune-keyword-other">libraries</html:span><html:span class="dune-meta-stanza-lib-or-exec-buildable"> </html:span><html:span class="dune-meta-atom">dns_forward</html:span><html:span class="dune-meta-stanza-lib-or-exec-buildable"> </html:span><html:span class="dune-meta-atom">alcotest</html:span><html:span class="dune-meta-stanza-lib-or-exec-buildable"> </html:span><html:span class="dune-meta-atom">fake_sleep</html:span><html:span class="dune-meta-stanza-lib-or-exec-buildable"> </html:span><html:span class="dune-meta-atom">fake_time</html:span><html:span class="dune-meta-stanza-lib-or-exec-buildable"><![CDATA[)]]> </html:span><html:span class="dune-meta-stanza"><![CDATA[)]]> </html:span><html:span class="dune-source">
</html:span>
</html:code>
                </html:pre>
                <html:p>With all of this machinery in place, I could now update <html:code>test_fake</html:code> to use the new modules that would provide the custom functionality for the clock and time implementations.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-comment-block"><![CDATA[(*]]> </html:span><html:span class="ocaml-comment-block"> The bad server should be marked offline and no-one will wait for it </html:span><html:span class="ocaml-comment-block"><![CDATA[*)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-constant-language-capital-identifier">Fake_time_state</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">reset</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-unit"><![CDATA[()]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-comment-block"><![CDATA[(*]]> </html:span><html:span class="ocaml-comment-block"> avoid the timeouts winning the race with the actual result </html:span><html:span class="ocaml-comment-block"><![CDATA[*)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-constant-language-capital-identifier">Fake_time_state</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">advance</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Duration</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">of_ms</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">500</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> 
</html:span>
</html:code>
                </html:pre>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>2</fr:month>
                  <fr:day>28</fr:day>
                </fr:date>
                <fr:title text="Conclusion">Conclusion</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>The switch to <fr:link href="/dune-virt-libs/" title="Dune Virtual Libraries" uri="https://patrick.sirref.org/dune-virt-libs/" display-uri="dune-virt-libs" type="local">dune virtual libraries</fr:link> 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.</html:p>
                <html:p>The <fr:link href="https://github.com/moby/vpnkit/pull/646" type="external">pull request to upgrade VPNKit is open</fr:link>.</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2023</fr:year>
              <fr:month>8</fr:month>
              <fr:day>9</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/ocaml-rtree/</fr:uri>
            <fr:display-uri>ocaml-rtree</fr:display-uri>
            <fr:route>/ocaml-rtree/</fr:route>
            <fr:title text="Reviving OCaml R-Tree">Reviving OCaml R-Tree</fr:title>
            <fr:meta name="description">Fast-forwarding a decade-old OCaml implementation of the R-Tree geospatial data-structure.
</fr:meta>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>Antonin Guttman <fr:link href="http://www-db.deis.unibo.it/courses/SI-LS/papers/Gut84.pdf" type="external">first proposed R-Trees in 1984</fr:link>.</html:p>
            <html:blockquote>
              <html: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...</html:p>
            </html:blockquote>
            <html:p><![CDATA[There are lots of excellent resources for understanding more about R-Trees and all of the wonderful variations there of (e.g.]]> <fr:link href="http://www.cs.ucr.edu/~ravi/CS236Papers/rstar.pdf" type="external">R*-trees</fr:link><![CDATA[). This]]> <fr:link href="https://www.bartoszsypytkowski.com/r-tree/" type="external">blog post</fr:link> seems to be the most popular introduction.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:uri>https://patrick.sirref.org/ocaml-rtree-001/</fr:uri>
                <fr:display-uri>ocaml-rtree-001</fr:display-uri>
                <fr:route>/ocaml-rtree-001/</fr:route>
                <fr:title text="An OCaml Rtree Implementation">An OCaml Rtree Implementation</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>In the <fr:link href="https://www.cst.cam.ac.uk/research/eeg" type="external">Energy and Environment Group</fr:link> 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 <fr:link href="https://github.com/mariusae/ocaml-rtree" type="external">an implementation in pure OCaml</fr:link>. After reaching out to the author, they were more than happy for their work to be maintained in the <fr:link href="https://github.com/geocaml" type="external">Geocaml organisation</fr:link>, updated to the latest OCaml tools and <fr:link href="https://github.com/ocaml/opam-repository/pull/24227" type="external">hopefully released on opam</fr:link>.</html:p>
                <html:p>The <fr:link href="https://github.com/geocaml/ocaml-rtree/commit/073d79ad34de15f0671f2faafb24b1edc5c2d8c7" type="external">dunification</fr:link><![CDATA[ went smoothly whilst fast-forwarding 15 OCaml compiler versions with no changes or problems (just dune unused variable warnings).]]></html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:uri>https://patrick.sirref.org/ocaml-rtree-002/</fr:uri>
                <fr:display-uri>ocaml-rtree-002</fr:display-uri>
                <fr:route>/ocaml-rtree-002/</fr:route>
                <fr:title text="OCaml Rtree Examples">OCaml Rtree Examples</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><![CDATA[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]]> <html:code>Rectangle</html:code> envelope.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword-other">module</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Line</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">struct</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p0</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">float</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">*</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">float</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">float</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">*</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">float</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword">open</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Repr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">in</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source">record</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">line</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-keyword-other">fun</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p0</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p0</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword-operator">|+</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">field</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">p0</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">pair</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">float</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">float</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-keyword-other">fun</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">p0</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword-operator">|+</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">field</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">p1</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">pair</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">float</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">float</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-keyword-other">fun</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">p1</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword-operator">|&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">sealr</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">envelope</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Rtree</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Rectangle</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">envelope</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p0</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">x1</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">y1</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">x2</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">y2</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">x0</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Float</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">min</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">x1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">x2</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">in</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">x1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Float</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">max</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">x1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">x2</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">in</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">y0</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Float</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">min</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">y1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">y2</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">in</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">y1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Float</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">max</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">y1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">y2</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">in</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-constant-language-capital-identifier">Rtree</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Rectangle</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">v</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">x0</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">y0</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">x1</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">y1</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">end</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html:p>In addition to the <html:code>envelope</html:code> function, we also need to provide a runtime representation using <html:code>Repr</html:code>. In the example, we've constructed it by hand but I recommend using <fr:link href="https://ocaml.org/p/ppx_repr/latest" type="external">ppx_repr</fr:link> to derive it for you. From here we can create our index.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword-other">module</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">R</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Rtree</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Make</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Rtree</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Rectangle</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Line</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:uri>https://patrick.sirref.org/ocaml-rtree-003/</fr:uri>
                    <fr:display-uri>ocaml-rtree-003</fr:display-uri>
                    <fr:route>/ocaml-rtree-003/</fr:route>
                    <fr:title text="Inserting Values">Inserting Values</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html: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.</html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">r</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">i</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">R</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">empty</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">4</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">in</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-constant-language-capital-identifier">R</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">insert</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">i</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Line</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p0</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">1.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">1.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">2.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">2.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">r</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">R</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">&lt;</html:span><html:span class="ocaml-source">abstr</html:span><html:span class="ocaml-keyword-operator">&gt;</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                    <html:p>As you might expect, bulk loading takes a list of values instead.</html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">r</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">lines</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">        </html:span><html:span class="ocaml-constant-language-capital-identifier">Line</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">        </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p0</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">0.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">0.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">1.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">1.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">        </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p0</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">1.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">1.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">2.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">2.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">        </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p0</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">2.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">2.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">3.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">3.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">        </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p0</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">3.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">3.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">4.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">4.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">        </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword-other">in</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-constant-language-capital-identifier">R</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">load</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">max_node_load</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-constant-numeric-decimal-integer">4</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">lines</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">r</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">R</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">&lt;</html:span><html:span class="ocaml-source">abstr</html:span><html:span class="ocaml-keyword-operator">&gt;</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:uri>https://patrick.sirref.org/ocaml-rtree-004/</fr:uri>
                    <fr:display-uri>ocaml-rtree-004</fr:display-uri>
                    <fr:route>/ocaml-rtree-004/</fr:route>
                    <fr:title text="Spatial Queries">Spatial Queries</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>The lines we loaded into the last index are really just four segments of the line <html:code>y = x</html:code>. Let's spatially query for the first two segments.</html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">R</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">find</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">r</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Rtree</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Rectangle</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">v</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">x0</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-constant-numeric-decimal-float">0.</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">y0</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-constant-numeric-decimal-float">0.</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">x1</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-constant-numeric-decimal-float">2.</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">y1</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-constant-numeric-decimal-float">2.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-operator">-</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Line</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">list</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Line</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">p0</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">0.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">0.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">1.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">1.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Line</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">p0</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">1.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">1.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">2.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">2.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Line</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">p0</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">2.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">2.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">p1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-float">3.</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-float">3.</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                    <html:p>You can see the query actually returned the first three, that's because all bound checks are inclusive.</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <html:p>The <fr:link href="https://github.com/geocaml/ocaml-rtree/blob/d0a789b8eb6c594ed8c0f9c9a6c4b5cd7c734a03/test/image.ml#L95-L106" type="external">source repository includes a fairly simple example of rendering an R-Tree</fr:link> using <fr:link href="https://github.com/dbuenzli/vg" type="external">Vg</fr:link>. This can be done outside of the repository using the <html:code>tree</html:code> representation.</html:p>
            <html:pre class="hilite">
              <html:code><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source">show</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">R</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">tree</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">tree</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">R</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">R</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">tree</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">nonrec</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">tree</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-constant-language-capital-identifier">R</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">tree</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-constant-language-capital-identifier">Node</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">of</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Line</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">envelope</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">*</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">R</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">tree</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">list</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Leaf</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">of</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Line</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">envelope</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">*</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Line</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">list</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Empty</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
            </html:pre>
            <html:p>Here is an example rendering from the repository showing some random lines and the envelopes of the R-tree.</html:p>
            <html:p style="text-align:center">
    <html:img src="./rtree.svg" />
</html:p>
          </fr:mainmatter>
        </fr:tree>
        <html:div style="margin-top: 1em">
          <html:h1>Weeklies</html:h1>
        </html:div>
        <html:p>A collection of less thoughtfully crafted reports, focused on OCaml-related activities.</html:p>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2026</fr:year>
              <fr:month>3</fr:month>
              <fr:day>10</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/ocaml-roundup-february-2026/</fr:uri>
            <fr:display-uri>ocaml-roundup-february-2026</fr:display-uri>
            <fr:route>/ocaml-roundup-february-2026/</fr:route>
            <fr:title text="OCaml Roundup: February 2026">OCaml Roundup: February 2026</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>Much like last month, this month has been busy with lots of work on <fr:link href="/ocaml-tiff/" title="ocaml-tiff" uri="https://patrick.sirref.org/ocaml-tiff/" display-uri="ocaml-tiff" type="local">ocaml-tiff</fr:link> thanks to <fr:link href="https://patrick.sirref.org/tambe salome/" type="external">Tambe Salome</fr:link> and <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link>.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2026</fr:year>
                  <fr:month>3</fr:month>
                  <fr:day>10</fr:day>
                </fr:date>
                <fr:title text="Outreachy">Outreachy</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><fr:link href="https://patrick.sirref.org/tambe salome/" type="external">Tambe Salome</fr:link>, at the time of writing, has completed her internship! We will be hosting the biannual <fr:link href="https://discuss.ocaml.org/t/outreachy-demo-day-for-december-2025-round/17883" type="external">Demo Day celebration</fr:link> for this round's interns, so please do come along.</html:p>
                <html:p>Since the last update <fr:link href="https://patrick.sirref.org/tambe salome/" type="external">Tambe Salome</fr:link> and I have been slowly making progress on making the write-functionality more feature-complete. As I eluded <fr:link href="/ocaml-roundup-january-2026/" title="OCaml Roundup: January 2026" uri="https://patrick.sirref.org/ocaml-roundup-january-2026/" display-uri="ocaml-roundup-january-2026" type="local">last month</fr:link>, TIFF files are <html:em>hard</html: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 <![CDATA[store information that we could readily pull from the file itself (via]]>  something like <html:code><![CDATA[pread(2)]]></html:code><![CDATA[). 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.</html:p>
                <html:p>This month, I also bumped up against well-meaning contributions to <fr:link href="/ocaml-tiff/" title="ocaml-tiff" uri="https://patrick.sirref.org/ocaml-tiff/" display-uri="ocaml-tiff" type="local">ocaml-tiff</fr:link> that made use of AI. This left me with some thoughts that I am adding below.</html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2026</fr:year>
                      <fr:month>3</fr:month>
                      <fr:day>9</fr:day>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/vibecoding-etiquette/</fr:uri>
                    <fr:display-uri>vibecoding-etiquette</fr:display-uri>
                    <fr:route>/vibecoding-etiquette/</fr:route>
                    <fr:title text="Vibecoding Etiquette">Vibecoding Etiquette</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html: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.</html:p>
                    <html: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 <![CDATA[US Department of War (I struggle to find the meaningful difference between]]>  <fr:link href="https://www.anthropic.com/news/where-stand-department-war" type="external">"opertational planning" vs. "operational decision-making" given the leaders of the US DoW</fr:link><![CDATA[),]]>  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.</html:p>
                    <html:p>Everybody can draw their line where they want, and I am, in good faith, trying to find where mine should be.</html:p>
                    <html: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.</html:p>
                    <html: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. <fr:link href="https://github.com/ocaml-multicore/eio/blob/main/HACKING.md#ai-generated-code" type="external">Eio's "AI-generated Code"</fr:link> subsection is succinct and prohibits contributions that <html:em>solely</html:em> use AI.</html:p>
                    <html:blockquote>
                      <html: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.</html:p>
                      <html: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.</html:p>
                      <html: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.</html:p>
                    </html:blockquote>
                    <html:p>Additionally, I plead to other developers to <html:em>own</html:em> their use of these tools. Please, make Claude a co-author of the commits where Claude has generated <html:em>any</html: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 <fr:link href="https://github.com/ocaml/ocaml/blob/trunk/AI.md" type="external">OCaml compiler's AI notice</fr:link> which includes:</html:p>
                    <html:blockquote>
                      <html: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.</html:p>
                    </html:blockquote>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2026</fr:year>
                  <fr:month>3</fr:month>
                  <fr:day>10</fr:day>
                </fr:date>
                <fr:title text="Ppxlib">Ppxlib</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>We are still in the throes of supporting OCaml 5.5 in <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link>. Some of the features have proved more complicated to encode into migrations that "roundtrip". Roundtripping, in the context of <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link>, is when a modern feature of OCaml must be preserved in older abstract syntax trees which may have no specific node to encode them.</html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2026</fr:year>
                      <fr:month>3</fr:month>
                      <fr:day>10</fr:day>
                    </fr:date>
                    <fr:title text="Bugs in Ptyp_open">Bugs in Ptyp_open</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Unfortunately, <fr:link href="/jonmsterling/" title="Jon Sterling" uri="https://patrick.sirref.org/jonmsterling/" display-uri="jonmsterling" type="local">Jon Sterling</fr:link> was <fr:link href="https://mastodon.social/@jonmsterling@mathstodon.xyz/116085163199163273" type="external">bitten by this recently</fr:link>. <![CDATA[The feature in question was locally opening modules in types (added in OCaml]]>  <![CDATA[5.2). For example:]]></html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-keyword-other">module</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">M</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">struct</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">int</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">end</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">M</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">list</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                    <html:p>Here, the <html:code><![CDATA[M.(t list)]]></html:code> is an example of a new AST node called <html:code>Ptyp_open</html:code>. I had hastily not migrated <html:code>Ptyp_open</html:code> to older compilers. So what happened? Jon had used this new feature in his project with a 5.3 compiler with <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> 0.35. This is before our <fr:link href="/ppxlib-5-2/" title="Bumping Ppxlib's AST to 5.2" uri="https://patrick.sirref.org/ppxlib-5-2/" display-uri="ppxlib-5-2" type="local">internal bump to the 5.2 AST</fr:link> 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:</html:p>
                    <html:blockquote>
                      <html:p>Error: migration error: module open in types is not supported before OCaml 5.02</html:p>
                    </html:blockquote>
                    <html:p><![CDATA[The error is confusing (least of all because there is a typo on the OCaml]]>  <![CDATA[version number). Since then, we have]]> <fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/625" type="external">patched this issue</fr:link> and have planned to <fr:link href="https://github.com/ocaml-ppx/ppxlib/compare/main...0.35" type="external">release a patched 0.35</fr:link> in the not too distant future.</html:p>
                    <html:p>If you can bump to <html:code>ppxlib&gt;=0.36</html:code> then you will not face this issue.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2026</fr:year>
                      <fr:month>3</fr:month>
                      <fr:day>10</fr:day>
                    </fr:date>
                    <fr:title text="Modular Explicits">Modular Explicits</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>We ran into a fairly interesting corner of the OCaml language whilst trying to migrate modular explicits in <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link>. As a recap, in OCaml 5.5 you can now right function types that depend on modules. For example:</html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-keyword-other">module</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Add</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">sig</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">t</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword">val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">add</html:span><html:span class="ocaml-source"> : t -&gt; t -&gt; t
</html:span>
<html:span class="ocaml-keyword-other">end</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">add</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-keyword-other">module</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">A</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Add</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">A</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">A</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">A</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">fun</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-keyword-other">module</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">A</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Add</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">a</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">b</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">A</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">add</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">a</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">b</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                    <html:p>We have to tell the compiler the module type of <html:code>A</html:code> by adding <html:code>: Add</html:code>. However, there is another very similar syntax for these kinds of constraints, <html:code><![CDATA[(module A : module Add)]]></html:code>. And in fact, the former syntax was syntactic sugar for the latter. In OCaml 5.5, these two <fr:link href="https://github.com/ocaml/ocaml/pull/14149" type="external">were distinguished from one another</fr:link> and <html:code><![CDATA[(module A : Add)]]></html:code> is the required syntax for modular explicits. As you might imagine, this is a bit of a headache in terms of <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> 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.</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2026</fr:year>
                  <fr:month>3</fr:month>
                  <fr:day>10</fr:day>
                </fr:date>
                <fr:title text="Six Month Retrospective">Six Month Retrospective</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>This month marks the end of six months of work with <fr:link href="https://tarides.com/" type="external">Tarides</fr:link>. I wrote a small retrospective and plan for my next six months below.</html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2026</fr:year>
                      <fr:month>2</fr:month>
                      <fr:day>9</fr:day>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/fellowship-roundup/</fr:uri>
                    <fr:display-uri>fellowship-roundup</fr:display-uri>
                    <fr:route>/fellowship-roundup/</fr:route>
                    <fr:title text="Fellowship Roundup">Fellowship Roundup</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2026</fr:year>
                          <fr:month>2</fr:month>
                          <fr:day>9</fr:day>
                        </fr:date>
                        <fr:title text="Overview">Overview</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>February is the final month of my current six-month fellowship work with <fr:link href="https://tarides.com/" type="external">Tarides</fr:link>. A lot of the work can be summarised by reading the <fr:link href="/ocaml-blog/" title="Patrick's OCaml Blog" uri="https://patrick.sirref.org/ocaml-blog/" display-uri="ocaml-blog" type="local">roundups</fr:link><![CDATA[ (see]]> <fr:link href="/ocaml-roundup-october-2025/" title="OCaml Roundup: October 2025" uri="https://patrick.sirref.org/ocaml-roundup-october-2025/" display-uri="ocaml-roundup-october-2025" type="local">October</fr:link>, <fr:link href="/ocaml-roundup-november-2025/" title="OCaml Roundup: November 2025" uri="https://patrick.sirref.org/ocaml-roundup-november-2025/" display-uri="ocaml-roundup-november-2025" type="local">November</fr:link>, <fr:link href="/ocaml-roundup-december-2025/" title="OCaml Roundup: December 2025" uri="https://patrick.sirref.org/ocaml-roundup-december-2025/" display-uri="ocaml-roundup-december-2025" type="local">December</fr:link> and <fr:link href="/ocaml-roundup-january-2026/" title="OCaml Roundup: January 2026" uri="https://patrick.sirref.org/ocaml-roundup-january-2026/" display-uri="ocaml-roundup-january-2026" type="local">January</fr:link><![CDATA[). I have been writing throughout the fellowship.]]>  However, they do not quite capture all the work I have been doing.</html:p>
                        <html:p>Below, I pick individual projects and expand on them more holistically rather than pointing at individual PRs or issues.</html:p>
                        <fr:tree show-metadata="false" numbered="false">
                          <fr:frontmatter>
                            <fr:authors>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                              </fr:author>
                            </fr:authors>
                            <fr:date>
                              <fr:year>2026</fr:year>
                              <fr:month>2</fr:month>
                              <fr:day>9</fr:day>
                            </fr:date>
                            <fr:title text="Ppxlib">Ppxlib</fr:title>
                          </fr:frontmatter>
                          <fr:mainmatter>
                            <html:p>Most of my time over the past six months has been devoted to <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> maintenance. A large proportion of this time has been solo development work. <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">Ppxlib</fr:link><![CDATA[ is a cornerstone library of the OCaml ecosystem (whether people like]]>  <![CDATA[it or not).]]></html:p>
                            <html:pre><![CDATA[$ opam list --depends-on=ppxlib --recursive | wc -l
2030]]></html:pre>
                            <html:p>Moreover, it is completely invaluable to Jane Street too. Like other AST-based <![CDATA[tools (e.g. ocamlformat, merlin),]]> <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> must follow a regular release schedule to support newer compilers. During the years of multicore OCaml development, <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> 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:</html:p>
                            <html:ul>
                              <html:li>
                                <html:p>Functions are represented according to their arity.</html:p>
                              </html:li>
                              <html:li>
                                <html:p>Local module opens on types.</html:p>
                              </html:li>
                              <html:li>
                                <html:p>Effect syntax.</html:p>
                              </html:li>
                              <html:li>
                                <html:p>Modular explicits.</html:p>
                              </html:li>
                              <html:li>
                                <html:p>External types.</html:p>
                              </html:li>
                              <html:li>
                                <html:p>Locations for all parts of long identifiers.</html:p>
                              </html:li>
                              <html:li>
                                <html:p>Labeled tuples.</html:p>
                              </html:li>
                            </html:ul>
                            <html: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 <html:code>Ast_builder</html:code>/<html:code>Ast_pattern</html:code> functions for using the feature. <fr:link href="/nathanreb/" title="Nathan Rebours" uri="https://patrick.sirref.org/nathanreb/" display-uri="nathanreb" type="local">Nathan</fr:link> and I have been managing pretty well I would say, though we are not getting any technical debt work done.</html:p>
                          </fr:mainmatter>
                        </fr:tree>
                        <fr:tree show-metadata="false" numbered="false">
                          <fr:frontmatter>
                            <fr:authors>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                              </fr:author>
                            </fr:authors>
                            <fr:date>
                              <fr:year>2026</fr:year>
                              <fr:month>2</fr:month>
                              <fr:day>9</fr:day>
                            </fr:date>
                            <fr:title text="Outreachy">Outreachy</fr:title>
                          </fr:frontmatter>
                          <fr:mainmatter>
                            <html:p>As the OCaml coordinator for <fr:link href="/outreachy/" title="Outreachy" uri="https://patrick.sirref.org/outreachy/" display-uri="outreachy" type="local">Outreachy</fr:link> I have been running the latest December 2025 round. We are lucky to have <html:em>four</html:em> projects on the go!</html:p>
                            <html:ul>
                              <html:li>
                                <html:p>Thibaut Mattio is mentoring two projects: <fr:link href="https://www.outreachy.org/outreachy-december-2025-internship-cohort/communities/ocaml/#raven-create-a-monitoring-dashboard-for-deep-learn" type="external">an ML dashboard for Raven</fr:link> and <fr:link href="https://www.outreachy.org/outreachy-december-2025-internship-cohort/communities/ocaml/#create-an-oxcaml-backend-for-raven" type="external">an OxCaml backend for Raven</fr:link>.</html:p>
                              </html:li>
                              <html:li>
                                <html:p><fr:link href="https://github.com/xvw" type="external">Xvw</fr:link> is mentoring a <fr:link href="https://github.com/yocaml/" type="external">Yocaml</fr:link> <fr:link href="https://www.outreachy.org/outreachy-december-2025-internship-cohort/communities/ocaml/#improve-yocaml-error-reporting-and-data-model" type="external">project</fr:link>.</html:p>
                              </html:li>
                              <html:li>
                                <html:p>I am <fr:link href="/outreachy-ocaml-tiff/" title="Write support in OCaml TIFF library" uri="https://patrick.sirref.org/outreachy-ocaml-tiff/" display-uri="outreachy-ocaml-tiff" type="local">mentoring</fr:link> a <fr:link href="/geocaml/" title="Geocaml" uri="https://patrick.sirref.org/geocaml/" display-uri="geocaml" type="local">Geocaml</fr:link> project.</html:p>
                              </html:li>
                            </html:ul>
                          </fr:mainmatter>
                        </fr:tree>
                        <fr:tree show-metadata="false" numbered="false">
                          <fr:frontmatter>
                            <fr:authors>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                              </fr:author>
                            </fr:authors>
                            <fr:date>
                              <fr:year>2026</fr:year>
                              <fr:month>2</fr:month>
                              <fr:day>9</fr:day>
                            </fr:date>
                            <fr:title text="Eio">Eio</fr:title>
                          </fr:frontmatter>
                          <fr:mainmatter>
                            <html:p>During my work on tools like <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> I have made a few improvements to <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link> including:</html:p>
                            <html:ul>
                              <html:li>
                                <html:p><fr:link href="https://github.com/ocaml-multicore/eio/pull/821" type="external">A draft PR for incremental reading of directories</fr:link>.</html:p>
                              </html:li>
                              <html:li>
                                <html:p><fr:link href="https://github.com/ocaml-multicore/eio/pull/803" type="external">New fork actions for processes: setgid, setuid and process groups</fr:link>.</html:p>
                              </html:li>
                              <html:li>
                                <html:p><fr:link href="https://github.com/ocaml-multicore/eio/pull/823" type="external">Utility functions for overriding standard environments</fr:link>.</html:p>
                              </html:li>
                              <html:li>
                                <html:p><fr:link href="https://github.com/ocaml-multicore/eio/pull/822" type="external">Fixing documentation</fr:link>.</html:p>
                              </html:li>
                            </html:ul>
                          </fr:mainmatter>
                        </fr:tree>
                        <fr:tree show-metadata="false" numbered="false">
                          <fr:frontmatter>
                            <fr:authors>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                              </fr:author>
                            </fr:authors>
                            <fr:date>
                              <fr:year>2026</fr:year>
                              <fr:month>2</fr:month>
                              <fr:day>9</fr:day>
                            </fr:date>
                            <fr:title text="OxCaml">OxCaml</fr:title>
                          </fr:frontmatter>
                          <fr:mainmatter>
                            <html:p>I have enjoyed my work on OxCaml went it has happend. I think a few tools have been useful including the <fr:link href="/try-oxcaml/" title="Try OxCaml" uri="https://patrick.sirref.org/try-oxcaml/" display-uri="try-oxcaml" type="local">try-oxcaml</fr:link> work. <fr:link href="/dra27/" title="David Allsopp" uri="https://patrick.sirref.org/dra27/" display-uri="dra27" type="local">David</fr:link> and I also had fun at <fr:link href="/icfp-2025/" title="ICFP 2025" uri="https://patrick.sirref.org/icfp-2025/" display-uri="icfp-2025" type="local">ICFP</fr:link> discussing some quick experiments related to <fr:link href="/icfp-oxcaml-uring/" title="OCaml Roundup: October 2025 › OxCaml Experiments " uri="https://patrick.sirref.org/icfp-oxcaml-uring/" display-uri="icfp-oxcaml-uring" type="local">io_uring and OxCaml</fr:link>.</html:p>
                            <html: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 <![CDATA[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.</html:p>
                          </fr:mainmatter>
                        </fr:tree>
                        <fr:tree show-metadata="false" numbered="false">
                          <fr:frontmatter>
                            <fr:authors>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                              </fr:author>
                            </fr:authors>
                            <fr:date>
                              <fr:year>2026</fr:year>
                              <fr:month>2</fr:month>
                              <fr:day>9</fr:day>
                            </fr:date>
                            <fr:title text="Forester">Forester</fr:title>
                          </fr:frontmatter>
                          <fr:mainmatter>
                            <html:p><fr:link href="https://tarides.org/" type="external">Tarides</fr:link> are funding some work on <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">forester</fr:link>. This site uses <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">forester</fr:link> by way of <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">graft</fr:link> and I have spent some time working on these tools during the fellowship.</html:p>
                            <html:p>This includes a <html:code>bytesrw</html:code>-based <fr:link href="/bib/" title="Bib" uri="https://patrick.sirref.org/bib/" display-uri="bib" type="local">bibtex</fr:link> library in OCaml that could be released soon.</html:p>
                          </fr:mainmatter>
                        </fr:tree>
                        <fr:tree show-metadata="false" numbered="false">
                          <fr:frontmatter>
                            <fr:authors>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                              </fr:author>
                            </fr:authors>
                            <fr:date>
                              <fr:year>2026</fr:year>
                              <fr:month>2</fr:month>
                              <fr:day>9</fr:day>
                            </fr:date>
                            <fr:title text="Papers">Papers</fr:title>
                          </fr:frontmatter>
                          <fr:mainmatter>
                            <html:p>I had the great fortune of attending <fr:link href="https://patrick.sirref.org/ifcp-2025/" type="external">ICFP</fr:link> where I presented two talks and was co-author on a few others too.</html:p>
                            <html:hr />
                            <fr:tree show-metadata="false" expanded="false" numbered="false">
                              <fr:frontmatter>
                                <fr:authors>
                                  <fr:author>
                                    <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                                  </fr:author>
                                  <fr:author>
                                    <fr:link href="https://patrick.sirref.org/David J. Scott" type="external">David J. Scott</fr:link>
                                  </fr:author>
                                  <fr:author>
                                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                                  </fr:author>
                                  <fr:author>
                                    <fr:link href="https://patrick.sirref.org/Ryan T. Gibb" type="external">Ryan T. Gibb</fr:link>
                                  </fr:author>
                                  <fr:author>
                                    <fr:link href="https://patrick.sirref.org/Thomas Gazagnaire/" type="external">Thomas Gazagnaire</fr:link>
                                  </fr:author>
                                </fr:authors>
                                <fr:date>
                                  <fr:year>2025</fr:year>
                                </fr:date>
                                <fr:uri>https://patrick.sirref.org/madhavapeddy2025docker/</fr:uri>
                                <fr:display-uri>madhavapeddy2025docker</fr:display-uri>
                                <fr:route>/madhavapeddy2025docker/</fr:route>
                                <fr:title text="Functional Networking for Millions of Docker Desktops (Experience Report)">Functional Networking for Millions of Docker Desktops (Experience Report)</fr:title>
                                <fr:taxon>Reference</fr:taxon>
                                <fr:meta name="external">https://dl.acm.org/doi/10.1145/3747525</fr:meta>
                                <fr:meta name="journal">Proc. ACM Program. Lang.</fr:meta>
                                <fr:meta name="doi">10.1145/3747525</fr:meta>
                              </fr:frontmatter>
                              <fr:mainmatter>
                                <fr:tree show-metadata="false">
                                  <fr:frontmatter>
                                    <fr:authors>
                                      <fr:author>
                                        <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                                      </fr:author>
                                      <fr:author>
                                        <fr:link href="https://patrick.sirref.org/David J. Scott" type="external">David J. Scott</fr:link>
                                      </fr:author>
                                      <fr:author>
                                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                                      </fr:author>
                                      <fr:author>
                                        <fr:link href="https://patrick.sirref.org/Ryan T. Gibb" type="external">Ryan T. Gibb</fr:link>
                                      </fr:author>
                                      <fr:author>
                                        <fr:link href="https://patrick.sirref.org/Thomas Gazagnaire/" type="external">Thomas Gazagnaire</fr:link>
                                      </fr:author>
                                    </fr:authors>
                                    <fr:date>
                                      <fr:year>2025</fr:year>
                                    </fr:date>
                                    <fr:title text="Abstract">Abstract</fr:title>
                                  </fr:frontmatter>
                                  <fr:mainmatter>
                                    <html: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.
</html:p>
                                  </fr:mainmatter>
                                </fr:tree>
                              </fr:mainmatter>
                            </fr:tree>
                            <fr:tree show-metadata="false" expanded="false" numbered="false">
                              <fr:frontmatter>
                                <fr:authors>
                                  <fr:author>
                                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                                  </fr:author>
                                </fr:authors>
                                <fr:date>
                                  <fr:year>2025</fr:year>
                                </fr:date>
                                <fr:uri>https://patrick.sirref.org/ferris2025scientific_programming/</fr:uri>
                                <fr:display-uri>ferris2025scientific_programming</fr:display-uri>
                                <fr:route>/ferris2025scientific_programming/</fr:route>
                                <fr:title text="What we talk about when we talk about scientific programming">What we talk about when we talk about scientific programming</fr:title>
                                <fr:taxon>Reference</fr:taxon>
                                <fr:meta name="external">https://watch.eeg.cl.cam.ac.uk/w/aYXqXLtgQawYMjVXjSQtjx</fr:meta>
                                <fr:meta name="doi" />
                              </fr:frontmatter>
                              <fr:mainmatter>
                                <fr:tree show-metadata="false">
                                  <fr:frontmatter>
                                    <fr:authors>
                                      <fr:author>
                                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                                      </fr:author>
                                    </fr:authors>
                                    <fr:date>
                                      <fr:year>2025</fr:year>
                                    </fr:date>
                                    <fr:title text="Abstract">Abstract</fr:title>
                                  </fr:frontmatter>
                                  <fr:mainmatter>
                                    <html:p><![CDATA[	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.]]></html:p>
                                  </fr:mainmatter>
                                </fr:tree>
                              </fr:mainmatter>
                            </fr:tree>
                            <fr:tree show-metadata="false" expanded="false" numbered="false">
                              <fr:frontmatter>
                                <fr:authors>
                                  <fr:author>
                                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                                  </fr:author>
                                  <fr:author>
                                    <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                                  </fr:author>
                                </fr:authors>
                                <fr:date>
                                  <fr:year>2025</fr:year>
                                </fr:date>
                                <fr:uri>https://patrick.sirref.org/ferris2025hazel_of_ocaml/</fr:uri>
                                <fr:display-uri>ferris2025hazel_of_ocaml</fr:display-uri>
                                <fr:route>/ferris2025hazel_of_ocaml/</fr:route>
                                <fr:title text="Generating a corpus of Hazel programs from ill-typed OCaml programs">Generating a corpus of Hazel programs from ill-typed OCaml programs</fr:title>
                                <fr:taxon>Reference</fr:taxon>
                                <fr:meta name="external">https://patrick.sirref.org/var/tyde2025.pdf</fr:meta>
                                <fr:meta name="doi" />
                              </fr:frontmatter>
                              <fr:mainmatter>
                                <fr:tree show-metadata="false">
                                  <fr:frontmatter>
                                    <fr:authors>
                                      <fr:author>
                                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                                      </fr:author>
                                      <fr:author>
                                        <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                                      </fr:author>
                                    </fr:authors>
                                    <fr:date>
                                      <fr:year>2025</fr:year>
                                    </fr:date>
                                    <fr:title text="Abstract">Abstract</fr:title>
                                  </fr:frontmatter>
                                  <fr:mainmatter>
                                    <html: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.
</html:p>
                                  </fr:mainmatter>
                                </fr:tree>
                              </fr:mainmatter>
                            </fr:tree>
                            <html:p>See also <fr:link href="https://patricoferris.github.io/hazel_of_ocaml/" type="external">the online hazel of ocaml compiler</fr:link></html:p>
                            <fr:tree show-metadata="false" expanded="false" numbered="false">
                              <fr:frontmatter>
                                <fr:authors>
                                  <fr:author>
                                    <fr:link href="https://patrick.sirref.org/Max Carroll/" type="external">Max Carroll</fr:link>
                                  </fr:author>
                                  <fr:author>
                                    <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                                  </fr:author>
                                  <fr:author>
                                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                                  </fr:author>
                                </fr:authors>
                                <fr:date>
                                  <fr:year>2025</fr:year>
                                </fr:date>
                                <fr:uri>https://patrick.sirref.org/carroll2025decomposable_type_highlighting/</fr:uri>
                                <fr:display-uri>carroll2025decomposable_type_highlighting</fr:display-uri>
                                <fr:route>/carroll2025decomposable_type_highlighting/</fr:route>
                                <fr:title text="Decomposable Type Highlighting for Bidirectional Type and Cast Systems">Decomposable Type Highlighting for Bidirectional Type and Cast Systems</fr:title>
                                <fr:taxon>Reference</fr:taxon>
                                <fr:meta name="external">https://maxcarroll0.github.io/papers/workshops/HATRA-decomposable-type-highlighting/</fr:meta>
                                <fr:meta name="doi" />
                              </fr:frontmatter>
                              <fr:mainmatter>
                                <fr:tree show-metadata="false">
                                  <fr:frontmatter>
                                    <fr:authors>
                                      <fr:author>
                                        <fr:link href="https://patrick.sirref.org/Max Carroll/" type="external">Max Carroll</fr:link>
                                      </fr:author>
                                      <fr:author>
                                        <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                                      </fr:author>
                                      <fr:author>
                                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                                      </fr:author>
                                    </fr:authors>
                                    <fr:date>
                                      <fr:year>2025</fr:year>
                                    </fr:date>
                                    <fr:title text="Abstract">Abstract</fr:title>
                                  </fr:frontmatter>
                                  <fr:mainmatter>
                                    <html: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.
</html:p>
                                  </fr:mainmatter>
                                </fr:tree>
                              </fr:mainmatter>
                            </fr:tree>
                            <fr:tree show-metadata="false" expanded="false" numbered="false">
                              <fr:frontmatter>
                                <fr:authors>
                                  <fr:author>
                                    <fr:link href="https://patrick.sirref.org/Michael Winston Dales/" type="external">Michael Winston Dales</fr:link>
                                  </fr:author>
                                  <fr:author>
                                    <fr:link href="https://patrick.sirref.org/Alison Eyres/" type="external">Alison Eyres</fr:link>
                                  </fr:author>
                                  <fr:author>
                                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                                  </fr:author>
                                  <fr:author>
                                    <fr:link href="https://patrick.sirref.org/Francesca A. Ridley" type="external">Francesca A. Ridley</fr:link>
                                  </fr:author>
                                  <fr:author>
                                    <fr:link href="https://patrick.sirref.org/Simon Tarr/" type="external">Simon Tarr</fr:link>
                                  </fr:author>
                                  <fr:author>
                                    <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                                  </fr:author>
                                </fr:authors>
                                <fr:date>
                                  <fr:year>2025</fr:year>
                                </fr:date>
                                <fr:uri>https://patrick.sirref.org/dales2025yirgacheffe/</fr:uri>
                                <fr:display-uri>dales2025yirgacheffe</fr:display-uri>
                                <fr:route>/dales2025yirgacheffe/</fr:route>
                                <fr:title text="Yirgacheffe: A Declarative Approach to Geospatial Data">Yirgacheffe: A Declarative Approach to Geospatial Data</fr:title>
                                <fr:taxon>Reference</fr:taxon>
                                <fr:meta name="external">https://dl.acm.org/doi/10.1145/3759536.3763806</fr:meta>
                                <fr:meta name="doi">10.1145/3759536.3763806</fr:meta>
                              </fr:frontmatter>
                              <fr:mainmatter>
                                <fr:tree show-metadata="false">
                                  <fr:frontmatter>
                                    <fr:authors>
                                      <fr:author>
                                        <fr:link href="https://patrick.sirref.org/Michael Winston Dales/" type="external">Michael Winston Dales</fr:link>
                                      </fr:author>
                                      <fr:author>
                                        <fr:link href="https://patrick.sirref.org/Alison Eyres/" type="external">Alison Eyres</fr:link>
                                      </fr:author>
                                      <fr:author>
                                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                                      </fr:author>
                                      <fr:author>
                                        <fr:link href="https://patrick.sirref.org/Francesca A. Ridley" type="external">Francesca A. Ridley</fr:link>
                                      </fr:author>
                                      <fr:author>
                                        <fr:link href="https://patrick.sirref.org/Simon Tarr/" type="external">Simon Tarr</fr:link>
                                      </fr:author>
                                      <fr:author>
                                        <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                                      </fr:author>
                                    </fr:authors>
                                    <fr:date>
                                      <fr:year>2025</fr:year>
                                    </fr:date>
                                    <fr:title text="Abstract">Abstract</fr:title>
                                  </fr:frontmatter>
                                  <fr:mainmatter>
                                    <html:p><![CDATA[		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.]]></html:p>
                                  </fr:mainmatter>
                                </fr:tree>
                              </fr:mainmatter>
                            </fr:tree>
                            <html:hr />
                            <html:p>I had some great conversations with <fr:link href="/kc/" title="KC Sivaramakrishnan" uri="https://patrick.sirref.org/kc/" display-uri="kc" type="local">KC</fr:link> too with respect to my current research.</html:p>
                          </fr:mainmatter>
                        </fr:tree>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2026</fr:year>
                          <fr:month>2</fr:month>
                          <fr:day>9</fr:day>
                        </fr:date>
                        <fr:title text="Future Work">Future Work</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html: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:</html:p>
                        <html:blockquote>
                          <html:p>Embedding deep provenance tracking, reversible execution and mergeable <![CDATA[histories directly into an interactive programming environment (a POSIX-like]]>  <![CDATA[shell) greatly decreases the gap between exploratory scientific work and]]>  reproducible, publishable results; all whilst leaving existing workflows intact and being programming language agnostic.</html:p>
                        </html:blockquote>
                        <html:p>I want to focus on building these tools using <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link>, <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link>, <fr:link href="https://patrick.sirref.org/oxcaml/" type="external">OxCaml</fr:link> etc. There are other projects I wish to continue regardless, like <fr:link href="/outreachy/" title="Outreachy" uri="https://patrick.sirref.org/outreachy/" display-uri="outreachy" type="local">Outreachy</fr:link><![CDATA[, though just as a coordinator (not a mentor).]]></html:p>
                        <fr:tree show-metadata="false" numbered="false">
                          <fr:frontmatter>
                            <fr:authors>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                              </fr:author>
                            </fr:authors>
                            <fr:date>
                              <fr:year>2026</fr:year>
                              <fr:month>2</fr:month>
                              <fr:day>9</fr:day>
                            </fr:date>
                            <fr:title text="Overlapping PhD Work">Overlapping PhD Work</fr:title>
                          </fr:frontmatter>
                          <fr:mainmatter>
                            <html:p>There are multiple projects that overlap with my work. For example, <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link>, which I wrote a <fr:link href="/irmin-retro/" title="Irmin Retrospective" uri="https://patrick.sirref.org/irmin-retro/" display-uri="irmin-retro" type="local">retrospective</fr:link> for. This is at the core of <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> and suggests an extremely valid use case for a brancheable, mergeable database.</html:p>
                            <html:p>In addition to this, continuing to work on <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link> makes sense to me too. <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link> currently has no maintainer and no active development, but the <fr:link href="https://github.com/ocaml-multicore/eio/issues" type="external">issues are piling up</fr:link>. In particular, I am making heavy use of <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link> in <fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link><![CDATA[, 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 <fr:link href="/anilmadhavapeddy/" title="Anil Madhavapeddy" uri="https://patrick.sirref.org/anilmadhavapeddy/" display-uri="anilmadhavapeddy" type="local">Anil</fr:link> and <fr:link href="/talex5/" title="Thomas Leonard" uri="https://patrick.sirref.org/talex5/" display-uri="talex5" type="local">Thomas</fr:link> recently to discuss the future of <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link> and there was some agreement that we are all heavy users of it and hope to keep up its maintenance and set of features.</html:p>
                            <html:p>One large piece of work that is sorely needed here is moving <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link> to <html:code>bytes</html:code> and not bigarray-backed <html:code>Cstruct</html:code>s. Any libraries using <html:code>bytesrw</html:code><![CDATA[ (e.g.]]>  <html:code>jsont</html:code><![CDATA[) incur an extra copy of data into and out of the bytes.]]>  <fr:link href="/anilmadhavapeddy/" title="Anil Madhavapeddy" uri="https://patrick.sirref.org/anilmadhavapeddy/" display-uri="anilmadhavapeddy" type="local">Anil</fr:link> has been <fr:link href="https://anil.recoil.org/notes/oxcaml-httpz" type="external">working on some of the pieces</fr:link> recently to make this better!</html:p>
                          </fr:mainmatter>
                        </fr:tree>
                        <fr:tree show-metadata="false" numbered="false">
                          <fr:frontmatter>
                            <fr:authors>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                              </fr:author>
                            </fr:authors>
                            <fr:date>
                              <fr:year>2026</fr:year>
                              <fr:month>2</fr:month>
                              <fr:day>9</fr:day>
                            </fr:date>
                            <fr:title text="Maintaining and Releasing my own libraries">Maintaining and Releasing my own libraries</fr:title>
                          </fr:frontmatter>
                          <fr:mainmatter>
                            <html:p>I have published quite a few OCaml libraries in my time, below is just a few <![CDATA[libraries (filtered to not include OCurrent projects).]]></html:p>
                            <html: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]]></html:pre>
                            <html:p>Some of these are used in the community including <html:code>hilite</html:code>, <html:code>ppx_deriving_yaml</html:code> and the multi-codecs. I would like to do some general maintenance of some of these tools and release a few iterations of <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">graft</fr:link> which now makes use of <fr:link href="/bib/" title="Bib" uri="https://patrick.sirref.org/bib/" display-uri="bib" type="local">bib</fr:link>.</html:p>
                          </fr:mainmatter>
                        </fr:tree>
                        <fr:tree show-metadata="false" numbered="false">
                          <fr:frontmatter>
                            <fr:authors>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                              </fr:author>
                            </fr:authors>
                            <fr:date>
                              <fr:year>2026</fr:year>
                              <fr:month>2</fr:month>
                              <fr:day>9</fr:day>
                            </fr:date>
                            <fr:title text="Ppxlib Maintenance">Ppxlib Maintenance</fr:title>
                          </fr:frontmatter>
                          <fr:mainmatter>
                            <html:p>By far, maintenance of <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> 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 <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link>. In particular, perhaps only maintaining <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> as far as OCaml release-readiness is a possibility and <![CDATA[important bug fixes (like]]> <fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/613" type="external">the OOM bug reported by Jane Street</fr:link><![CDATA[).]]></html:p>
                          </fr:mainmatter>
                        </fr:tree>
                        <fr:tree show-metadata="false" numbered="false">
                          <fr:frontmatter>
                            <fr:authors>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                              </fr:author>
                            </fr:authors>
                            <fr:date>
                              <fr:year>2026</fr:year>
                              <fr:month>2</fr:month>
                              <fr:day>9</fr:day>
                            </fr:date>
                            <fr:title text="Forester, Graft and Writing">Forester, Graft and Writing</fr:title>
                          </fr:frontmatter>
                          <fr:mainmatter>
                            <html: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 <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link> <![CDATA[to do this, particularly as it is written in OCaml (and could make great use of]]>  my own work on <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link><![CDATA[).]]></html:p>
                            <html:p>I hope to continue working on <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">Graft</fr:link> and related tools like <fr:link href="/bib/" title="Bib" uri="https://patrick.sirref.org/bib/" display-uri="bib" type="local">bib</fr:link>. But I would also like to start writing some long-form content similar to the <fr:link href="/irmin-retro/" title="Irmin Retrospective" uri="https://patrick.sirref.org/irmin-retro/" display-uri="irmin-retro" type="local">Irmin retrospective</fr:link>.</html:p>
                          </fr:mainmatter>
                        </fr:tree>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2026</fr:year>
              <fr:month>2</fr:month>
              <fr:day>5</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/ocaml-roundup-january-2026/</fr:uri>
            <fr:display-uri>ocaml-roundup-january-2026</fr:display-uri>
            <fr:route>/ocaml-roundup-january-2026/</fr:route>
            <fr:title text="OCaml Roundup: January 2026">OCaml Roundup: January 2026</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>A new year, another roundup in my open-source, OCaml activities. This month has been busy with lots of work on <fr:link href="/ocaml-tiff/" title="ocaml-tiff" uri="https://patrick.sirref.org/ocaml-tiff/" display-uri="ocaml-tiff" type="local">ocaml-tiff</fr:link> thanks to <fr:link href="https://patrick.sirref.org/tambe salome/" type="external">Tambe Salome</fr:link> and <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link>.</html:p>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2026</fr:year>
                  <fr:month>2</fr:month>
                  <fr:day>5</fr:day>
                </fr:date>
                <fr:title text="Outreachy">Outreachy</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><fr:link href="https://patrick.sirref.org/tambe salome/" type="external">Tambe Salome</fr:link> has been working to add write support to <fr:link href="/ocaml-tiff/" title="ocaml-tiff" uri="https://patrick.sirref.org/ocaml-tiff/" display-uri="ocaml-tiff" type="local">ocaml-tiff</fr:link>; 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 <html:em>write</html:em> the file, you might need to write at different offsets too.</html:p>
                <html:p>This becomes particularly complicated when you do not know ahead of time how <![CDATA[you are going to layout the file (e.g. how many strips will the raw data be]]>  <![CDATA[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 <fr:link href="/tambe-salome/" title="Tambe Salome" uri="https://patrick.sirref.org/tambe-salome/" display-uri="tambe-salome" type="local">Salome</fr:link> has made excellent progress:</html:p>
                <html: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]]></html:pre>
                <html: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.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2026</fr:year>
                  <fr:month>2</fr:month>
                  <fr:day>5</fr:day>
                </fr:date>
                <fr:title text="Ppxlib">Ppxlib</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>The first cut of <fr:link href="https://patrick.sirref.org/ocaml 5.5" type="external">OCaml 5.5</fr:link> is not too far away, at which point the <![CDATA[Parsetree will be frozen. Unfortunately (for]]> <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link><![CDATA[ maintainers), a handful]]>  of new features sneaked into this release including: modular explicits, external type declarations and the <fr:link href="/ocaml-roundup-december-2025/" title="OCaml Roundup: December 2025" uri="https://patrick.sirref.org/ocaml-roundup-december-2025/" display-uri="ocaml-roundup-december-2025" type="local">previously mentioned</fr:link> local structure items.</html:p>
                <html:p>All of these features require migrations to support newer compilers. In this migration process, <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> lowers modern ASTs to the AST of OCaml 5.2. New <![CDATA[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:</html:p>
                <html:ul>
                  <html:li>
                    <html:p><fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/606" type="external">The initial PR to support 5.5</fr:link>.</html:p>
                  </html:li>
                  <html:li>
                    <html:p><fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/621" type="external">Supporting all the new local structure items</fr:link>.</html:p>
                  </html:li>
                  <html:li>
                    <html:p><fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/622" type="external">Full support for modular explicits and external type declarations</fr:link>.</html:p>
                  </html:li>
                </html:ul>
                <html:p>Additionally, <fr:link href="/nathanreb/" title="Nathan Rebours" uri="https://patrick.sirref.org/nathanreb/" display-uri="nathanreb" type="local">Nathan</fr:link> has been adding better feature encoding support for the 5.3 and 5.4. Unlike the migration code above, these also include <html:code>Ast_builder</html:code> and <html:code>Ast_pattern</html:code> functions for building and matching on the new AST nodes. This allows ppx authors to <html:em>use</html:em> those nodes in their ppxes.</html:p>
                <html:ul>
                  <html:li>
                    <html:p><fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/624" type="external">OCaml 5.3 effect syntax</fr:link>.</html:p>
                  </html:li>
                  <html:li>
                    <html:p><fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/607" type="external">OCaml 5.4 labeled tuples</fr:link>.</html:p>
                  </html:li>
                </html:ul>
                <html:p>Finally, we have an important bug fix where long identifiers were given a <html:code>Location.none</html:code>. Unfortunately, it is not possible to fully recover a long <![CDATA[identifier's location because of the possibility of whitespaces (e.g.]]> <html:code><![CDATA[Foo (M).t]]></html:code><![CDATA[ is valid).]]> <fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/619" type="external">Read more about that fix here</fr:link>.</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2026</fr:year>
              <fr:month>1</fr:month>
              <fr:day>11</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/ocaml-roundup-december-2025/</fr:uri>
            <fr:display-uri>ocaml-roundup-december-2025</fr:display-uri>
            <fr:route>/ocaml-roundup-december-2025/</fr:route>
            <fr:title text="OCaml Roundup: December 2025">OCaml Roundup: December 2025</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>December was busy, both personally and in my OCaml-related work. If you haven't been following along have a read of my <fr:link href="/ocaml-roundup-october-2025/" title="OCaml Roundup: October 2025" uri="https://patrick.sirref.org/ocaml-roundup-october-2025/" display-uri="ocaml-roundup-october-2025" type="local">October</fr:link> and <fr:link href="/ocaml-roundup-november-2025/" title="OCaml Roundup: November 2025" uri="https://patrick.sirref.org/ocaml-roundup-november-2025/" display-uri="ocaml-roundup-november-2025" type="local">November</fr:link> roundups.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2026</fr:year>
                  <fr:month>1</fr:month>
                  <fr:day>11</fr:day>
                </fr:date>
                <fr:uri>https://patrick.sirref.org/outreachy-december-round/</fr:uri>
                <fr:display-uri>outreachy-december-round</fr:display-uri>
                <fr:route>/outreachy-december-round/</fr:route>
                <fr:title text="Outreachy December Round ">Outreachy December Round </fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>December marks the beginning of a new <fr:link href="/outreachy/" title="Outreachy" uri="https://patrick.sirref.org/outreachy/" display-uri="outreachy" type="local">Outreachy</fr:link> round, and I am very excited to be working with <fr:link href="/tambe-salome/" title="Tambe Salome" uri="https://patrick.sirref.org/tambe-salome/" display-uri="tambe-salome" type="local">Tambe Salome</fr:link> on improving the <fr:link href="/ocaml-tiff/" title="ocaml-tiff" uri="https://patrick.sirref.org/ocaml-tiff/" display-uri="ocaml-tiff" type="local">ocaml-tiff</fr:link> library.</html:p>
                <html:p>In particular, we will be adding the ability to <html:em>write</html:em> TIFF files from raw data. I imagine an API something like:</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword-other">val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">write</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-storage-type">'repr</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-storage-type">'kind</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Tiff</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Data</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-constant-language-capital-identifier">Tiff</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">File</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">wo</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-support-type">unit</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html:p>So far <fr:link href="/tambe-salome/" title="Tambe Salome" uri="https://patrick.sirref.org/tambe-salome/" display-uri="tambe-salome" type="local">Salome</fr:link> has been making excellent progress churning through some issues that are blocking us from starting the main project, including:</html:p>
                <html:ol>
                  <html:li>
                    <html:p><fr:link href="https://github.com/geocaml/ocaml-tiff/pull/56" type="external">Adding a sublibrary</fr:link> for <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link>.</html:p>
                  </html:li>
                  <html:li>
                    <html:p><fr:link href="https://github.com/geocaml/ocaml-tiff/pull/57" type="external">Using the new Nx library</fr:link>.</html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="https://github.com/geocaml/ocaml-tiff/pull/58" type="external">Uncovering bugs in our decoding of the number of bits per pixel</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p><fr:link href="https://github.com/geocaml/ocaml-tiff/pull/59" type="external">Preliminary work on write support</fr:link>!</html:p>
                  </html:li>
                </html:ol>
                <html:p>As a community, the mentors and mentees also had a community call to introduce ourselves to eachother. I am very excited about the <fr:link href="https://yocaml.github.io/tutorial/" type="external">Yocaml</fr:link> project and the <html:em>two</html:em> <fr:link href="https://raven-ml.dev/" type="external">Raven</fr:link> projects.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2026</fr:year>
                  <fr:month>1</fr:month>
                  <fr:day>11</fr:day>
                </fr:date>
                <fr:title text="Ppxlib">Ppxlib</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>If you recall, I discussed the new representation for local constructs in the AST.</html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>12</fr:month>
                      <fr:day>9</fr:day>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/ppxlib-5.5-support</fr:uri>
                    <fr:display-uri>ppxlib-5.5-support</fr:display-uri>
                    <fr:route>/ppxlib-5.5-support</fr:route>
                    <fr:title text="Initial OCaml 5.5 Support ">Initial OCaml 5.5 Support </fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>We <fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/606" type="external">recently merged 5.5 support</fr:link> into our <html:code>main</html:code><![CDATA[ branch (thanks to Nathan for the review). It cast a light on]]>  some new features coming to OCaml including the ability to define <html:em>any</html:em> structure <html:em>locally</html:em>. Most OCaml programmers will be familiar with things like <![CDATA[local opens (e.g.]]> <html:code>let open M in</html:code><![CDATA[). This has now been extended to include any]]>  <![CDATA[structure item (more or less, you cannot nest value bindings).]]></html:p>
                    <html:p><html:em>External</html:em> types have also landed, bringing with them a new "type kind" in the AST. You can <fr:link href="https://github.com/gasche/ocaml/blob/44e69a0eb6d57ea2e7dc14c6ea4bac4a260a2d5b/manual/src/refman/extensions/externaltypes.etex" type="external">read about them in the manual</fr:link>.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <html:p>It transpires that since then, changes have landed in the compiler that mean just about <html:em>any</html:em> OCaml structure item can now be declared locally. I have documented an <fr:link href="https://github.com/ocaml-ppx/ppxlib/issues/617" type="external">issue on ppxlib</fr:link> about the problems this will cause for us:</html:p>
                <html:blockquote>
                  <html:p>Currently, we only migrate the previously supported structure items that <![CDATA[could appear in a let-binding (]]> <html:code>let open</html:code><![CDATA[ etc.). Now, however, the compiler]]>  allows anything to appear in a local let-binding except additional <![CDATA[let-bindings (]]> <html:code>let let ...</html:code><![CDATA[) and includes (]]> <html:code>let include</html:code><![CDATA[). 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.</html:p>
                </html:blockquote>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2026</fr:year>
                      <fr:month>1</fr:month>
                      <fr:day>11</fr:day>
                    </fr:date>
                    <fr:title text="Migration Woes">Migration Woes</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p><![CDATA[We had more migration woes in the form of incorrect (or missing) locations for]]>  <![CDATA[long identifiers (thanks to]]> <fr:link href="https://github.com/ocaml-ppx/ppxlib/issues/618" type="external">gasche for the report</fr:link><![CDATA[). Long identifiers, or]]>  <html:code>Longident</html:code>s are used in OCaml to identify values like <html:code>Foo.bar</html:code> or <html:code><![CDATA[Map.Make(String).t]]></html: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.</html:p>
                    <html:p>However, our code didn't do this, instead it simply defaulted to <html:code>Location.none</html:code> causing some imprecise error codes in preprocessed OCaml files. For example:</html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-keyword-other">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-unit"><![CDATA[()]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">NonExistingModule</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">run</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-unit"><![CDATA[()]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                    <html:p>Has the following error:</html:p>
                    <html:pre><![CDATA[File "_none_", line 1:              
Error: Unbound module NonExistingModule]]></html:pre>
                    <html:p>I have <fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/619" type="external">proposed a fix</fr:link> which partially brings back locations during the migration. Part of the problem, I think, is that the exact location of long identifiers containing applications <![CDATA[(like]]> <html:code><![CDATA[Map.Make(String).t]]></html:code><![CDATA[) is lost. This is because there could be arbitrary]]>  <![CDATA[white-space in the original source code (e.g.]]> <html:code><![CDATA[Map.Make    (String).t]]></html:code><![CDATA[)]]></html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>12</fr:month>
              <fr:day>9</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/ocaml-roundup-november-2025/</fr:uri>
            <fr:display-uri>ocaml-roundup-november-2025</fr:display-uri>
            <fr:route>/ocaml-roundup-november-2025/</fr:route>
            <fr:title text="OCaml Roundup: November 2025">OCaml Roundup: November 2025</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>A roundup of <html:em>some</html:em> of my OCaml activity this month!</html:p>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>12</fr:month>
                  <fr:day>9</fr:day>
                </fr:date>
                <fr:title text="Ppxlib Updates">Ppxlib Updates</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html: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.</html:p>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>12</fr:month>
                      <fr:day>9</fr:day>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/ppxlib-5.5-support</fr:uri>
                    <fr:display-uri>ppxlib-5.5-support</fr:display-uri>
                    <fr:route>/ppxlib-5.5-support</fr:route>
                    <fr:title text="Initial OCaml 5.5 Support ">Initial OCaml 5.5 Support </fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>We <fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/606" type="external">recently merged 5.5 support</fr:link> into our <html:code>main</html:code><![CDATA[ branch (thanks to Nathan for the review). It cast a light on]]>  some new features coming to OCaml including the ability to define <html:em>any</html:em> structure <html:em>locally</html:em>. Most OCaml programmers will be familiar with things like <![CDATA[local opens (e.g.]]> <html:code>let open M in</html:code><![CDATA[). This has now been extended to include any]]>  <![CDATA[structure item (more or less, you cannot nest value bindings).]]></html:p>
                    <html:p><html:em>External</html:em> types have also landed, bringing with them a new "type kind" in the AST. You can <fr:link href="https://github.com/gasche/ocaml/blob/44e69a0eb6d57ea2e7dc14c6ea4bac4a260a2d5b/manual/src/refman/extensions/externaltypes.etex" type="external">read about them in the manual</fr:link>.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>12</fr:month>
                      <fr:day>9</fr:day>
                    </fr:date>
                    <fr:title text="Bug Fixes for Attribute Rewriters">Bug Fixes for Attribute Rewriters</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>There <fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/613" type="external">was a bug</fr:link> in the error handling for attribute rewriters -- a relatively new feature to have been added to ppxlib.</html:p>
                    <html:p>In some places, ppxlib makes use of a <html:code>With_error.t</html:code> monad. Unlike the <html:code>Result.t</html:code> monad, <html:code>With_error.t</html:code> allows you to <html:em>collect</html: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.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>12</fr:month>
                      <fr:day>9</fr:day>
                    </fr:date>
                    <fr:title text="Value binding constraints in ppxlib">Value binding constraints in ppxlib</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>I spent a good few hours understanding why the <fr:link href="https://github.com/mirage/repr/pull/110" type="external">CI tests in my PR to mirage/repr</fr:link> were still failing. It turns out, the bug, is fairly simple to reproduce. Consider the following OCaml code:</html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">g</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">int</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">1</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                    <html: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.</html:p>
                    <html:p>The first is using the <html:code>Ppat_constraint</html:code> AST node which allows you to attach a type constraint to any pattern.</html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Ppat_constraint</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">of</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pattern</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">*</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">core_type</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-comment-block"><![CDATA[(*]]> </html:span><html:span class="ocaml-comment-block"><![CDATA[ (P : T)]]> </html:span><html:span class="ocaml-comment-block"><![CDATA[*)]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                    <html:p><![CDATA[This tends to be used for things like function arguments (e.g.]]> <html:code><![CDATA[fun (x : int) -> x + 1]]></html:code><![CDATA[).]]>  So it doesn't quite capture what we want for this binding constraint.</html:p>
                    <html:p>On older OCaml compilers, <html:code>let g : int = 1</html:code> also includes a <html:code>Pexp_constraint</html: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.</html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">g</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">x</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">int</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">x</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">+</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">1</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                    <html:p>In this example, we no longer parse a <html:code>Ppat_constraint</html:code> and instead this is treated as syntactic sugar for:</html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">g</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">x</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">x</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">+</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">int</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                    <html:p>In <fr:link href="https://github.com/ocaml/ocaml/pull/12119" type="external">OCaml 5.1 a new field for value bindings was added</fr:link> allowing type constraints to be tracked directly in the bindings themselves.</html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-keyword-other">and</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">value_binding</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source">pvb_pat</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pattern</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source">pvb_expr</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">expression</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source">pvb_constraint</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">poly_constraint</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">option</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source">pvb_attributes</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">attributes</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source">pvb_loc</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Location</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-comment-doc"><![CDATA[(**]]> </html:span><html:span class="ocaml-comment-doc"><![CDATA[ [let pat : type_constraint = exp]]]> </html:span><html:span class="ocaml-comment-doc"><![CDATA[*)]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                    <html:p><![CDATA[Our type constraint (]]> <html:code>: int</html:code><![CDATA[) can be recorded in the]]> <html:code>pvb_constraint</html: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 <html:em>before</html:em> 5.1!</html:p>
                    <html:p>So what was the bug? The author's of <html:code>repr</html:code> had added some value bindings to circumvent some "unused value warnings" in OCaml. They choose to write these bindings like:</html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-keyword-other">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language">_</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">int</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">1</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                    <html: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 <html:em>forces</html:em> the AST representation to be a single <html:code>Ppat_constraint</html:code> node regardless of the current compiler version. No <html:code>Pexp_constraint</html:code> and no <html:code>pvb_constraint</html:code>.</html:p>
                    <html:p>However, using ppxlib with a compiler less than 5.1 meant that this did not roundtrip cleanly. Instead, the value <html:em>after</html:em> passing through ppxlib's migrations was:</html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">_</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">int</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">1</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                    <html:p>After bottoming out at the issue, I discovered we <fr:link href="https://github.com/ocaml-ppx/ppxlib/blob/22778658345fce526e6146da188cdc2d6d2e5286/test/501_migrations/reverse_migrations.t#L142" type="external">already had a test case for this in ppxlib</fr:link>! Whatsomore, <html:code>ocamlformat.0.20.0</html:code><![CDATA[ (which]]> <html:code>repr</html:code><![CDATA[ was still using) actually]]>  transforms instances of <html:code>let x : t = ...</html:code> into <html:code><![CDATA[let (x : t) = ...]]></html:code>! This limitation does not seem inherent to the parsetree, the printer or the migrations. But I have <![CDATA[asked the (very kind and friendly) previous maintainers about these changes.]]></html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>12</fr:month>
                  <fr:day>9</fr:day>
                </fr:date>
                <fr:title text="Outreachy">Outreachy</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>December 8th 2025 marks the start of the next round of Outreachy. I have been preparing some issues for <fr:link href="https://github.com/geocaml/ocaml-tiff" type="external">geocaml/ocaml-tiff</fr:link> and I am excited to get started with <fr:link href="https://github.com/giftcup" type="external">Tambe Salome</fr:link>!</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>12</fr:month>
                  <fr:day>9</fr:day>
                </fr:date>
                <fr:uri>https://patrick.sirref.org/graft-and-bib-update/</fr:uri>
                <fr:display-uri>graft-and-bib-update</fr:display-uri>
                <fr:route>/graft-and-bib-update/</fr:route>
                <fr:title text="Graft and Bib ">Graft and Bib </fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I spent some time at the start of the month updating and fixing <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">Graft</fr:link> and <fr:link href="/bib/" title="Bib" uri="https://patrick.sirref.org/bib/" display-uri="bib" type="local">Bib</fr:link>.</html:p>
                <html:p>I added <fr:link href="https://graft.sirref.org/named-subtrees" type="external">named subtrees</fr:link> to the markdown syntax. This allows users to create subtrees with headings that are also externally linkable.</html:p>
                <html:p>With some more bug fixing, I hope to release both libraries before the new year!</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>11</fr:month>
              <fr:day>5</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/ocaml-roundup-october-2025/</fr:uri>
            <fr:display-uri>ocaml-roundup-october-2025</fr:display-uri>
            <fr:route>/ocaml-roundup-october-2025/</fr:route>
            <fr:title text="OCaml Roundup: October 2025">OCaml Roundup: October 2025</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html: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 <fr:link href="/icfp-2025/" title="ICFP 2025" uri="https://patrick.sirref.org/icfp-2025/" display-uri="icfp-2025" type="local">my ICFP roundup</fr:link> might be a good preface to what follows.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>11</fr:month>
                  <fr:day>5</fr:day>
                </fr:date>
                <fr:title text="Outreachy December 2025">Outreachy December 2025</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>The contribution period for this year's <fr:link href="/outreachy/" title="Outreachy" uri="https://patrick.sirref.org/outreachy/" display-uri="outreachy" type="local">Outreachy</fr:link> round took place for most of the month of October. This year I am excited to be going back to a <fr:link href="/geocaml/" title="Geocaml" uri="https://patrick.sirref.org/geocaml/" display-uri="geocaml" type="local">Geocaml</fr:link> project, working primarily to add writing capabilities to <fr:link href="https://github.com/geocaml/ocaml-tiff" type="external">ocaml-tiff</fr:link>.</html:p>
                <html:p>As per usual, I have been extremely pleased with the level of interest in the various <fr:link href="https://www.outreachy.org/apply/project-selection/#ocaml" type="external">OCaml projects being offered</fr:link>. 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.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>11</fr:month>
                  <fr:day>5</fr:day>
                </fr:date>
                <fr:title text="Ppxlib and the Future of Compiler Support">Ppxlib and the Future of Compiler Support</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><fr:link href="/nathanreb/" title="Nathan Rebours" uri="https://patrick.sirref.org/nathanreb/" display-uri="nathanreb" type="local">Nathan</fr:link> has put a tremendous amount of effort into laying a roadmap this month for <fr:link href="https://discuss.ocaml.org/t/ann-ppxlib-support-for-future-compilers/17430" type="external">how ppxlib, going forward, will support future compilers</fr:link>. This is in response to the calamity that was <fr:link href="/ppxlib-5-2/" title="Bumping Ppxlib's AST to 5.2" uri="https://patrick.sirref.org/ppxlib-5-2/" display-uri="ppxlib-5-2" type="local">bumping the internal AST to 5.2</fr:link>, 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.</html:p>
                <html:p>The first <fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/607" type="external">substantial PR</fr:link> for this modern world of ppxlib is in review!</html:p>
                <html:p>Aside from that I also debugged an issue that lead to <fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/604" type="external">ppxlib OOM-ing</fr:link> 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 <fr:link href="https://blog.janestreet.com/finding-memory-leaks-with-memtrace/" type="external">memtrace</fr:link> to be able to hunt it down:</html:p>
                <html:img src="/bafkrmignyxory52fgqvdsqxqcd6dfifpiqrerqwcl6lbdy3gbj4ck46zee.png" />
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>11</fr:month>
                  <fr:day>5</fr:day>
                </fr:date>
                <fr:title text="Incremental Directory Reading for Eio">Incremental Directory Reading for Eio</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html: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 <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">Graft</fr:link> and <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link> both do! A standard approach to this involves a recursive dance of <html:code>readdir</html:code> and <html:code>stat</html:code>, the former lists the entries in a directory whilst the latter lets you know what kind of file is at a particular path <![CDATA[(e.g. symbolic link, directory etc.). This has a few downsides:]]></html:p>
                <html:ol>
                  <html:li>
                    <html:p>We're making <html:strong>two</html:strong><![CDATA[ systems calls (pretty much one of the most expensive things your program can do).]]></html:p>
                  </html:li>
                  <html:li>
                    <html:p>If a directory contains thousands of files, we end up allocating a big list of strings after returning from <html:code>readdir</html:code>.</html:p>
                  </html:li>
                </html:ol>
                <html:p>On Linux, we can get around most of that with <fr:link href="https://linux.die.net/man/2/getdents64" type="external"><![CDATA[getdents64(2)]]> </fr:link> which allows us to <html:em>incrementally</html:em> read a directory. Whatsomore, this system call also returns the file type so there's no need to do an extra <html:code>stat</html:code>!</html:p>
                <html:p>I prototyped <fr:link href="https://github.com/ocaml-multicore/eio/pull/821" type="external">an implementation</fr:link> of this called <html:code>Eio.Path.walk</html:code> which looks like:</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword-other">val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">walk</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language">_</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">File</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Stat</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">kind</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">*</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">string</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Seq</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-storage-type">'a</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-storage-type">'a</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-comment-doc"><![CDATA[(**]]> </html:span><html:span class="ocaml-comment-doc"><![CDATA[ [walk t] traverses the directory [t] producing a sequence of results.]]> </html:span><html:span class="ocaml-comment-doc"><![CDATA[*)]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html: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 <html:code>1.46s</html:code> to <html:code>110ms</html:code>. I have since rejigged the implementation to automatically <![CDATA[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.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>11</fr:month>
                  <fr:day>5</fr:day>
                </fr:date>
                <fr:uri>https://patrick.sirref.org/icfp-oxcaml-uring/</fr:uri>
                <fr:display-uri>icfp-oxcaml-uring</fr:display-uri>
                <fr:route>/icfp-oxcaml-uring/</fr:route>
                <fr:title text="OxCaml Experiments ">OxCaml Experiments </fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I have included here a transclusion from my <fr:link href="/icfp-2025/" title="ICFP 2025" uri="https://patrick.sirref.org/icfp-2025/" display-uri="icfp-2025" type="local">ICFP</fr:link> post about an experiment using unboxed 32-bit integers in OCaml's Uring library.</html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:uri>https://patrick.sirref.org/oxcaml-and-uring/</fr:uri>
                    <fr:display-uri>oxcaml-and-uring</fr:display-uri>
                    <fr:route>/oxcaml-and-uring/</fr:route>
                    <fr:title text="OxCaml and Uring">OxCaml and Uring</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Jane Street were a big presence at ICFP 2025, carting along with them a shiny new OCaml compiler: <fr:link href="https://oxcaml.org/" type="external">OxCaml</fr:link>. If have been <fr:link href="/try-oxcaml/" title="Try OxCaml" uri="https://patrick.sirref.org/try-oxcaml/" display-uri="try-oxcaml" type="local">playing around with OxCaml recently</fr:link> but nothing outside toplevels in Javascript. Until now!</html:p>
                    <html:p>After talking to <fr:link href="/dra27/" title="David Allsopp" uri="https://patrick.sirref.org/dra27/" display-uri="dra27" type="local">David</fr:link>, I spent some time converting a small corner of the <fr:link href="https://github.com/ocaml-multicore/ocaml-uring" type="external">ocaml-uring</fr:link> library to use a part of <fr:link href="https://patrick.sirref.org/oxcaml/" type="external">OxCaml</fr:link>. In particular making the following change:</html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">module</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Heap</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">struct</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword-other">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">ptr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">int32</html:span><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-comment-block"><![CDATA[(*]]> </html:span><html:span class="ocaml-comment-block"> ... </html:span><html:span class="ocaml-comment-block"><![CDATA[*)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">end</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">cqe</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source">user_data_id</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Heap</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">ptr</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source">res</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">int32</html:span><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                    <html:p><![CDATA[The idea being that a completion queue entry (a notification that some]]>  <![CDATA[operation has completed) could be fully represented using 64 bits (two 32-bit,]]>  <fr:link href="https://oxcaml.org/documentation/unboxed-types/01-intro/" type="external">unboxed values</fr:link><![CDATA[).]]>  You can <fr:link href="https://github.com/ocaml-multicore/ocaml-uring/compare/main...patricoferris:ocaml-uring:oxcaml?expand=1" type="external">see how this impacted the library</fr:link>! <![CDATA[I'm not certain about this change (and I'm sure I did it wrong) but it was nice]]>  to realise <fr:link href="https://patrick.sirref.org/oxcaml/" type="external">OxCaml</fr:link> gives you this kind of control. However, I am worried about the ergonomics of manipulating values like <html:code>int32#</html:code> and the temptation to case it into an <html:code>int</html:code><![CDATA[ (presumably losing a good portion of the value of having]]>  <![CDATA[an unboxed value in the first place).]]></html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>11</fr:month>
                      <fr:day>5</fr:day>
                    </fr:date>
                    <fr:title text="x-ocaml with OxCaml">x-ocaml with OxCaml</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>I sent <fr:link href="https://github.com/oxcaml/opam-repository/pull/19" type="external">a few PRs</fr:link> 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.</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>11</fr:month>
                  <fr:day>5</fr:day>
                </fr:date>
                <fr:title text="Geospatial OCaml">Geospatial OCaml</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>In addition to the <fr:link href="/outreachy/" title="Outreachy" uri="https://patrick.sirref.org/outreachy/" display-uri="outreachy" type="local">Outreachy</fr:link> work I mentioned above, I also found the time to keep the <fr:link href="/geocaml/" title="Geocaml" uri="https://patrick.sirref.org/geocaml/" display-uri="geocaml" type="local">Geocaml</fr:link> project ticking along. A few projects saw some much-needed love including:</html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>11</fr:month>
                      <fr:day>5</fr:day>
                    </fr:date>
                    <fr:title text="PROJ in OCaml">PROJ in OCaml</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>A <fr:link href="https://github.com/geocaml/ocaml-proj" type="external">modernisation of the bindings</fr:link> to <fr:link href="https://proj.org/en/stable/" type="external">PROJ</fr:link>. 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 <fr:link href="https://github.com/geocaml/ocaml-geojson" type="external">GeoJSON</fr:link>, the <![CDATA[geospatial data will normally have some coordinate reference system (CRS) with]]>  it detailing exactly what the numbers that tell you <html:em>where</html:em> something is mean. One of the most common being <fr:link href="https://en.wikipedia.org/wiki/World_Geodetic_System" type="external">WGS84</fr:link><![CDATA[ (used by GPS and]]>  <![CDATA[GeoJSON for example). Each CRS has its benefits and drawbacks, and often you]]>  will need to convert between them. That is what PROJ does.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>11</fr:month>
                      <fr:day>5</fr:day>
                    </fr:date>
                    <fr:title text="WKT in OCaml">WKT in OCaml</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p><![CDATA[Well-known Text (WKT) is a very simple encoding of geospatial objects and CRSs.]]>  For example, a polygon might look like:</html:p>
                    <html:pre><![CDATA[Polygon ((10 10, 10 20, 20 20, 20 15, 10 10))]]></html:pre>
                    <html:p>I used <fr:link href="https://ocaml.org/p/bytesrw" type="external">bytesrw</fr:link> to build a <fr:link href="https://github.com/geocaml/ocaml-wkt" type="external">simple codec for the WKT format</fr:link>. It is probably about time to write the basic geospatial object library too, something similar to <fr:link href="https://github.com/georust/geo" type="external">Rust's geo</fr:link> library.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>11</fr:month>
                      <fr:day>5</fr:day>
                    </fr:date>
                    <fr:title text="Geotessera">Geotessera</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>A lot of people in <fr:link href="https://www.cst.cam.ac.uk/research/eeg" type="external">my group</fr:link> are excited about <fr:link href="/tessera2025/" title="TESSERA: Temporal Embeddings of Surface Spectra for Earth Representation and Analysis" uri="https://patrick.sirref.org/tessera2025/" display-uri="tessera2025" type="local">Tessera</fr:link>. They have made it easy to used the Tessera embeddings via a python library called <fr:link href="https://github.com/ucam-eo/geotessera" type="external">geotessera</fr:link>. In true OCaml-at-heart spirit, I tried my hand at <fr:link href="https://tangled.org/@patrick.sirref.org/ocaml-geotessera" type="external">porting this library</fr:link>. I had a good deal of success, converting the data into <fr:link href="https://ocaml.org/p/nx" type="external">Nx array</fr:link>, extracting the CRS and transform out of the GeoTIFF landmasks using <fr:link href="https://github.com/geocaml/ocaml-tiff" type="external">ocaml-tiff</fr:link>, reading datasets using <fr:link href="https://github.com/geocaml/ocaml-geojson" type="external">ocaml-geojson</fr:link> etc. This made me excited but also keen to improve the APIs of most of these libraries too.</html:p>
                    <html:p>I feel <fr:link href="/geocaml/" title="Geocaml" uri="https://patrick.sirref.org/geocaml/" display-uri="geocaml" type="local">geocaml</fr:link> 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!</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>9</fr:month>
              <fr:day>2</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/ocaml-weekly-2025-w32-w35/</fr:uri>
            <fr:display-uri>ocaml-weekly-2025-w32-w35</fr:display-uri>
            <fr:route>/ocaml-weekly-2025-w32-w35/</fr:route>
            <fr:title text="OCaml Weekly 2025 w32 to w35">OCaml Weekly 2025 w32 to w35</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html: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 <fr:link href="/weeklies/" title="Patrick Ferris' Weeklies" uri="https://patrick.sirref.org/weeklies/" display-uri="weeklies" type="local">weeklies</fr:link> and <fr:link href="/posts/" title="Posts" uri="https://patrick.sirref.org/posts/" display-uri="posts" type="local">posts</fr:link> a little tricky. Nevertheless, here are some of the things I have been thinking about and working on!</html:p>
            <html:p>I managed to publish one signficant post this month: a <fr:link href="/irmin-retro/" title="Irmin Retrospective" uri="https://patrick.sirref.org/irmin-retro/" display-uri="irmin-retro" type="local">retrospective on Irmin</fr:link>.</html:p>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>9</fr:month>
                  <fr:day>2</fr:day>
                </fr:date>
                <fr:title text="Eio">Eio</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html: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 <fr:link href="https://github.com/geocaml/ocaml-tiff/blob/0dd98659642d1d9741068bb1eb943b4edeb5b5d6/src/tiff.ml#L2" type="external">providing read functions</fr:link> as opposed to using an opinionated IO library directly.</html:p>
                <html:p>That being said, I am a very happy user of <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link> when those choices do not matter, <![CDATA[as is the case in building your own application (e.g.]]> <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link><![CDATA[). To this end,]]>  I have spent a good bit of time upstreaming support for various missing pieces in Eio's API including:</html:p>
                <html:ul>
                  <html:li>
                    <html:p><fr:link href="https://github.com/ocaml-multicore/eio/pull/803" type="external">Setuid and setgid</fr:link> fork action's for the process API.</html:p>
                  </html:li>
                  <html:li>
                    <html:p><fr:link href="https://github.com/ocaml-multicore/eio/pull/802" type="external">Set process group</fr:link> support for job control in the process API.</html:p>
                  </html:li>
                  <html:li>
                    <html:p><fr:link href="https://github.com/ocaml-multicore/eio/pull/796" type="external">Responding to <html:code>Buf_write.of_flow</html:code></fr:link> 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.</html:p>
                  </html:li>
                  <html:li>
                    <html:p>I did <fr:link href="https://github.com/ocaml-multicore/eio/issues/788#issuecomment-3224454812" type="external">some investigating into <html:code>EINTR</html:code> bug</fr:link> 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 <html:code>stdout</html:code>.</html:p>
                  </html:li>
                  <html:li>
                    <html:p><fr:link href="https://github.com/ocaml-multicore/eio/issues/807" type="external">Spent some time thinking about the fiber local storage across domains issue</fr:link>, I've passed on some thoughts to folks working on this.</html:p>
                  </html:li>
                </html:ul>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>9</fr:month>
                  <fr:day>2</fr:day>
                </fr:date>
                <fr:title text="Vpnkit">Vpnkit</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>You might recall <fr:link href="/vpnkit-upgrade/" title="Defunctorising VPNKit" uri="https://patrick.sirref.org/vpnkit-upgrade/" display-uri="vpnkit-upgrade" type="local">I was interested in using vpnkit</fr:link>. <fr:link href="https://hannes.robur.coop/" type="external">Hannes</fr:link> has done an amazing amount of work <![CDATA[(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.</html:p>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>9</fr:month>
                      <fr:day>2</fr:day>
                    </fr:date>
                    <fr:title text="Papers and Talks at ICFP">Papers and Talks at ICFP</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html: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:</html:p>
                    <html:ul>
                      <html:li>
                        <html:p>Essentially a <fr:link href="https://icfp25.sigplan.org/details/icfp-2025-papers/21/Functional-Networking-for-Millions-of-Docker-Desktops-Experience-Report-" type="external">Vpnkit Experience Report</fr:link>.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>An extended abstract on generating a corpus of ill-typed Hazel programs was accepted into <fr:link href="https://conf.researchr.org/home/icfp-splash-2025/tyde-2025" type="external">TyDe workshop</fr:link>.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>Relatedly, the work that project supported was accepted into HATRA which was the <fr:link href="/part-ii-hazel/" title="Type Error Debugging in Hazel" uri="https://patrick.sirref.org/part-ii-hazel/" display-uri="part-ii-hazel" type="local">Part II project I supervised</fr:link>: <fr:link href="https://conf.researchr.org/details/icfp-splash-2025/hatra-2025-papers/2/Decomposable-Type-Highlighting-for-Bidirectional-Type-and-Cast-Systems" type="external">Decomposable Type Highlighting for Bidirectional Type and Cast Systems</fr:link>.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>And <fr:link href="https://conf.researchr.org/home/icfp-splash-2025/propl-2025" type="external">two PROPL talks</fr:link>!</html:p>
                      </html:li>
                    </html:ul>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>9</fr:month>
                  <fr:day>2</fr:day>
                </fr:date>
                <fr:title text="Outreachy">Outreachy</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html: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 <fr:link href="https://www.gridbugs.org/" type="external">gridbugs</fr:link> and <fr:link href="/mdales/" title="Michael W. Dales" uri="https://patrick.sirref.org/mdales/" display-uri="mdales" type="local">mdales</fr:link>, and also our fantastic interns. If you are interested, please do watch our demo day presentations.</html:p>
                <html:div style="text-align: center">
    <html: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" />
</html:div>
                <html:p>The next round is fast approaching and we still need to work out the logistics. But I had a good conversation with <fr:link href="/mdales/" title="Michael W. Dales" uri="https://patrick.sirref.org/mdales/" display-uri="mdales" type="local">mdales</fr:link> about possible <fr:link href="/geocaml/" title="Geocaml" uri="https://patrick.sirref.org/geocaml/" display-uri="geocaml" type="local">Geocaml</fr:link> projects that I intend to submit!</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>7</fr:month>
              <fr:day>31</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/ocaml-weekly-2025-w30-w31/</fr:uri>
            <fr:display-uri>ocaml-weekly-2025-w30-w31</fr:display-uri>
            <fr:route>/ocaml-weekly-2025-w30-w31/</fr:route>
            <fr:title text="OCaml Weekly 2025 w30 and w31">OCaml Weekly 2025 w30 and w31</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>A bumper edition today, a fortnightly.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>7</fr:month>
                  <fr:day>31</fr:day>
                </fr:date>
                <fr:title text="Opam Releases">Opam Releases</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I did a little personal spring-cleaning of packages I maintain and pushed a few releases to opam. This included a <fr:link href="https://github.com/ocaml/opam-repository/pull/28187" type="external">0.1.0 release</fr:link> of <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">graft</fr:link>! There is some light documentation online at <fr:link href="https://graft.sirref.org/" type="external">https://graft.sirref.org</fr:link>.</html:p>
                <html:p>Elsewhere, <fr:link href="https://github.com/patricoferris/hilite" type="external">Hilite</fr:link> got a <fr:link href="https://github.com/ocaml/opam-repository/pull/28172" type="external">0.5.0 release</fr:link>. This release makes the core syntax highlighting separate from the markdown part of the library. You can now <fr:link href="https://ocaml.org/p/hilite/latest/doc/hilite/Hilite/index.html#val-src_code_to_pairs" type="external">generate pairs of tokens and identifiers</fr:link> <![CDATA[to plug into any "OCaml sourcecode to format" tool you might be building (e.g.]]>  <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">graft</fr:link><![CDATA[!).]]></html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>7</fr:month>
                  <fr:day>31</fr:day>
                </fr:date>
                <fr:title text="Interactive OCaml Presentations">Interactive OCaml Presentations</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I had fun trying to fuse slipshow and x-ocaml!</html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors />
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>7</fr:month>
                      <fr:day>23</fr:day>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/slipshow-x-xocaml/</fr:uri>
                    <fr:display-uri>slipshow-x-xocaml</fr:display-uri>
                    <fr:route>/slipshow-x-xocaml/</fr:route>
                    <fr:title text="Slipshow x x-ocaml">Slipshow x x-ocaml</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>A short, explanatory post about combining two very fun pieces of work in OCaml.</html:p>
                    <html:p><fr:link href="https://github.com/panglesd" type="external">Paul-Elliot</fr:link> has been building <fr:link href="https://github.com/panglesd/slipshow" type="external">Slipshow</fr:link> for some time now where slides are <html:em>slips</html:em> and your presentations run vertically. More recently, <fr:link href="/artw/" title="Arthur Wendling" uri="https://patrick.sirref.org/artw/" display-uri="artw" type="local">Arthur</fr:link> has built <fr:link href="https://github.com/art-w/x-ocaml" type="external">x-ocaml</fr:link>, a web component library for executable OCaml cells embedded into OCaml.</html:p>
                    <html:p>Using <fr:link href="https://github.com/patricoferris/xocmd" type="external">xocmd</fr:link>, a small tool I built for translating markdown codeblocks to x-ocaml components, your Slipshow's can now be <html:em>executable</html:em>!</html:p>
                    <html:pre><![CDATA[xocmd learn-effects.md | slipshow compile - > learn-effects.html]]></html:pre>
                    <html:p>
    Take a look at 
    <html:a href="/bafkrmictvc3ap2ah37cbcdoo6rsl7vxqu6srogmgzx6iml45bq7zz5weo4.html">an example</html:a>!
    (or the 
    <html:a href="/bafkrmib3jugpkznxcftqjvhbbtfqgx4oz2m32p5xloh4nxia3lhxy2momq.md">source markdown</html:a>).
</html:p>
                    <html:p>I really like this light-weight approach to building interactive presentations <![CDATA[for explaining things in OCaml (e.g. over running a jupyter notebook server).]]></html:p>
                  </fr:mainmatter>
                </fr:tree>
                <html:p>I tried using x-ocaml with <fr:link href="https://irmin.org/" type="external">Irmin</fr:link> and something is not <![CDATA[quite right with some of the runtime JS code being generated (]]> <fr:link href="https://github.com/art-w/x-ocaml/issues/11" type="external">see the issue in case you can help</fr:link><![CDATA[). This was]]>  intended to be used alongside a longer-form retrospective I am writing on my use of Irmin over the years.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>7</fr:month>
                  <fr:day>31</fr:day>
                </fr:date>
                <fr:title text="Outreachy">Outreachy</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I have been helping <fr:link href="/mdales/" title="Michael W. Dales" uri="https://patrick.sirref.org/mdales/" display-uri="mdales" type="local">Michael's</fr:link> intern whilst he has been away on their project <fr:link href="https://github.com/claudiusFX/claudius" type="external">Claudius</fr:link>. 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 <html:em>manual</html:em><![CDATA[ steps when you wish to remove a dependency (1. remove it from]]>  the <html:code>dune-project</html:code> file, 2. run <html:code>dune build</html:code> to update the opam file, 3. remove all occurences of the library from <html:code>dune</html:code><![CDATA[ files across your project).]]></html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>7</fr:month>
                  <fr:day>31</fr:day>
                </fr:date>
                <fr:title text="Ppxlib">Ppxlib</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Work on <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">Ppxlib</fr:link> has been fairly varied this past two weeks. I mentioned before about an exiting plan <fr:link href="/nathanreb/" title="Nathan Rebours" uri="https://patrick.sirref.org/nathanreb/" display-uri="nathanreb" type="local">Nathan</fr:link> 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 <fr:link href="/ppxlib-5-2/" title="Bumping Ppxlib's AST to 5.2" uri="https://patrick.sirref.org/ppxlib-5-2/" display-uri="ppxlib-5-2" type="local">the 5.2 bump</fr:link>. <fr:link href="https://github.com/mirage/repr/pull/110" type="external">Repr</fr:link> got some fixes pushed to it, but this unconvered <fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/588" type="external">more issues</fr:link>.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>7</fr:month>
                  <fr:day>31</fr:day>
                </fr:date>
                <fr:title text="Misc.">Misc.</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I spent some time cleaning up <fr:link href="https://github.com/quantifyearth/container-image" type="external">container-image</fr:link>, a tool primarily written by <fr:link href="https://github.com/samoht" type="external">Thomas G.</fr:link> to fetch OCI images from repositories. The <fr:link href="https://github.com/quantifyearth/container-image/pull/5" type="external">tidy up</fr:link> went surprisingly well, except for some spurious HTTP errors with AWS. Maybe I'll spend some <![CDATA[proper time trying to help the state of HTTP clients in OCaml (of which there]]>  <![CDATA[are many, but few that work very well out of the box in my experience).]]></html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>7</fr:month>
              <fr:day>15</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/ocaml-weekly-2025-w29/</fr:uri>
            <fr:display-uri>ocaml-weekly-2025-w29</fr:display-uri>
            <fr:route>/ocaml-weekly-2025-w29/</fr:route>
            <fr:title text="OCaml Weekly 2025 w29">OCaml Weekly 2025 w29</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>7</fr:month>
                  <fr:day>15</fr:day>
                </fr:date>
                <fr:title text="Ppxlib">Ppxlib</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I met with <fr:link href="/nathanreb/" title="Nathan Rebours" uri="https://patrick.sirref.org/nathanreb/" display-uri="nathanreb" type="local">Nathan</fr:link> this week to discuss future plans for <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link>. The current state of affairs is that <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> is becoming unmaintainable. This is primarily a knock-on effect from changes being made to <![CDATA[OCaml's parsetree (e.g. labelled tuples being added in 5.4).]]>  <fr:link href="/nathanreb/" title="Nathan Rebours" uri="https://patrick.sirref.org/nathanreb/" display-uri="nathanreb" type="local">Nathan</fr:link> has a plan that will provide two key properties.</html:p>
                <html:ol>
                  <html:li>
                    <html:p>Migrations, which allow old compilers to be used with new <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> releases, will be more compatible. For example, we will be able to migrate new features downwards and back up without raising an error.</html:p>
                  </html:li>
                  <html:li>
                    <html:p>Ppx authors will be able to use new features in an opt-in workflow, rather than <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link><![CDATA[ bumping the internal AST (like we did]]> <fr:link href="/ppxlib-5-2/" title="Bumping Ppxlib's AST to 5.2" uri="https://patrick.sirref.org/ppxlib-5-2/" display-uri="ppxlib-5-2" type="local">in ppxlib.0.36.0</fr:link><![CDATA[). This will reduce the maintenance burden]]>  significantly whilst still allowing users to write ppxes for new OCaml features.</html:p>
                  </html:li>
                </html:ol>
                <html:p>I also started looking into some older issues in <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> related to performance. This is work-in-progress, but I am trying to improve the performance of some passes done by <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link>. To better understand what was making <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> slow, I wanted to use <fr:link href="https://github.com/tarides/runtime_events_tools" type="external">runtime_events_tools</fr:link> but I was dismayed to see it wanting to install over 100 packages! I <fr:link href="https://github.com/tarides/runtime_events_tools/pull/57" type="external">opened a PR to reduce the number of packages</fr:link>. 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.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>7</fr:month>
                  <fr:day>15</fr:day>
                </fr:date>
                <fr:title text="Outreachy">Outreachy</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>In <fr:link href="/outreachy/" title="Outreachy" uri="https://patrick.sirref.org/outreachy/" display-uri="outreachy" type="local">Outreachy</fr:link> 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 <fr:link href="/mdales/" title="Michael W. Dales" uri="https://patrick.sirref.org/mdales/" display-uri="mdales" type="local">Michael</fr:link> and <fr:link href="https://github.com/gridbugs" type="external">Steve</fr:link> have put in so far to make this a very successful Outreachy round for OCaml.</html:p>
                <html:p>In sadder news, an email was shared with all <fr:link href="/outreachy/" title="Outreachy" uri="https://patrick.sirref.org/outreachy/" display-uri="outreachy" type="local">Outreachy</fr:link> 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.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>7</fr:month>
                  <fr:day>15</fr:day>
                </fr:date>
                <fr:title text="Graft">Graft</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>With the release of <fr:link href="https://patrick.sirref.org/Forester/" type="external">Forester.5.0</fr:link>, I made a plan to make a release of <fr:link href="https://patrick.sirref.org/Graft/" type="external">Graft.0.1</fr:link>. Unfortunately this is blocked by a new release of <fr:link href="https://github.com/ocaml/opam-repository/pull/28172" type="external">hilite</fr:link>, a tool I built for doing build-time syntax highlighting for OCaml code. This powers the syntax highlighting on <fr:link href="https://ocaml.org/" type="external">ocaml.org</fr:link>.</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
      </fr:mainmatter>
    </fr:tree>
    <fr:tree show-metadata="false" expanded="false" toc="false">
      <fr:frontmatter>
        <fr:authors />
        <fr:uri>https://patrick.sirref.org/teaching/</fr:uri>
        <fr:display-uri>teaching</fr:display-uri>
        <fr:route>/teaching/</fr:route>
        <fr:title text="Teaching">Teaching</fr:title>
      </fr:frontmatter>
      <fr:mainmatter>
        <html:p>I supervise multiple courses in the <fr:link href="/camcst/" title="Department of Computer Science and Technology, University of Cambridge" uri="https://patrick.sirref.org/camcst/" display-uri="camcst" type="local">Department of Computer Science</fr:link> including:</html:p>
        <fr:tree show-metadata="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:uri>https://patrick.sirref.org/focs/</fr:uri>
            <fr:display-uri>focs</fr:display-uri>
            <fr:route>/focs/</fr:route>
            <fr:title text="Foundations of Computer Science">Foundations of Computer Science</fr:title>
            <fr:meta name="external">https://www.cl.cam.ac.uk/teaching/2425/FoundsCS/</fr:meta>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p><html:em>Foundations of Computer Science</html:em> is a first-year course taught in the <fr:link href="/camcst/" title="Department of Computer Science and Technology, University of Cambridge" uri="https://patrick.sirref.org/camcst/" display-uri="camcst" type="local">Department of Computer Science</fr:link>. It is currently lectured by <fr:link href="/anilmadhavapeddy/" title="Anil Madhavapeddy" uri="https://patrick.sirref.org/anilmadhavapeddy/" display-uri="anilmadhavapeddy" type="local">Anil Madhavapeddy</fr:link> and taught in OCaml.</html:p>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:uri>https://patrick.sirref.org/discrete-maths/</fr:uri>
            <fr:display-uri>discrete-maths</fr:display-uri>
            <fr:route>/discrete-maths/</fr:route>
            <fr:title text="Discrete Mathematics">Discrete Mathematics</fr:title>
            <fr:meta name="external">https://www.cl.cam.ac.uk/teaching/2425/DiscMath/</fr:meta>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p><html:em>Discrete Mathematics</html:em> is a first-year course taught in the <fr:link href="/camcst/" title="Department of Computer Science and Technology, University of Cambridge" uri="https://patrick.sirref.org/camcst/" display-uri="camcst" type="local">Department of Computer Science</fr:link>. It is currently lectured by <fr:link href="/jonmsterling/" title="Jon Sterling" uri="https://patrick.sirref.org/jonmsterling/" display-uri="jonmsterling" type="local">Jon Sterling</fr:link>.</html:p>
          </fr:mainmatter>
        </fr:tree>
        <html:p><![CDATA[In addition to this, I supervise multiple final year (Part II) dissertations.]]></html:p>
        <fr:tree show-metadata="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:uri>https://patrick.sirref.org/part-ii/</fr:uri>
            <fr:display-uri>part-ii</fr:display-uri>
            <fr:route>/part-ii/</fr:route>
            <fr:title text="Part II Projects">Part II Projects</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>Part II is the name for third year students studying Computer Science at <fr:link href="/ucam/" title="University of Cambridge" uri="https://patrick.sirref.org/ucam/" display-uri="ucam" type="local">Cambridge</fr:link>. Over the course of the year, a student is tasked with building a substantial piece of software culminating in a dissertation-style write up at the end. I did this back in 2020, you <fr:link href="/pf341-diss/" title="Optimisations Across Hardware and Software using RISC-V" uri="https://patrick.sirref.org/pf341-diss/" display-uri="pf341-diss" type="local">can read about that here</fr:link>.</html:p>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2023</fr:year>
                  <fr:month>9</fr:month>
                  <fr:day>10</fr:day>
                </fr:date>
                <fr:uri>https://patrick.sirref.org/part-ii-2023/</fr:uri>
                <fr:display-uri>part-ii-2023</fr:display-uri>
                <fr:route>/part-ii-2023/</fr:route>
                <fr:title text="Part II Students 2023">Part II Students 2023</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>In the final year of the <fr:link href="/ucam/" title="University of Cambridge" uri="https://patrick.sirref.org/ucam/" display-uri="ucam" type="local">Cambridge</fr:link> undergraduate degree in computer science, students undertake a coding project with an accompanying dissertation.</html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors />
                    <fr:uri>https://patrick.sirref.org/part-ii-dslid/</fr:uri>
                    <fr:display-uri>part-ii-dslid</fr:display-uri>
                    <fr:route>/part-ii-dslid/</fr:route>
                    <fr:title text="A DSL for Decentralised Identity in OCaml">A DSL for Decentralised Identity in OCaml</fr:title>
                    <fr:meta name="external">https://github.com/majkimge/DecentralisedDigitalIdentity</fr:meta>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>This project was completed by <fr:link href="https://www.linkedin.com/in/michal-mgeladze-arciuch" type="external">Michał Mgeładze-Arciuch</fr:link> and supervised by <fr:link href="/anilmadhavapeddy/" title="Anil Madhavapeddy" uri="https://patrick.sirref.org/anilmadhavapeddy/" display-uri="anilmadhavapeddy" type="local">Anil Madhavapeddy</fr:link> and <fr:link href="/patrickferris/" title="Patrick Ferris" uri="https://patrick.sirref.org/patrickferris/" display-uri="patrickferris" type="local">Patrick Ferris</fr:link>.</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2024</fr:year>
                  <fr:month>9</fr:month>
                  <fr:day>10</fr:day>
                </fr:date>
                <fr:uri>https://patrick.sirref.org/part-ii-2024/</fr:uri>
                <fr:display-uri>part-ii-2024</fr:display-uri>
                <fr:route>/part-ii-2024/</fr:route>
                <fr:title text="Part II Students 2024">Part II Students 2024</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>In the final year of the <fr:link href="/ucam/" title="University of Cambridge" uri="https://patrick.sirref.org/ucam/" display-uri="ucam" type="local">Cambridge</fr:link> undergraduate degree in computer science, students undertake a coding project with an accompanying dissertation.</html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors />
                    <fr:uri>https://patrick.sirref.org/part-ii-hazel/</fr:uri>
                    <fr:display-uri>part-ii-hazel</fr:display-uri>
                    <fr:route>/part-ii-hazel/</fr:route>
                    <fr:title text="Type Error Debugging in Hazel">Type Error Debugging in Hazel</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:blockquote>
                      <html:p>This project will add some features to the <fr:link href="/hazel/" title="Hazel" uri="https://patrick.sirref.org/hazel/" display-uri="hazel" type="local">Hazel</fr:link> language. <fr:link href="/hazel/" title="Hazel" uri="https://patrick.sirref.org/hazel/" display-uri="hazel" type="local">Hazel</fr:link><![CDATA[ is a functional research language that makes use of gradual types to support unusual features such as: holes (code place-holders) to give type meaning to incomplete programs. Importantly for this project, all Hazel programs, even ill-typed or incomplete programs, are evaluable. This allows dynamic reasoning about ill-typed programs via evaluation traces with the potential to improve the user’s understanding of why ill-typed programs go wrong.]]></html:p>
                      <html:p><![CDATA[This project aims to exploit further this potential by providing some extra features to both: aid with finding values/inputs that demonstrate why type-errors were found (type-error witnesses) and linking the evaluation traces back to source code.]]></html:p>
                    </html:blockquote>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors />
                    <fr:uri>https://patrick.sirref.org/part-ii-udsl/</fr:uri>
                    <fr:display-uri>part-ii-udsl</fr:display-uri>
                    <fr:route>/part-ii-udsl/</fr:route>
                    <fr:title text="A Universal Data Access DSL">A Universal Data Access DSL</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:blockquote>
                      <html:p><![CDATA[The design and implementation of a jq-like EDSL allowing programmers to abstract away the format in which data is stored (YAML, EXIF metadata etc.) and the file system being used – e.g.]]> <html:code><![CDATA[open("a/b/[c,d]")]]></html:code><![CDATA[ could mean "fields c, d in YAML file b of ZIP file a", or it could mean "fields b.c, b.d in JSON file a". My project would statically examine the filesystem to decide which case we're in, giving data scientists an easy way to declare the shape of the data they depend on. Success criteria include projection (correctly reading the data based on the file type), subtyping (e.g. JSON-LD is a child of JSON) and perhaps some compiler optimisations related to parsing (e.g. only loading a JSON library if the file is actually JSON).]]></html:p>
                    </html:blockquote>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors />
                    <fr:uri>https://patrick.sirref.org/part-ii-paraeff/</fr:uri>
                    <fr:display-uri>part-ii-paraeff</fr:display-uri>
                    <fr:route>/part-ii-paraeff/</fr:route>
                    <fr:title text="Implementing Parallel Algebraic Effect Handlers in OCaml">Implementing Parallel Algebraic Effect Handlers in OCaml</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:blockquote>
                      <html:p><![CDATA[Algebraic effects are becoming increasingly common, but it can be difficult to use them in parallel computations. Xie et al. (2024) present a new structure for effect handlers which allows parallel subcomputations to perform effects independently without synchronisation. I plan to implement the traverse handler in OCaml 5 and evaluate its performance against equivalent programs which do not use effects using a variety of benchmark programs. As extensions, I will devise similar handlers for other types of parallelism, possibly including a more general form which works for many types simultaneously, and investigate how to improve its real-world performance.]]></html:p>
                    </html:blockquote>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors />
                    <fr:uri>https://patrick.sirref.org/part-ii-geocaml/</fr:uri>
                    <fr:display-uri>part-ii-geocaml</fr:display-uri>
                    <fr:route>/part-ii-geocaml/</fr:route>
                    <fr:title text="Effective Geospatial Code in OCaml">Effective Geospatial Code in OCaml</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>This project is co-supervised with <fr:link href="/mdales/" title="Michael W. Dales" uri="https://patrick.sirref.org/mdales/" display-uri="mdales" type="local">Michael Dales</fr:link>.</html:p>
                    <html:blockquote>
                      <html:p>Geospatial processing is critical in environmental science and is used in a range of environmental scenarios, both in areas of carbon accounting like digital Monitoring, Reporting and Verification in Reforestation Carbon Removal, and also biodiversity analysis like calculating worldwide extinction rates.</html:p>
                      <html:p><![CDATA[However there are problems with the current state of affairs, Python is one of the most popular data science libraries, and when doing geospatial data science with Python you use the GDAL geospatial data library. This workflow is not ideal [2]. For environmental scientists, interacting with the geospatial data in the imperative way that Python requires can be very difficult, and it is also not designed for the scale of computation needed for large geospatial projects. Furthermore, Python’s dynamic type system means that tricky type errors due to heterogeneity of data points can go unchecked. GDAL also only allows synchronous IO for loading GeoTIFF files, which can hurt performance.]]></html:p>
                      <html:p><![CDATA[I will write a non-blocking library for reading GeoTIFF files in OCaml (built on top of the WIP OCaml-TIFF library1 written by one of my supervisors, Patrick Ferris). I will then use OCaml to write an embedded Domain Specific Language (eDSL) which will be used to interact with geospatial data in a declarative way.]]></html:p>
                    </html:blockquote>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
      </fr:mainmatter>
    </fr:tree>
    <fr:tree show-metadata="false" expanded="false" toc="false">
      <fr:frontmatter>
        <fr:authors />
        <fr:uri>https://patrick.sirref.org/publications/</fr:uri>
        <fr:display-uri>publications</fr:display-uri>
        <fr:route>/publications/</fr:route>
        <fr:title text="Publications">Publications</fr:title>
      </fr:frontmatter>
      <fr:mainmatter>
        <html:p>Various talks, papers and preprints.</html:p>
        <fr:tree show-metadata="true" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:title text="Published">Published</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <fr:tree show-metadata="true" toc="false" numbered="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:title text="Conference Papers">Conference Papers</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:hr />
                <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/David J. Scott" type="external">David J. Scott</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Ryan T. Gibb" type="external">Ryan T. Gibb</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Thomas Gazagnaire/" type="external">Thomas Gazagnaire</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/madhavapeddy2025docker/</fr:uri>
                    <fr:display-uri>madhavapeddy2025docker</fr:display-uri>
                    <fr:route>/madhavapeddy2025docker/</fr:route>
                    <fr:title text="Functional Networking for Millions of Docker Desktops (Experience Report)">Functional Networking for Millions of Docker Desktops (Experience Report)</fr:title>
                    <fr:taxon>Reference</fr:taxon>
                    <fr:meta name="external">https://dl.acm.org/doi/10.1145/3747525</fr:meta>
                    <fr:meta name="journal">Proc. ACM Program. Lang.</fr:meta>
                    <fr:meta name="doi">10.1145/3747525</fr:meta>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <fr:tree show-metadata="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/David J. Scott" type="external">David J. Scott</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Ryan T. Gibb" type="external">Ryan T. Gibb</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Thomas Gazagnaire/" type="external">Thomas Gazagnaire</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                        </fr:date>
                        <fr:title text="Abstract">Abstract</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html: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.
</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
                <html:hr />
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="true" toc="false" numbered="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:title text="Workshop Papers">Workshop Papers</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:hr />
                <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/ferris2025hazel_of_ocaml/</fr:uri>
                    <fr:display-uri>ferris2025hazel_of_ocaml</fr:display-uri>
                    <fr:route>/ferris2025hazel_of_ocaml/</fr:route>
                    <fr:title text="Generating a corpus of Hazel programs from ill-typed OCaml programs">Generating a corpus of Hazel programs from ill-typed OCaml programs</fr:title>
                    <fr:taxon>Reference</fr:taxon>
                    <fr:meta name="external">https://patrick.sirref.org/var/tyde2025.pdf</fr:meta>
                    <fr:meta name="doi" />
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <fr:tree show-metadata="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                        </fr:date>
                        <fr:title text="Abstract">Abstract</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html: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.
</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
                <html:hr />
                <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Max Carroll/" type="external">Max Carroll</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/carroll2025decomposable_type_highlighting/</fr:uri>
                    <fr:display-uri>carroll2025decomposable_type_highlighting</fr:display-uri>
                    <fr:route>/carroll2025decomposable_type_highlighting/</fr:route>
                    <fr:title text="Decomposable Type Highlighting for Bidirectional Type and Cast Systems">Decomposable Type Highlighting for Bidirectional Type and Cast Systems</fr:title>
                    <fr:taxon>Reference</fr:taxon>
                    <fr:meta name="external">https://maxcarroll0.github.io/papers/workshops/HATRA-decomposable-type-highlighting/</fr:meta>
                    <fr:meta name="doi" />
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <fr:tree show-metadata="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Max Carroll/" type="external">Max Carroll</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                        </fr:date>
                        <fr:title text="Abstract">Abstract</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html: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.
</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
                <html:hr />
                <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Michael Winston Dales/" type="external">Michael Winston Dales</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Alison Eyres/" type="external">Alison Eyres</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Francesca A. Ridley" type="external">Francesca A. Ridley</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Simon Tarr/" type="external">Simon Tarr</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/dales2025yirgacheffe/</fr:uri>
                    <fr:display-uri>dales2025yirgacheffe</fr:display-uri>
                    <fr:route>/dales2025yirgacheffe/</fr:route>
                    <fr:title text="Yirgacheffe: A Declarative Approach to Geospatial Data">Yirgacheffe: A Declarative Approach to Geospatial Data</fr:title>
                    <fr:taxon>Reference</fr:taxon>
                    <fr:meta name="external">https://dl.acm.org/doi/10.1145/3759536.3763806</fr:meta>
                    <fr:meta name="doi">10.1145/3759536.3763806</fr:meta>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <fr:tree show-metadata="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Michael Winston Dales/" type="external">Michael Winston Dales</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Alison Eyres/" type="external">Alison Eyres</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Francesca A. Ridley" type="external">Francesca A. Ridley</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Simon Tarr/" type="external">Simon Tarr</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                        </fr:date>
                        <fr:title text="Abstract">Abstract</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p><![CDATA[		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.]]></html:p>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
                <html:hr />
                <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Cyrus Omar/" type="external">Cyrus Omar</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2024</fr:year>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/omar2024bastion/</fr:uri>
                    <fr:display-uri>omar2024bastion</fr:display-uri>
                    <fr:route>/omar2024bastion/</fr:route>
                    <fr:title text="Modularizing Reasoning about AI Capabilities via Abstract Dijkstra Monads">Modularizing Reasoning about AI Capabilities via Abstract Dijkstra Monads</fr:title>
                    <fr:taxon>Reference</fr:taxon>
                    <fr:meta name="external">https://icfp24.sigplan.org/home/hope-2024</fr:meta>
                    <fr:meta name="doi" />
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <fr:tree show-metadata="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Cyrus Omar/" type="external">Cyrus Omar</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2024</fr:year>
                        </fr:date>
                        <fr:title text="Abstract">Abstract</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p><![CDATA[    The proposed talk will outline the vision for a recently originated research project aiming to build a formally verified prototype of a foundational "operating system" for safeguarded AI, called Bastion, that grounds these activities within programming language theory, namely by combining dependent type theory (as a practical general-purpose theory of computational structures and proofs), Dijkstra monads (as a flexible formalism for reasoning about an AI agent's computational effects), and abstract types (for modularizing reasoningto individual components that can be separately developed by various stakeholders, including AI safety researchers, formal methods experts, organizations of various scales, and governments seeking to develop actionable, specific policy).]]></html:p>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
                <html:hr />
                <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Ryan Gibb/" type="external">Ryan Gibb</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2024</fr:year>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/gibb2024carbonaware/</fr:uri>
                    <fr:display-uri>gibb2024carbonaware</fr:display-uri>
                    <fr:route>/gibb2024carbonaware/</fr:route>
                    <fr:title text="Carbon-Aware Name Resolution">Carbon-Aware Name Resolution</fr:title>
                    <fr:taxon>Reference</fr:taxon>
                    <fr:meta name="external">https://www.sicsa.ac.uk/wp-content/uploads/2024/11/LOCO2024_paper_28.pdf</fr:meta>
                    <fr:meta name="journal">1st International Workshop on Low Carbon Computing</fr:meta>
                    <fr:meta name="doi" />
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <fr:tree show-metadata="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Ryan Gibb/" type="external">Ryan Gibb</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2024</fr:year>
                        </fr:date>
                        <fr:title text="Abstract">Abstract</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>The current Internet architecture fails to treat the carbon emissions associated with networked services as a first-class metric. We propose extending the DNS with load balancing techniques to consider the carbon cost of scheduling decisions, and further to actively wake machines running networked services as a side effect of name resolution. By extending the DNS, we maintain compatibility with existing Internet infrastructure, unlocking the ability for existing applications to be carbon-aware.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
                <html:hr />
                <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Michael Dales/" type="external">Michael Dales</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2024</fr:year>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/dales2024frugallinux/</fr:uri>
                    <fr:display-uri>dales2024frugallinux</fr:display-uri>
                    <fr:route>/dales2024frugallinux/</fr:route>
                    <fr:title text="Lineage first computing: towards a frugal userspace for Linux">Lineage first computing: towards a frugal userspace for Linux</fr:title>
                    <fr:taxon>Reference</fr:taxon>
                    <fr:meta name="external">https://www.sicsa.ac.uk/wp-content/uploads/2024/11/LOCO2024_paper_30.pdf</fr:meta>
                    <fr:meta name="journal">1st International Workshop on Low Carbon Computing</fr:meta>
                    <fr:meta name="doi" />
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <fr:tree show-metadata="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Michael Dales/" type="external">Michael Dales</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2024</fr:year>
                        </fr:date>
                        <fr:title text="Abstract">Abstract</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>Data-science is a vital tool in tackling the ongoing climate crisis, but it is one that has a significant cost to it also, in terms of energy used during execution and in terms of significant hardware investment required to run it. These are then amplified considerably in the exploratory nature of scientific research.We argue this is because the affordances of the operating system, particularly filesystems, make little effort to support reuse of computed artifacts directly or promote reuse through trusted lineage data.

However, it turns out that many of the userspace interfaces exposed by the Linux kernel entirely support a radically more efficient -- a more frugal -- model of computation than is currently the default. In this talk, we explore a new OS architecture which defaults to deterministic, reusable computation with the careful recording of side effects. This in turn allows the OS to guide complex computations towards previously acquired intermediate results, but still allowing for recomputation when required.

We use these interfaces to build a new Linux userspace where we put the workflow graph-containing relationships between tools, provenance and labelling-as the core of a system that drives how processes, data, and users interact. Our prototype shell, dubbed Shark, is a data-science first operating environment that is designed to both ensure efficient use of computation and storage resources, and to make it easy for non-experts to create pipeline descriptions from end results post-hoc. It does this by making the lineage graph of a data-pipeline the key concept that ties everything else together: by tracking how the data-pipeline evolves from experimental practice, and tracking what data has already been built and what hasn't we can prevent re-execution both at development and after publication.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
                <html:hr />
                <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Jessica Man/" type="external">Jessica Man</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Sadiq Jaffer/" type="external">Sadiq Jaffer</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Martin Kleppmann/" type="external">Martin Kleppmann</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2024</fr:year>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/man2024emissionimpossible/</fr:uri>
                    <fr:display-uri>man2024emissionimpossible</fr:display-uri>
                    <fr:route>/man2024emissionimpossible/</fr:route>
                    <fr:title text="Emission Impossible: privacy-preserving carbon emissions claims">Emission Impossible: privacy-preserving carbon emissions claims</fr:title>
                    <fr:taxon>Reference</fr:taxon>
                    <fr:meta name="external">https://www.sicsa.ac.uk/wp-content/uploads/2024/11/LOCO2024_paper_35.pdf</fr:meta>
                    <fr:meta name="journal">1st International Workshop on Low Carbon Computing</fr:meta>
                    <fr:meta name="doi" />
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <fr:tree show-metadata="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Jessica Man/" type="external">Jessica Man</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Sadiq Jaffer/" type="external">Sadiq Jaffer</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Martin Kleppmann/" type="external">Martin Kleppmann</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2024</fr:year>
                        </fr:date>
                        <fr:title text="Abstract">Abstract</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p><![CDATA[In this talk we will explore: (i) how the conflicting incentives around carbon emissions reporting make existing systems unlikely to succeed; and (ii) how we could use ZKPs to allow for the accurate reporting of carbon claims without compromising on individual privacy and competitiveness requirements.]]></html:p>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
                <html:hr />
                <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Thomas Leonard/" type="external">Thomas Leonard</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Christiano Haesbaert/" type="external">Christiano Haesbaert</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Lucas Pluvinage/" type="external">Lucas Pluvinage</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Vesa Karvonen/" type="external">Vesa Karvonen</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Sudha Parimala/" type="external">Sudha Parimala</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/K Sivaramakrishnan/" type="external">K Sivaramakrishnan</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Vincent Balat/" type="external">Vincent Balat</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2023</fr:year>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/leonard2023eio/</fr:uri>
                    <fr:display-uri>leonard2023eio</fr:display-uri>
                    <fr:route>/leonard2023eio/</fr:route>
                    <fr:title text="Eio 1.0-effects-based IO for OCaml 5">Eio 1.0-effects-based IO for OCaml 5</fr:title>
                    <fr:taxon>Reference</fr:taxon>
                    <fr:meta name="doi" />
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <fr:tree show-metadata="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Thomas Leonard/" type="external">Thomas Leonard</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Christiano Haesbaert/" type="external">Christiano Haesbaert</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Lucas Pluvinage/" type="external">Lucas Pluvinage</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Vesa Karvonen/" type="external">Vesa Karvonen</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Sudha Parimala/" type="external">Sudha Parimala</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/K Sivaramakrishnan/" type="external">K Sivaramakrishnan</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Vincent Balat/" type="external">Vincent Balat</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2023</fr:year>
                        </fr:date>
                        <fr:title text="Abstract">Abstract</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>Eio provides an effects-based direct-style IO stack for OCaml 5. This talk introduces Eio's main features, such as use of effects, multicore support and lock-free data-structures, support for modular programming, interoperability with other concurrency libraries such as Lwt, Async and Domainslib, and interactive monitoring support enabled by the custom runtime events in OCaml 5.1. We will report on our experiences porting existing applications to Eio.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
                <html:hr />
                <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Sadiq Jaffer/" type="external">Sadiq Jaffer</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2022</fr:year>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/jaffer2022runtimeevents/</fr:uri>
                    <fr:display-uri>jaffer2022runtimeevents</fr:display-uri>
                    <fr:route>/jaffer2022runtimeevents/</fr:route>
                    <fr:title text="Continuous Monitoring of OCaml Applications using Runtime Events">Continuous Monitoring of OCaml Applications using Runtime Events</fr:title>
                    <fr:taxon>Reference</fr:taxon>
                    <fr:meta name="external">https://icfp22.sigplan.org/details/ocaml-2022-papers/7/Continuous-Monitoring-of-OCaml-Applications-using-Runtime-Events</fr:meta>
                    <fr:meta name="doi" />
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <fr:tree show-metadata="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Sadiq Jaffer/" type="external">Sadiq Jaffer</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2022</fr:year>
                        </fr:date>
                        <fr:title text="Abstract">Abstract</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>The upcoming 5.0 release of OCaml includes a new runtime tracing system designed for continuous monitoring of OCaml applications called Runtime Events. It enables very low overhead, programmatic access to performance data emitted by the OCaml runtime and garbage collector. This talk focuses on the implementation of Runtime Events and the user experience of writing applications exploiting this new feature.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="true" toc="false" numbered="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:title text="Misc.">Misc.</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:hr />
                <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/ferris2025scientific_programming/</fr:uri>
                    <fr:display-uri>ferris2025scientific_programming</fr:display-uri>
                    <fr:route>/ferris2025scientific_programming/</fr:route>
                    <fr:title text="What we talk about when we talk about scientific programming">What we talk about when we talk about scientific programming</fr:title>
                    <fr:taxon>Reference</fr:taxon>
                    <fr:meta name="external">https://watch.eeg.cl.cam.ac.uk/w/aYXqXLtgQawYMjVXjSQtjx</fr:meta>
                    <fr:meta name="doi" />
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <fr:tree show-metadata="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                        </fr:date>
                        <fr:title text="Abstract">Abstract</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p><![CDATA[	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.]]></html:p>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
                <html:hr />
                <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Sadiq Jaffer/" type="external">Sadiq Jaffer</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Michael Dales/" type="external">Michael Dales</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Derek Sorensen/" type="external">Derek Sorensen</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Thomas Swinfield/" type="external">Thomas Swinfield</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Robin Message/" type="external">Robin Message</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Srinivasan Keshav/" type="external">Srinivasan Keshav</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2024</fr:year>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/jaffer2024global/</fr:uri>
                    <fr:display-uri>jaffer2024global</fr:display-uri>
                    <fr:route>/jaffer2024global/</fr:route>
                    <fr:title text="Global, robust and comparable digital carbon assets">Global, robust and comparable digital carbon assets</fr:title>
                    <fr:taxon>Reference</fr:taxon>
                    <fr:meta name="doi">10.1109/ICBC59979.2024.10634343</fr:meta>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <fr:tree show-metadata="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Sadiq Jaffer/" type="external">Sadiq Jaffer</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Michael Dales/" type="external">Michael Dales</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Derek Sorensen/" type="external">Derek Sorensen</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Thomas Swinfield/" type="external">Thomas Swinfield</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Robin Message/" type="external">Robin Message</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Srinivasan Keshav/" type="external">Srinivasan Keshav</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2024</fr:year>
                        </fr:date>
                        <fr:title text="Abstract">Abstract</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p><![CDATA[Carbon credits purchased in the voluntary carbon market allow
			unavoidable emissions, such as international flights for essential
			travel, to be offset by an equivalent climate benefit, such as
			avoiding emissions from tropical deforestation. However, many
			concerns regarding the credibility of these offsetting claims have
			been raised. Moreover, the credit market is manual, therefore
			inefficient and unscalable, and non-fungible, therefore illiquid.
			To address these issues, we propose an efficient digital
			methodology that combines remote sensing data, modern econometric
			techniques, and on-chain certification and trading to create a new
			digital carbon asset (the PACT stablecoin) against which carbon
			offsetting claims can be transparently verified. PACT stablecoins
			are produced as outputs from a reproducible computational pipeline
			for estimating the climate benefits of carbon offset projects that
			not only quantifies the CO2 emissions involved, but also allows for
			similar credits to be pooled based on their co-benefits such as
			biodiversity and jurisdictional attributes, increasing liquidity
			through fungibility within pools. We implement and evaluate the
			PACT carbon stablecoin on the Tezos blockchain, which is designed
			to facilitate low-cost transactions while minimizing environmental
			impact. Our implementation includes a contract for a registry for
			tracking issuance, ownership, and retirement of credits, and a
			custodian contract to bridge on-chain and off-chain transactions.
			Our work brings scale and trust to the voluntary carbon market by
			providing a transparent, scalable, and efficient framework for
			high-integrity carbon credit transactions.]]></html:p>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
                <html:hr />
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="true" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:title text="Preprints">Preprints</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:hr />
            <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Michael Dales/" type="external">Michael Dales</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Sadiq Jaffer/" type="external">Sadiq Jaffer</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Amelia Holcomb/" type="external">Amelia Holcomb</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Eleanor Scott/" type="external">Eleanor Scott</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Thomas Swinfield/" type="external">Thomas Swinfield</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Alison Eyres/" type="external">Alison Eyres</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Andrew Balmford/" type="external">Andrew Balmford</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/David Coomes/" type="external">David Coomes</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Srinivasan Keshav/" type="external">Srinivasan Keshav</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2023</fr:year>
                </fr:date>
                <fr:uri>https://patrick.sirref.org/ferris2023planetary/</fr:uri>
                <fr:display-uri>ferris2023planetary</fr:display-uri>
                <fr:route>/ferris2023planetary/</fr:route>
                <fr:title text="Planetary computing for data-driven environmental policy-making">Planetary computing for data-driven environmental policy-making</fr:title>
                <fr:taxon>Reference</fr:taxon>
                <fr:meta name="journal">Arxiv</fr:meta>
                <fr:meta name="doi">10.48550/arXiv.2303.04501</fr:meta>
              </fr:frontmatter>
              <fr:mainmatter>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Michael Dales/" type="external">Michael Dales</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Sadiq Jaffer/" type="external">Sadiq Jaffer</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Amelia Holcomb/" type="external">Amelia Holcomb</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Eleanor Scott/" type="external">Eleanor Scott</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Thomas Swinfield/" type="external">Thomas Swinfield</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Alison Eyres/" type="external">Alison Eyres</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Andrew Balmford/" type="external">Andrew Balmford</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/David Coomes/" type="external">David Coomes</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Srinivasan Keshav/" type="external">Srinivasan Keshav</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2023</fr:year>
                    </fr:date>
                    <fr:title text="Abstract">Abstract</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>We make a case for planetary computing -- infrastructure to handle the ingestion, transformation, analysis and publication of global data products for furthering environmental science and enabling better informed policy-making. We draw on our experiences as a team of computer scientists working with environmental scientists on forest carbon and biodiversity preservation, and classify existing solutions by their flexibility in scalably processing geospatial data, and also how well they support building trust in the results via traceability and reproducibility. We identify research gaps in the intersection of computing and environmental science around how to handle continuously changing datasets that are often collected across decades and require careful access control rather than being fully open access.</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <html:hr />
            <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Andrew Balmford/" type="external">Andrew Balmford</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/David Coomes/" type="external">David Coomes</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Michael Dales/" type="external">Michael Dales</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/James Hartup/" type="external">James Hartup</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Sadiq Jaffer/" type="external">Sadiq Jaffer</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Srinivasan Keshav/" type="external">Srinivasan Keshav</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Miranda Lam/" type="external">Miranda Lam</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Robin Message/" type="external">Robin Message</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2023</fr:year>
                </fr:date>
                <fr:uri>https://patrick.sirref.org/balmford2023pact/</fr:uri>
                <fr:display-uri>balmford2023pact</fr:display-uri>
                <fr:route>/balmford2023pact/</fr:route>
                <fr:title text="PACT Tropical Moist Forest Accreditation Methodology v2.0">PACT Tropical Moist Forest Accreditation Methodology v2.0</fr:title>
                <fr:taxon>Reference</fr:taxon>
                <fr:meta name="journal">Cambridge Open Engage</fr:meta>
                <fr:meta name="doi">10.33774/coe-2023-g584d-v5</fr:meta>
              </fr:frontmatter>
              <fr:mainmatter>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Andrew Balmford/" type="external">Andrew Balmford</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/David Coomes/" type="external">David Coomes</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Michael Dales/" type="external">Michael Dales</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/James Hartup/" type="external">James Hartup</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Sadiq Jaffer/" type="external">Sadiq Jaffer</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Srinivasan Keshav/" type="external">Srinivasan Keshav</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Miranda Lam/" type="external">Miranda Lam</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                      </fr:author>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Robin Message/" type="external">Robin Message</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2023</fr:year>
                    </fr:date>
                    <fr:title text="Abstract">Abstract</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p><![CDATA[This draft document describes the methodology developed by the Cambridge Center for Carbon Credits (4C) for estimating the number of credits to be issued to a project in the tropical moist forest (TMF) biome. It expands on the methodology outlined in (Swinfield and Balmford, 2023). We welcome comments and suggestions in the associated online document at https://tinyurl.com/cowgreport.]]></html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
      </fr:mainmatter>
    </fr:tree>
    <fr:tree show-metadata="false" expanded="false" toc="false">
      <fr:frontmatter>
        <fr:authors />
        <fr:uri>https://patrick.sirref.org/weeklies/</fr:uri>
        <fr:display-uri>weeklies</fr:display-uri>
        <fr:route>/weeklies/</fr:route>
        <fr:title text="Patrick Ferris' Weeklies">Patrick Ferris' Weeklies</fr:title>
      </fr:frontmatter>
      <fr:mainmatter>
        <html:p><![CDATA[A collection of personal weekly(ish) updates about my work. If you want a more specific]]>  feed of OCaml-related work, please see <fr:link href="https://patrick.sirref.org/ocaml-weeklies/" type="external">OCaml weeklies</fr:link>. My personal weeklies will include the OCaml specific ones too.</html:p>
        <html:p><fr:link href="/weeklies/atom.xml" type="external">An RSS feed is available</fr:link>.</html:p>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick/" type="external">Patrick</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>11</fr:month>
              <fr:day>24</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/weekly-2025-w49/</fr:uri>
            <fr:display-uri>weekly-2025-w49</fr:display-uri>
            <fr:route>/weekly-2025-w49/</fr:route>
            <fr:title text="Data Provenance in Shelter">Data Provenance in Shelter</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>A late update that stretches more than a week...</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://shelter.sirref.org/Patrick Ferris/" type="external">https://shelter.sirref.org/Patrick Ferris/</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>12</fr:month>
                  <fr:day>9</fr:day>
                </fr:date>
                <fr:uri>https://shelter.sirref.org/shelter-log-002/</fr:uri>
                <fr:display-uri>https://shelter.sirref.org/shelter-log-002/</fr:display-uri>
                <fr:route>https://shelter.sirref.org/shelter-log-002/</fr:route>
                <fr:title text="@ How?">@ How?</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>A quick update on a new feature that was added recently, the <html:code>@ how</html:code> <fr:link href="https://shelter.sirref.org/shelter-0002/" type="external">meta-command</fr:link>.</html:p>
                <html:p><![CDATA[One of the issues facing any exploratory programmer (or indeed anybody]]>  <![CDATA[returning to a project) is the]]> <html:em>provenance</html:em> of a given file. How that file came to be and who and what processes have interacted with it since.</html:p>
                <html:p>Shelter now has a command for asking exactly that of any given file in the system.</html:p>
                <html:pre><![CDATA[echo hello > hello.txt
echo world > world.txt
cat world.txt > hello.txt
@ how hello.txt]]></html:pre>
                <html:p>The previous snippet of shell script will output:</html:p>
                <html:pre><![CDATA[Ran echo hello > hello.txt
Ran cat world.txt > hello.txt (read: "world.txt")]]></html:pre>
                <html:p>There are plenty of optimisations and improvements to make, but this is a nice first step to showing the kinds of feature you get when programming with Shelter.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>12</fr:month>
                  <fr:day>9</fr:day>
                </fr:date>
                <fr:uri>https://patrick.sirref.org/ocaml-roundup-november-2025/</fr:uri>
                <fr:display-uri>ocaml-roundup-november-2025</fr:display-uri>
                <fr:route>/ocaml-roundup-november-2025/</fr:route>
                <fr:title text="OCaml Roundup: November 2025">OCaml Roundup: November 2025</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>A roundup of <html:em>some</html:em> of my OCaml activity this month!</html:p>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>12</fr:month>
                      <fr:day>9</fr:day>
                    </fr:date>
                    <fr:title text="Ppxlib Updates">Ppxlib Updates</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html: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.</html:p>
                    <fr:tree show-metadata="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>12</fr:month>
                          <fr:day>9</fr:day>
                        </fr:date>
                        <fr:uri>https://patrick.sirref.org/ppxlib-5.5-support</fr:uri>
                        <fr:display-uri>ppxlib-5.5-support</fr:display-uri>
                        <fr:route>/ppxlib-5.5-support</fr:route>
                        <fr:title text="Initial OCaml 5.5 Support ">Initial OCaml 5.5 Support </fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>We <fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/606" type="external">recently merged 5.5 support</fr:link> into our <html:code>main</html:code><![CDATA[ branch (thanks to Nathan for the review). It cast a light on]]>  some new features coming to OCaml including the ability to define <html:em>any</html:em> structure <html:em>locally</html:em>. Most OCaml programmers will be familiar with things like <![CDATA[local opens (e.g.]]> <html:code>let open M in</html:code><![CDATA[). This has now been extended to include any]]>  <![CDATA[structure item (more or less, you cannot nest value bindings).]]></html:p>
                        <html:p><html:em>External</html:em> types have also landed, bringing with them a new "type kind" in the AST. You can <fr:link href="https://github.com/gasche/ocaml/blob/44e69a0eb6d57ea2e7dc14c6ea4bac4a260a2d5b/manual/src/refman/extensions/externaltypes.etex" type="external">read about them in the manual</fr:link>.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>12</fr:month>
                          <fr:day>9</fr:day>
                        </fr:date>
                        <fr:title text="Bug Fixes for Attribute Rewriters">Bug Fixes for Attribute Rewriters</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>There <fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/613" type="external">was a bug</fr:link> in the error handling for attribute rewriters -- a relatively new feature to have been added to ppxlib.</html:p>
                        <html:p>In some places, ppxlib makes use of a <html:code>With_error.t</html:code> monad. Unlike the <html:code>Result.t</html:code> monad, <html:code>With_error.t</html:code> allows you to <html:em>collect</html: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.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>12</fr:month>
                          <fr:day>9</fr:day>
                        </fr:date>
                        <fr:title text="Value binding constraints in ppxlib">Value binding constraints in ppxlib</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>I spent a good few hours understanding why the <fr:link href="https://github.com/mirage/repr/pull/110" type="external">CI tests in my PR to mirage/repr</fr:link> were still failing. It turns out, the bug, is fairly simple to reproduce. Consider the following OCaml code:</html:p>
                        <html:pre class="hilite">
                          <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">g</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">int</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">1</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                        </html:pre>
                        <html: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.</html:p>
                        <html:p>The first is using the <html:code>Ppat_constraint</html:code> AST node which allows you to attach a type constraint to any pattern.</html:p>
                        <html:pre class="hilite">
                          <html:code><html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Ppat_constraint</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">of</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pattern</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">*</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">core_type</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-comment-block"><![CDATA[(*]]> </html:span><html:span class="ocaml-comment-block"><![CDATA[ (P : T)]]> </html:span><html:span class="ocaml-comment-block"><![CDATA[*)]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                        </html:pre>
                        <html:p><![CDATA[This tends to be used for things like function arguments (e.g.]]> <html:code><![CDATA[fun (x : int) -> x + 1]]></html:code><![CDATA[).]]>  So it doesn't quite capture what we want for this binding constraint.</html:p>
                        <html:p>On older OCaml compilers, <html:code>let g : int = 1</html:code> also includes a <html:code>Pexp_constraint</html: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.</html:p>
                        <html:pre class="hilite">
                          <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">g</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">x</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">int</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">x</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">+</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">1</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                        </html:pre>
                        <html:p>In this example, we no longer parse a <html:code>Ppat_constraint</html:code> and instead this is treated as syntactic sugar for:</html:p>
                        <html:pre class="hilite">
                          <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">g</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">x</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">x</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">+</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">int</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                        </html:pre>
                        <html:p>In <fr:link href="https://github.com/ocaml/ocaml/pull/12119" type="external">OCaml 5.1 a new field for value bindings was added</fr:link> allowing type constraints to be tracked directly in the bindings themselves.</html:p>
                        <html:pre class="hilite">
                          <html:code><html:span class="ocaml-keyword-other">and</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">value_binding</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source"><![CDATA[{]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source">pvb_pat</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">pattern</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source">pvb_expr</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">expression</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source">pvb_constraint</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">poly_constraint</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">option</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source">pvb_attributes</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">attributes</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source">pvb_loc</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Location</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source"><![CDATA[}]]> </html:span><html:span class="ocaml-comment-doc"><![CDATA[(**]]> </html:span><html:span class="ocaml-comment-doc"><![CDATA[ [let pat : type_constraint = exp]]]> </html:span><html:span class="ocaml-comment-doc"><![CDATA[*)]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                        </html:pre>
                        <html:p><![CDATA[Our type constraint (]]> <html:code>: int</html:code><![CDATA[) can be recorded in the]]> <html:code>pvb_constraint</html: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 <html:em>before</html:em> 5.1!</html:p>
                        <html:p>So what was the bug? The author's of <html:code>repr</html:code> had added some value bindings to circumvent some "unused value warnings" in OCaml. They choose to write these bindings like:</html:p>
                        <html:pre class="hilite">
                          <html:code><html:span class="ocaml-keyword-other">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language">_</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">int</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">1</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                        </html:pre>
                        <html: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 <html:em>forces</html:em> the AST representation to be a single <html:code>Ppat_constraint</html:code> node regardless of the current compiler version. No <html:code>Pexp_constraint</html:code> and no <html:code>pvb_constraint</html:code>.</html:p>
                        <html:p>However, using ppxlib with a compiler less than 5.1 meant that this did not roundtrip cleanly. Instead, the value <html:em>after</html:em> passing through ppxlib's migrations was:</html:p>
                        <html:pre class="hilite">
                          <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">_</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">int</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">1</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                        </html:pre>
                        <html:p>After bottoming out at the issue, I discovered we <fr:link href="https://github.com/ocaml-ppx/ppxlib/blob/22778658345fce526e6146da188cdc2d6d2e5286/test/501_migrations/reverse_migrations.t#L142" type="external">already had a test case for this in ppxlib</fr:link>! Whatsomore, <html:code>ocamlformat.0.20.0</html:code><![CDATA[ (which]]> <html:code>repr</html:code><![CDATA[ was still using) actually]]>  transforms instances of <html:code>let x : t = ...</html:code> into <html:code><![CDATA[let (x : t) = ...]]></html:code>! This limitation does not seem inherent to the parsetree, the printer or the migrations. But I have <![CDATA[asked the (very kind and friendly) previous maintainers about these changes.]]></html:p>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>12</fr:month>
                      <fr:day>9</fr:day>
                    </fr:date>
                    <fr:title text="Outreachy">Outreachy</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>December 8th 2025 marks the start of the next round of Outreachy. I have been preparing some issues for <fr:link href="https://github.com/geocaml/ocaml-tiff" type="external">geocaml/ocaml-tiff</fr:link> and I am excited to get started with <fr:link href="https://github.com/giftcup" type="external">Tambe Salome</fr:link>!</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>12</fr:month>
                      <fr:day>9</fr:day>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/graft-and-bib-update/</fr:uri>
                    <fr:display-uri>graft-and-bib-update</fr:display-uri>
                    <fr:route>/graft-and-bib-update/</fr:route>
                    <fr:title text="Graft and Bib ">Graft and Bib </fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>I spent some time at the start of the month updating and fixing <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">Graft</fr:link> and <fr:link href="/bib/" title="Bib" uri="https://patrick.sirref.org/bib/" display-uri="bib" type="local">Bib</fr:link>.</html:p>
                    <html:p>I added <fr:link href="https://graft.sirref.org/named-subtrees" type="external">named subtrees</fr:link> to the markdown syntax. This allows users to create subtrees with headings that are also externally linkable.</html:p>
                    <html:p>With some more bug fixing, I hope to release both libraries before the new year!</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>11</fr:month>
              <fr:day>15</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/weekly-2025-w46/</fr:uri>
            <fr:display-uri>weekly-2025-w46</fr:display-uri>
            <fr:route>/weekly-2025-w46/</fr:route>
            <fr:title text="Shelter imports">Shelter imports</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>Most of this week was spent fixing bugs in <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> in an attempt to get it ready to run the <fr:link href="https://github.com/quantifyearth/LIFE" type="external">LIFE</fr:link> pipeline.</html:p>
            <html:p>To do so, <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> requires a mechanism by which to pull in files from the outside world. That could be configuration files, source trees, data etc. For now, this has taken the form of a crude <html:code>@ import</html:code> statement. In true <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link> fashion, I have transcluded the <html:em>foreign</html:em> tree from my <fr:link href="https://shelter.sirref.org/logs" type="external">Shelter logs</fr:link>.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://shelter.sirref.org/Shelter Programmers/" type="external">https://shelter.sirref.org/Shelter Programmers/</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>11</fr:month>
                  <fr:day>16</fr:day>
                </fr:date>
                <fr:uri>https://shelter.sirref.org/shelter-log-001/</fr:uri>
                <fr:display-uri>https://shelter.sirref.org/shelter-log-001/</fr:display-uri>
                <fr:route>https://shelter.sirref.org/shelter-log-001/</fr:route>
                <fr:title text="Import statements">Import statements</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Welcome to the first <fr:link href="https://shelter.sirref.org/index/" type="external">Shelter</fr:link> log! In this log I will explain the work I have been doing to add an <html:code>@ import</html:code> <fr:link href="https://shelter.sirref.org/shelter-0002/" type="external">meta-command</fr:link>.</html:p>
                <html:p>The syntax thus far is relatively straightforward.</html:p>
                <html:pre><![CDATA[@ import --name=<optional-name> <URI> <DST>]]></html:pre>
                <html:p>There are a few key principles underlying <html:code>@ import</html:code>.</html:p>
                <html:ol>
                  <html:li>
                    <html:p>It should be at least as expressive as Docker's <html:code>COPY ...</html:code> command.</html:p>
                  </html:li>
                  <html:li>
                    <html:p>It should deal with a wider variety of import sources. In addition to local <![CDATA[file paths this could be data over HTTP (]]> <html:code>https://</html:code><![CDATA[), git repositories, zip]]>  archives over ssh etc.</html:p>
                  </html:li>
                  <html:li>
                    <html:p>Imports, where possible, should be catalogued and shared across <fr:link href="https://shelter.sirref.org/at-session/" type="external">sessions</fr:link>.</html:p>
                  </html:li>
                </html:ol>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://shelter.sirref.org/Shelter Programmers/" type="external">https://shelter.sirref.org/Shelter Programmers/</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>11</fr:month>
                      <fr:day>16</fr:day>
                    </fr:date>
                    <fr:title text="URIs as Sources">URIs as Sources</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p><![CDATA[Point (1) can be dealt with by point (2). Indeed, that latest development]]>  branch already allows users to import local files and directories into their session. For example:</html:p>
                    <html:pre><![CDATA[@ import shelter.opam .
opam install . --deps-only --with-test]]></html:pre>
                    <html:p>By allowing arbitrary URIs in the import command, we hope to force users away from downloading data via <html:code>curl</html:code> or python scripts. Lifting these side-effectful imports into <fr:link href="https://shelter.sirref.org/shelter/" type="external">Shelter</fr:link> allows us to manage the data in a much cleaner fashion.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://shelter.sirref.org/Shelter Programmers/" type="external">https://shelter.sirref.org/Shelter Programmers/</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>11</fr:month>
                      <fr:day>16</fr:day>
                    </fr:date>
                    <fr:title text="Scripts as Sources">Scripts as Sources</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>One idea I had was to allow users to invoke scripts as there "import source". Something like:</html:p>
                    <html:pre><![CDATA[@ import -- python download_gedi_data.py]]></html:pre>
                    <html:p>And using the same <fr:link href="https://shelter.sirref.org/shelter-tracing/" type="external">eBPF tracing</fr:link> we use during normal execution we can capture a fairly good idea of the tools and files needed to perform an import.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://shelter.sirref.org/Shelter Programmers/" type="external">https://shelter.sirref.org/Shelter Programmers/</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>11</fr:month>
                      <fr:day>16</fr:day>
                    </fr:date>
                    <fr:title text="Sharing Imports">Sharing Imports</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>One example of better data management is that <fr:link href="https://shelter.sirref.org/shelter/" type="external">Shelter</fr:link> imports can be <![CDATA[explicitly shared across sessions via the naming mechanism (also by hash).]]></html:p>
                    <html:p>When a user imports some data, they can optionally name that piece of data. For example:</html:p>
                    <html:pre><![CDATA[@ import
  --name=belfast-trees \
  https://www.belfastcity.gov.uk/getmedia/262a1f01-f219-4780-835e-7a833bdd1e1c/odTrees.csv \
  /home]]></html:pre>
                    <html:p><fr:link href="https://shelter.sirref.org/shelter/" type="external">Shelter</fr:link> stores that away and makes a link between the name, the URI and the underlying data. A user may then import the same piece of data into a different session by simply writing:</html:p>
                    <html:pre><![CDATA[@ import --name=belfast-trees /var/lib]]></html:pre>
                    <html:p><![CDATA[The same data is shared (read-only) into this session. By asking for the user's]]>  intent via the naming scheme, it makes it possible to then <html:em>version</html:em> the data and have a means by which to update said data, one could imagine:</html:p>
                    <html:pre><![CDATA[@ update --name=belfast-trees]]></html:pre>
                    <html:p>Which will retry the original URI and see if the data has changed, or if it has not. There is an implicit versioning number that users can specify in the name should they choose to.</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>11</fr:month>
                  <fr:day>15</fr:day>
                </fr:date>
                <fr:uri>https://patrick.sirref.org/eio-cap-debugging/</fr:uri>
                <fr:display-uri>eio-cap-debugging</fr:display-uri>
                <fr:route>/eio-cap-debugging/</fr:route>
                <fr:title text="Eio Debugging ">Eio Debugging </fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>One of the promises of <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link>'s capability model is an improved debugging experience. Your program must be designed in such a way as to make resources explicit. If you have a <html:code>load_config</html:code> function, more than likely it will need access to the file-system.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword-other">val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">load_config</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language">_</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Eio</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Path</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Config</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-comment-doc"><![CDATA[(**]]> </html:span><html:span class="ocaml-comment-doc"><![CDATA[ [load_config path] loads a configuration from [path].]]> </html:span><html:span class="ocaml-comment-doc"><![CDATA[*)]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html:p>Once all of your resources are explicit and threaded through your program, it <![CDATA[becomes much easier to swap out one resource for another (provided they have]]>  <![CDATA[the same interface).]]></html:p>
                <html:p>This week I was trying to get the <fr:link href="https://github.com/quantifyearth/LIFE" type="external">LIFE</fr:link> pipeline running in <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">shelter</fr:link>. Part of that involves pulling the <fr:link href="ghcr.io/osgeo/gdal:ubuntu-small-3.11.4" type="external">appropriate geospatial container image</fr:link>, but my code was terrifically broken, failing with what looked to me with a Docker error.</html:p>
                <html:p>With only this clue, I knew that it was probably in the execution of some command in a child process, but which one? To trace this quickly, I could plug in a slightly different instance of the <html:code>_ Eio.Process.mgr</html:code> capability. Essentially unchanged from the one provided by the unix backend except that it would also print to stderr the command it was trying to run!</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">debug_process_mgr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">mgr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-storage-type">'a</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Eio_unix</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Process</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">mgr</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-storage-type">'a</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Eio_unix</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Process</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">mgr</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword">module</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">D</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">struct</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword-other">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">unit</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">spawn_unix</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-unit"><![CDATA[()]]> </html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">sw</html:span><html:span class="ocaml-source"> ?</html:span><html:span class="ocaml-source">cwd</html:span><html:span class="ocaml-source"> ?</html:span><html:span class="ocaml-source">pgid</html:span><html:span class="ocaml-source"> ?</html:span><html:span class="ocaml-source">uid</html:span><html:span class="ocaml-source"> ?</html:span><html:span class="ocaml-source">gid</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">env</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">fds</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">executable</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">args</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-constant-language-capital-identifier">Eio</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">traceln</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">Spawning subprocess... </html:span><html:span class="ocaml-constant-character-printf"><![CDATA[%a]]> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Fmt</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">list</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">string</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">args</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-constant-language-capital-identifier">Eio_unix</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Process</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">spawn_unix</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">sw</html:span><html:span class="ocaml-source"> ?</html:span><html:span class="ocaml-source">cwd</html:span><html:span class="ocaml-source"> ?</html:span><html:span class="ocaml-source">pgid</html:span><html:span class="ocaml-source"> ?</html:span><html:span class="ocaml-source">uid</html:span><html:span class="ocaml-source"> ?</html:span><html:span class="ocaml-source">gid</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">mgr</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">env</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">fds</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">        ~</html:span><html:span class="ocaml-source">executable</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">args</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">end</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">in</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword">module</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">V</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Eio_unix</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Process</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Make_mgr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">D</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">in</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-constant-language-capital-identifier">Eio</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Resource</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">T</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-unit"><![CDATA[()]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Eio_unix</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Process</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Pi</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">mgr_unix</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-keyword-other">module</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">V</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html:p>Whist there is a fair amount of jumping through first-class-module-shaped hoops here, all I am doing is rewrapping an existing "method" to a spawn a unix child process. Then using <fr:link href="https://github.com/ocaml-multicore/eio/pull/823" type="external">this helper function</fr:link>, I can push that into my <fr:link href="https://patrick.sirref.org/standard environment/" type="external">standard environment</fr:link>.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">env</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-constant-language-capital-identifier">Eio_unix</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Stdenv</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">with_env</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  ~</html:span><html:span class="ocaml-source">process_mgr</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">debug_process_mgr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">env</html:span><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source">process_mgr</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source">env</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">in</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-constant-language-capital-identifier">Shelter</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">main</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">config</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">env</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-keyword-operator">&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language">_</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Shelter</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">env</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">dir</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">cmd_file</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html:p>And sure enough I was querying for the Docker user <html:em>before</html:em> pulling the image! I hadn't run into this, as for the last while I have been using <html:code>alpine</html:code> and <html:code>debian</html:code> images that already exists locally.</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>11</fr:month>
              <fr:day>10</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/weekly-2025-w45/</fr:uri>
            <fr:display-uri>weekly-2025-w45</fr:display-uri>
            <fr:route>/weekly-2025-w45/</fr:route>
            <fr:title text="Taking stock &amp; Graft updates">Taking stock &amp; Graft updates</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>I ended up working on a real mix of things last week. I managed to get two large posts uploaded to this site: an <fr:link href="/icfp-2025/" title="ICFP 2025" uri="https://patrick.sirref.org/icfp-2025/" display-uri="icfp-2025" type="local">ICFP recap</fr:link> and a deeper-dive into the random bits of <fr:link href="/ocaml-roundup-october-2025/" title="OCaml Roundup: October 2025" uri="https://patrick.sirref.org/ocaml-roundup-october-2025/" display-uri="ocaml-roundup-october-2025" type="local">OCaml hacking</fr:link>. This was pretty useful in terms of taking stock of where I was at, I always find post-conference, I'm a little lost. The conversations and ideas from ICFP are simultaneously exciting but also pretty inactionable.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>11</fr:month>
                  <fr:day>10</fr:day>
                </fr:date>
                <fr:uri>https://patrick.sirref.org/graft-updates/</fr:uri>
                <fr:display-uri>graft-updates</fr:display-uri>
                <fr:route>/graft-updates/</fr:route>
                <fr:title text="Graft Updates ">Graft Updates </fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>It would seem that there is a potential <html:em>second</html:em> user of <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">Graft</fr:link>! A great source of motivation for some tidying and feature implementing. At the end of last week I fixed some little bugs in <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">Graft</fr:link><![CDATA[ and (more importantly) allowed]]>  <fr:link href="https://graft.sirref.org/named-subtrees" type="external">users to name their subtrees</fr:link>. Upstream <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">Graft</fr:link> also now pins and uses my <fr:link href="/bib/" title="Bib" uri="https://patrick.sirref.org/bib/" display-uri="bib" type="local">Bibtex implementation</fr:link>.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>11</fr:month>
                  <fr:day>10</fr:day>
                </fr:date>
                <fr:title text="OCaml Geotessera">OCaml Geotessera</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>As I discussed in my <fr:link href="/ocaml-roundup-october-2025/" title="OCaml Roundup: October 2025" uri="https://patrick.sirref.org/ocaml-roundup-october-2025/" display-uri="ocaml-roundup-october-2025" type="local">OCaml roundup</fr:link>, I spent a bit of time polishing the <fr:link href="https://tangled.org/@patrick.sirref.org/ocaml-geotessera" type="external">OCaml geotessera code</fr:link>. In particular this meant starting to handle low-level geospatial transformations allowing users to project latitudes and longitudes into the rows and columns of their raster data. I feel like I'm stumbling onto a path <fr:link href="/mdales/" title="Michael W. Dales" uri="https://patrick.sirref.org/mdales/" display-uri="mdales" type="local">Michael</fr:link> has carved out with <fr:link href="https://github.com/quantifyearth/yirgacheffe/" type="external">Yirgacheffe</fr:link>. I'm following <fr:link href="https://digitalflapjack.com/weeknotes/2025-11-10/" type="external">along with his work excitedly</fr:link> and we had a good catch-up last week discussing how libraries should handle things like automatic, numeric precision conversion.</html:p>
                <html:p>As a fully paid-up member of the static types fan club, I'm often evangelising the benefits of types. However, I hit a little quirk of the <fr:link href="https://ocaml.org/p/nx" type="external">Nx</fr:link><![CDATA[ library in OCaml (a numpy equivalent). Take a look at this]]>  sum function:</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">sum</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">nx</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nx</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">sum</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">nx</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">|&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nx</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">item</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-list"><![CDATA[[]]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">sum</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-storage-type">'a</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-storage-type">'b</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nx</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-storage-type">'a</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">arr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nx</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">create</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nx</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">int8</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[[|]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">2</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[|]]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[[|]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">64</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">64</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[|]]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">arr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-support-type">int</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Bigarray</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">int8_signed_elt</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Nx</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">sum</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">arr</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-operator">-</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">int</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-</html:span><html:span class="ocaml-constant-numeric-decimal-integer">128</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html:p>Even though <html:code>sum</html:code> takes an <html:code><![CDATA[('a, 'b) Nx.t]]></html:code> array that stores elements with representation <html:code>'b</html:code> and allows you to read/write to the elements with OCaml values of type <html:code>'a</html:code>, the <html:code>sum</html:code> function performs the calculation in the world of the <html:code>'b</html:code><![CDATA[ representation type (here signed 8-bit integers). So we get an]]>  overflow! Perhaps not too surprising but easy to overlook! The moral of the story is that we still need to be careful in the OCaml world too.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>11</fr:month>
                  <fr:day>10</fr:day>
                </fr:date>
                <fr:title text="Shelter">Shelter</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I did a little cleaning up of the <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> code too. I noticed a few bugs from the demos I did at <fr:link href="/icfp-2025/" title="ICFP 2025" uri="https://patrick.sirref.org/icfp-2025/" display-uri="icfp-2025" type="local">ICFP</fr:link>. Most were pretty straight-forward to fix, and the test-suite is now checking <fr:link href="https://github.com/fn06/shelter/blob/main/test/fixtures/for.shl" type="external">parallel for-loops</fr:link> and <fr:link href="https://github.com/fn06/shelter/blob/main/test/fixtures/if.shl" type="external">conditional execution</fr:link> are working.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>11</fr:month>
                  <fr:day>10</fr:day>
                </fr:date>
                <fr:title text="This week">This week</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I hope to get a few things done this week:</html:p>
                <html:ul>
                  <html:li>
                    <html:p>Run some part of the <fr:link href="https://github.com/quantifyearth/LIFE" type="external">LIFE</fr:link> pipeline through <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link>.</html:p>
                  </html:li>
                  <html:li>
                    <html:p>Deploy the <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> daemon allowing other people to connect and take it for a spin.</html:p>
                  </html:li>
                  <html:li>
                    <html:p>Spend some time writing and reading, pulling ideas together rather than always writing code!</html:p>
                  </html:li>
                  <html:li>
                    <html:p>I have a slightly harebrained scheme that combines <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link>, atproto, <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link><![CDATA[, capn(proto/web) and webcomponents... I want to see if I can]]>  pull that together.</html:p>
                  </html:li>
                </html:ul>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>7</fr:month>
              <fr:day>18</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/weekly-2025-07-18/</fr:uri>
            <fr:display-uri>weekly-2025-07-18</fr:display-uri>
            <fr:route>/weekly-2025-07-18/</fr:route>
            <fr:title text="Back to shelter">Back to shelter</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>7</fr:month>
                  <fr:day>18</fr:day>
                </fr:date>
                <fr:title text="Capnproto Interface to Shelter">Capnproto Interface to Shelter</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I spent some time this week thinking about decoupling <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link>'s builds from the CLI tool. This would allow users to connect to a remote daemon to build and store their sessions, opening up the possibility of using <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> on Windows and macOS.</html:p>
                <html:p>The design so far keeps the metadata local, in an <fr:link href="https://irmin.org/" type="external">Irmin</fr:link> database. I will probably then augment the stored information with some kind of unique daemon identifier to know where the actual data is.</html:p>
                <html:p>This is all still quite fresh, and I will have more by the end of next week.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>7</fr:month>
                  <fr:day>18</fr:day>
                </fr:date>
                <fr:title text="OCaml-related Things">OCaml-related Things</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Something I decided to do last week, was to make a clearer delineation between my OCaml work and research. That line is not always very distinct, but I have split of a separate set of <fr:link href="https://patrick.sirref.org/ocaml-weeklies/" type="external">weeklies for OCaml related things</fr:link>.</html:p>
                <html:p>Fear not, the <fr:link href="https://patrick.sirref.org/ocaml-weeklies/" type="external">OCaml weeklies</fr:link> are a subset of these weeklies and so I will, when I remember, transclude them for you.</html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>7</fr:month>
                      <fr:day>15</fr:day>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/ocaml-weekly-2025-w29/</fr:uri>
                    <fr:display-uri>ocaml-weekly-2025-w29</fr:display-uri>
                    <fr:route>/ocaml-weekly-2025-w29/</fr:route>
                    <fr:title text="OCaml Weekly 2025 w29">OCaml Weekly 2025 w29</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>7</fr:month>
                          <fr:day>15</fr:day>
                        </fr:date>
                        <fr:title text="Ppxlib">Ppxlib</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>I met with <fr:link href="/nathanreb/" title="Nathan Rebours" uri="https://patrick.sirref.org/nathanreb/" display-uri="nathanreb" type="local">Nathan</fr:link> this week to discuss future plans for <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link>. The current state of affairs is that <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> is becoming unmaintainable. This is primarily a knock-on effect from changes being made to <![CDATA[OCaml's parsetree (e.g. labelled tuples being added in 5.4).]]>  <fr:link href="/nathanreb/" title="Nathan Rebours" uri="https://patrick.sirref.org/nathanreb/" display-uri="nathanreb" type="local">Nathan</fr:link> has a plan that will provide two key properties.</html:p>
                        <html:ol>
                          <html:li>
                            <html:p>Migrations, which allow old compilers to be used with new <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> releases, will be more compatible. For example, we will be able to migrate new features downwards and back up without raising an error.</html:p>
                          </html:li>
                          <html:li>
                            <html:p>Ppx authors will be able to use new features in an opt-in workflow, rather than <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link><![CDATA[ bumping the internal AST (like we did]]> <fr:link href="/ppxlib-5-2/" title="Bumping Ppxlib's AST to 5.2" uri="https://patrick.sirref.org/ppxlib-5-2/" display-uri="ppxlib-5-2" type="local">in ppxlib.0.36.0</fr:link><![CDATA[). This will reduce the maintenance burden]]>  significantly whilst still allowing users to write ppxes for new OCaml features.</html:p>
                          </html:li>
                        </html:ol>
                        <html:p>I also started looking into some older issues in <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> related to performance. This is work-in-progress, but I am trying to improve the performance of some passes done by <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link>. To better understand what was making <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> slow, I wanted to use <fr:link href="https://github.com/tarides/runtime_events_tools" type="external">runtime_events_tools</fr:link> but I was dismayed to see it wanting to install over 100 packages! I <fr:link href="https://github.com/tarides/runtime_events_tools/pull/57" type="external">opened a PR to reduce the number of packages</fr:link>. 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.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>7</fr:month>
                          <fr:day>15</fr:day>
                        </fr:date>
                        <fr:title text="Outreachy">Outreachy</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>In <fr:link href="/outreachy/" title="Outreachy" uri="https://patrick.sirref.org/outreachy/" display-uri="outreachy" type="local">Outreachy</fr:link> 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 <fr:link href="/mdales/" title="Michael W. Dales" uri="https://patrick.sirref.org/mdales/" display-uri="mdales" type="local">Michael</fr:link> and <fr:link href="https://github.com/gridbugs" type="external">Steve</fr:link> have put in so far to make this a very successful Outreachy round for OCaml.</html:p>
                        <html:p>In sadder news, an email was shared with all <fr:link href="/outreachy/" title="Outreachy" uri="https://patrick.sirref.org/outreachy/" display-uri="outreachy" type="local">Outreachy</fr:link> 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.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>7</fr:month>
                          <fr:day>15</fr:day>
                        </fr:date>
                        <fr:title text="Graft">Graft</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>With the release of <fr:link href="https://patrick.sirref.org/Forester/" type="external">Forester.5.0</fr:link>, I made a plan to make a release of <fr:link href="https://patrick.sirref.org/Graft/" type="external">Graft.0.1</fr:link>. Unfortunately this is blocked by a new release of <fr:link href="https://github.com/ocaml/opam-repository/pull/28172" type="external">hilite</fr:link>, a tool I built for doing build-time syntax highlighting for OCaml code. This powers the syntax highlighting on <fr:link href="https://ocaml.org/" type="external">ocaml.org</fr:link>.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>6</fr:month>
              <fr:day>30</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/rest-of-monthly-2025-06/</fr:uri>
            <fr:display-uri>rest-of-monthly-2025-06</fr:display-uri>
            <fr:route>/rest-of-monthly-2025-06/</fr:route>
            <fr:title text="PhD Work and Scientific Programming">PhD Work and Scientific Programming</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>I have been away on holidays. Some of that was spent hiking in the Massif de Calanques in Marseille, unfortunately this week <fr:link href="https://www.theguardian.com/world/2025/jul/08/marseille-airport-cancels-all-flights-as-wildfire-encroaches-on-city" type="external">they were on fire</fr:link>. Anyway, this "weekly" fills in the blanks for the rest of June 2025.</html:p>
            <html:p style="text-align: center">
  <html:img width="320" alt="A Calanque just outside of Marseille, a canyon-like structure of calcified stone on the edge of the Mediterranean." src="/bafkrmigalfmuwbf6l6lpj5wbkmxz25qrwtoe536sjogt42rhagtorfyu54.jpg" />
</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>6</fr:month>
                  <fr:day>30</fr:day>
                </fr:date>
                <fr:title text="Revisiting hazel_of_ocaml">Revisiting <fr:link href="/hazel_of_ocaml/" title="hazel_of_ocaml" uri="https://patrick.sirref.org/hazel_of_ocaml/" display-uri="hazel_of_ocaml" type="local">hazel_of_ocaml</fr:link></fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I spent some time thinking and writing about <fr:link href="/hazel_of_ocaml/" title="hazel_of_ocaml" uri="https://patrick.sirref.org/hazel_of_ocaml/" display-uri="hazel_of_ocaml" type="local">hazel_of_ocaml</fr:link> and the benefits of OCaml as source language and Hazel as a target language. The stability of OCaml with a powerful type-system makes it very expressive.</html:p>
                <html:p>Hazel, on the other hand, is a hotbed of PL theory research. The typed holes, which are fully supported within the language, are particular powerful targets for a transpiler. They allow transpiler developers to incrementally support the language whilst still getting full feedback of their generated source code. Whilst it is a niche use-case, I thought it was an interesting point to note.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>6</fr:month>
                  <fr:day>30</fr:day>
                </fr:date>
                <fr:title text="A second year report">A second year report</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I wrote my second year report at the end of June. The process was a bit chaotic, but I think ultimately it was useful for clarifying some ideas I had rattling about in my head.</html:p>
                <html:p>Part of that was working on my <fr:link href="/publications/" title="Publications" uri="https://patrick.sirref.org/publications/" display-uri="publications" type="local">publications</fr:link> page and, through a conversation with <fr:link href="/anilmadhavapeddy/" title="Anil Madhavapeddy" uri="https://patrick.sirref.org/anilmadhavapeddy/" display-uri="anilmadhavapeddy" type="local">Anil</fr:link>, realising that my work on <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">Graft</fr:link> was in many ways a part of my own research.</html:p>
                <html:p>If you are interested, feel free to peruse both my <fr:link href="/bafkrmigsvxp4qr3tltethz6oznlgxkkx2dwjjkovjvhemi3k3ljpcydvu4.pdf" type="external">first year</fr:link> and <fr:link href="/bafkrmifhsh5b6mgzdomyfz6harcm2hrzxzxtupije7mqjiwxotupmz4bgy.pdf" type="external">second year</fr:link> reports. Take them with a pinch of salt! I think it is useful to be fairly open with this sort of thing when you can be. Maybe someone will find them useful.</html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>6</fr:month>
                      <fr:day>30</fr:day>
                    </fr:date>
                    <fr:title text="What is scientific programming?">What is <html:em>scientific programming</html:em>?</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>This question arose whilst writing my second year report. It got me thinking about how we distinguish scientific programming from other kinds of programming. I came across a paper by Tim Storer: <fr:link href="/storer2017bridging/" title="Bridging the chasm: A survey of software engineering practice in scientific programming" uri="https://patrick.sirref.org/storer2017bridging/" display-uri="storer2017bridging" type="local">Bridiging the chasm: A survey of Software Engineering Practice in Scientific Programming</fr:link>. I enjoyed a few aspects of this paper.</html:p>
                    <html:ul>
                      <html:li>
                        <html:p>Relating scientific programming to the scientific method so directly was pretty useful insight for me. <html:em>Falsifable hypotheses</html:em>, <html:em>repeatable experiments</html:em> and <html:em>reproducible results</html:em> when applied as characteristics of the computer stack <![CDATA[(e.g. OS, programming language, filesystem etc.) might be a useful lens to]]>  argue for better tools to enable this.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>The breadth of Storer's case-study analysis on how scientific programming has "gone wrong" is very good, if anyone needs a reference to draw on to help support their tools or research, this seems like a good index to use.</html:p>
                      </html:li>
                    </html:ul>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>6</fr:month>
                  <fr:day>30</fr:day>
                </fr:date>
                <fr:title text="Ppxlib">Ppxlib</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I was reminded again of the pain of helping maintain <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link>. We are coming to the conclusion, that in its current form, it is becoming unmaintainable. I took a stab at updating <fr:link href="https://github.com/aantron/bisect_ppx/pull/448" type="external">bisect_ppx</fr:link> to the latest ppxlib. With OCaml entering a potentially turbulent parsetree era, it might be time to take stock of this and propose some fillers to help. Nathan Rebours and I are meeting next week to discuss ideas he has to make parsetree migrations smooth sailing for all!</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>6</fr:month>
                  <fr:day>30</fr:day>
                </fr:date>
                <fr:title text="Geocaml">Geocaml</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Work on <fr:link href="/ocaml-tiff/" title="ocaml-tiff" uri="https://patrick.sirref.org/ocaml-tiff/" display-uri="ocaml-tiff" type="local">ocaml-tiff</fr:link> has stalled, which is totally fine. <fr:link href="/mdales/" title="Michael W. Dales" uri="https://patrick.sirref.org/mdales/" display-uri="mdales" type="local">Michael</fr:link> and I independently are working on other things and have obligations to fulfill. Maybe some day we'll carve out enough time together to push forward on this project, but not this week.</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>6</fr:month>
              <fr:day>2</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/weekly-2025-06-02/</fr:uri>
            <fr:display-uri>weekly-2025-06-02</fr:display-uri>
            <fr:route>/weekly-2025-06-02/</fr:route>
            <fr:title text="Forester as a Target Syntax">Forester as a Target Syntax</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>This week included some time finishing <fr:link href="/open-trace/" title="Opentrace" uri="https://patrick.sirref.org/open-trace/" display-uri="open-trace" type="local">opentrace</fr:link> and subsequently folding it into <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">shelter</fr:link>. I have been writing up some more of the draft paper for <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">shelter</fr:link> which I am excited to share in the near future.</html:p>
            <html:p>I revisited the <fr:link href="/vpnkit-upgrade/" title="Defunctorising VPNKit" uri="https://patrick.sirref.org/vpnkit-upgrade/" display-uri="vpnkit-upgrade" type="local">upgrading vpnkit</fr:link> PR and pushed some more fixes. I have been thinking, again, about the promise of a direct-style world for OCaml that just hasn't quite landed yet. <html:em>C'est la vie</html:em>.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>6</fr:month>
                  <fr:day>2</fr:day>
                </fr:date>
                <fr:title text="Forester and Graft">Forester and Graft</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I spent a bit of time finally pulling out my changes to <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link> to add markdown and bibtex support into a standalone tool: <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">graft</fr:link>.</html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>6</fr:month>
                      <fr:day>2</fr:day>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/graft/</fr:uri>
                    <fr:display-uri>graft</fr:display-uri>
                    <fr:route>/graft/</fr:route>
                    <fr:title text="Graft">Graft</fr:title>
                    <fr:meta name="external">https://github.com/patricoferris/graft</fr:meta>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Graft is a <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link> preprocessor.</html:p>
                    <html:p><![CDATA[It takes a forester (a directory of trees) written in a mixture of Markdown, Bibtex and]]>  <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link> syntax and produces a new forest completely written in <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link> syntax.</html:p>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>6</fr:month>
                          <fr:day>2</fr:day>
                        </fr:date>
                        <fr:title text="Usage">Usage</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p><html:code>graft</html:code> simply preprocesses a forest generating Forester trees from <html:code>.md</html:code>, <html:code>.bib</html:code> and <html:code>.tree</html:code> files. It will copy the structure of the input directory in the output directory.</html:p>
                        <html:pre class="hilite">
                          <html:code><html:span class="sh-source">$ graft preprocess --output=grafted-trees trees
</html:span>
<html:span class="sh-source">$ forester build
</html:span>
</html:code>
                        </html:pre>
                        <html:p>This assumes that you have updated your Forester <html:code>toml</html:code> file to put the <html:code>grafted-trees</html:code> directory as your source of trees.</html:p>
                        <html:pre><![CDATA[[forest]
trees = [ "grafted-trees" ]]]></html:pre>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>6</fr:month>
                          <fr:day>2</fr:day>
                        </fr:date>
                        <fr:title text="Example">Example</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>A typical "tree" might look something like</html:p>
                        <html:pre><![CDATA[---
title: Opentrace and Supervisions
date: 2025-05-26
author: Patrick Ferris
---

Over the past two weeks I have mainly split my time (amongst many things) developing [opentrace](open-trace)
and doing revision supervisions.

```forester
\put\transclude/numbered{false}
\transclude{open-trace}
```]]></html:pre>
                        <html:p>A few things to note:</html:p>
                        <html:ol>
                          <html:li>
                            <html:p>The <html:code>yaml</html:code> frontmatter allows you to add some of the metadata fields from Forester.</html:p>
                          </html:li>
                          <html:li>
                            <html:p>At any point in your markdown there is an escape hatch to Forester using a <html:code>forester</html:code> codeblock.</html:p>
                          </html:li>
                        </html:ol>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
                <html:p>It is very satisfying to find the separation of concerns works quite well. For a while I had been rebasing my development branch on <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link>. I was also worried about trying to get the code upstream as it pulled in many dependencies. It seems that I have a very workable solution. I welcome contributions to <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">graft</fr:link> including extra input formats. I am also considering extending the <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link> configuration to contain some <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">graft</fr:link> configuration for how it should generate <![CDATA[new trees (e.g. at the moment every entry in a bibtex file is given a new tree).]]></html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>6</fr:month>
                      <fr:day>2</fr:day>
                    </fr:date>
                    <fr:title text="Maths Support">Maths Support</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>As part of that process, <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">graft</fr:link> now supports Markdown KaTeX. For example:</html:p>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:uri>https://patrick.sirref.org/mrdts/</fr:uri>
                        <fr:display-uri>mrdts</fr:display-uri>
                        <fr:route>/mrdts/</fr:route>
                        <fr:title text="Mergeable Replicated Data Type Implementation">Mergeable Replicated Data Type Implementation</fr:title>
                        <fr:taxon>Definition</fr:taxon>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>A <html:strong><![CDATA[mergeable replicated data type (MRDT) implementation]]></html:strong> for a data type <fr:tex display="inline"><![CDATA[\tau ]]></fr:tex> is a tuple <fr:tex display="inline"><![CDATA[D_{\tau } = (\Sigma , \sigma _{0}, do, merge)]]></fr:tex> where:</html:p>
                        <html:ul>
                          <html:li>
                            <html:p><fr:tex display="inline"><![CDATA[\Sigma ]]></fr:tex> is the set of all possible states at a branch,</html:p>
                          </html:li>
                          <html:li>
                            <html:p><fr:tex display="inline"><![CDATA[\sigma _{0} \in  \Sigma ]]></fr:tex> is the initial state,</html:p>
                          </html:li>
                          <html:li>
                            <html:p><fr:tex display="inline"><![CDATA[do : Op_{\tau } \times  \Sigma  \times  Timestamp \rightarrow  \Sigma  \times  Val_{\tau }]]></fr:tex> implements every data type operation,</html:p>
                          </html:li>
                          <html:li>
                            <html:p><fr:tex display="inline"><![CDATA[merge : \Sigma  \times  \Sigma  \times  \Sigma  \rightarrow  \Sigma ]]></fr:tex> implements the <html:em>three-way merge strategy</html:em>.</html:p>
                          </html:li>
                        </html:ul>
                        <html:p><fr:link href="/kcrsk-mrdts-2022/" title="Certified mergeable replicated data types" uri="https://patrick.sirref.org/kcrsk-mrdts-2022/" display-uri="kcrsk-mrdts-2022" type="local">Definition 2.1 from "Certified Mergeable Replicated Data Types"</fr:link>.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>6</fr:month>
                  <fr:day>2</fr:day>
                </fr:date>
                <fr:title text="Revision Supervisions">Revision Supervisions</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I have been doing revision supervisions for <fr:link href="/discrete-maths/" title="Discrete Mathematics" uri="https://patrick.sirref.org/discrete-maths/" display-uri="discrete-maths" type="local">Discrete Maths</fr:link> and <fr:link href="https://patrick.sirref.org/focs.md" type="external">Foundations of Computer Science</fr:link>. I have also been marking Operating Systems past paper questions for the same group of first years.</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>5</fr:month>
              <fr:day>26</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/weekly-2025-05-26/</fr:uri>
            <fr:display-uri>weekly-2025-05-26</fr:display-uri>
            <fr:route>/weekly-2025-05-26/</fr:route>
            <fr:title text="Opentrace and Supervisions">Opentrace and Supervisions</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p><![CDATA[Over the past two weeks I have mainly split my time (amongst many things) developing]]> <fr:link href="/open-trace/" title="Opentrace" uri="https://patrick.sirref.org/open-trace/" display-uri="open-trace" type="local">opentrace</fr:link> and doing revision supervisions.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>5</fr:month>
                  <fr:day>19</fr:day>
                </fr:date>
                <fr:uri>https://patrick.sirref.org/open-trace/</fr:uri>
                <fr:display-uri>open-trace</fr:display-uri>
                <fr:route>/open-trace/</fr:route>
                <fr:title text="Opentrace">Opentrace</fr:title>
                <fr:meta name="external">https://tangled.sh/@patrick.sirref.org/opentrace</fr:meta>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Thanks to <fr:link href="https://github.com/koonwen/" type="external">Koonwen's</fr:link> excellent <fr:link href="https://github.com/koonwen/ocaml-libbpf" type="external">libbpf bindings in OCaml</fr:link>, I have been building a little tool called <html:code>opentrace</html:code> to make it easier to track an executable's inputs and outputs.</html:p>
                <html:p>This work was inspired my <fr:link href="/mdales/" title="Michael W. Dales" uri="https://patrick.sirref.org/mdales/" display-uri="mdales" type="local">Michael's</fr:link> self-proclaimed "gross hack": <fr:link href="https://github.com/quantifyearth/pyshark" type="external">pyshark</fr:link>. Whilst pyshark achieves its goals by injecting code into commonly used python objects and methods, <fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">opentrace</fr:link> uses <fr:link href="https://ebpf.io/" type="external">eBPF</fr:link><![CDATA[. By using a lower-level API (hooks in the kernel),]]> <fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">opentrace</fr:link> can remain programming language agnostic. However, less information is none about the user's intent compared to something like pyshark.</html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>5</fr:month>
                      <fr:day>19</fr:day>
                    </fr:date>
                    <fr:title text="Monitoring the System">Monitoring the System</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p><fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">opentrace</fr:link> has an <html:code>all</html:code> command that will trace the entire system.</html:p>
                    <html: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]]></html:pre>
                    <html:p>The <html:code>--flags=O_WRONLY</html:code> argument filters the events where the <html:code>O_WRONLY</html:code> flag was set in the call to <html:code>open</html:code>.</html:p>
                    <html:p><![CDATA[We also get the name of the current executable linked to the task (]]> <html:code>comm</html:code><![CDATA[). The]]> <html:code>-wrapped</html:code> is an artefact of using Nix.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>5</fr:month>
                      <fr:day>19</fr:day>
                    </fr:date>
                    <fr:title text="Tracing an Executable">Tracing an Executable</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>The primary use case for this tool is to inspect what files your program might be reading and writing.</html:p>
                    <html: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"]]></html:pre>
                    <html:p>The "flags" argument can specify a small boolean formula for checking the open flags of a particular event with <html:code>|</html:code><![CDATA[ (or),]]> <html:code>&amp;</html:code><![CDATA[ (and), and]]> <html:code>~</html:code><![CDATA[ (not).]]>  Parentheses can be used for precedence.</html:p>
                    <html:pre><![CDATA[$ sudo opentrace exec --flags="O_WRONLY|O_RDONLY" -- ocaml --version]]></html:pre>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>5</fr:month>
                      <fr:day>19</fr:day>
                    </fr:date>
                    <fr:title text="Spawning Subprocesses">Spawning Subprocesses</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>One feature <fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">opentrace</fr:link><![CDATA[ needs (in this proof-of-concept phase) is the ability to also trace subprocesses.]]></html:p>
                    <html:p><fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">opentrace</fr:link> 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, <fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">opentrace</fr:link><![CDATA[ creates a new control group (cgroup) and places the new process into that group.]]>  This gives <fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">opentrace</fr:link> a new identifier to track, namely the cgroup.</html:p>
                    <html:p>So consider the following program.</html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-keyword-other">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-unit"><![CDATA[()]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-constant-language-capital-identifier">Eio_posix</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">run</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">@@</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">fun</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">env</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-constant-language-capital-identifier">Eio</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Path</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">save</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">create</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-polymorphic-variant">`Or_truncate</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-octal-integer">0o664</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">env</html:span><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source">fs</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">/</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">hello.txt</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">hello</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-constant-language-capital-identifier">Eio</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-constant-language-capital-identifier">Process</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">run</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">env</html:span><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source">process_mgr</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">/bin/bash</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">-c</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">echo 'heya' &gt; heya.txt</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                    <html:p>It first creates a file using direct calls to functions like <html:code>openat</html:code>. Then it spawns a process which creates a new file called <html:code>heya.txt</html:code>. This happens in a separate process. However, with the <html:code>--cgroups</html:code> flag we can capture both interactions with the operating system.</html:p>
                    <html: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]]></html:pre>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>5</fr:month>
                          <fr:day>19</fr:day>
                        </fr:date>
                        <fr:title text="Eio's Process API">Eio's Process API</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>I have used the <html:code>Eio_unix</html:code> <fr:link href="https://ocaml.org/p/eio/latest/doc/Eio_unix/Process/index.html" type="external">fork action process API</fr:link> 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 <html:code>sudo</html:code>. When a user requests for a particular program to be executed and traced, <fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">opentrace</fr:link> spawns a process via the Eio Process API. <fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">Opentrace</fr:link> defines a few new so-called "fork actions", little fragments of C code that are run after the call to <html:code>fork</html:code><![CDATA[ (]]> <html:code>clone</html:code><![CDATA[).]]>  Most likely this ends with a call to <html:code>execve</html:code>, but other calls are possible for example <html:code>setuid</html:code> allowing <fr:link href="/opentrace/" title="Opentrace" uri="https://patrick.sirref.org/opentrace/" display-uri="opentrace" type="local">opentrace</fr:link> to change the user of the child process so it does not run as <html:code>root</html:code><![CDATA[. Similarly, this is where (if used) we create the cgroup and place the process]]>  into that group.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>5</fr:month>
                      <fr:day>19</fr:day>
                    </fr:date>
                    <fr:title text="Limitations: Io_uring">Limitations: Io_uring</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Whilst testing <html:code>opentrace</html:code> against some of the tools I use nearly daily, I noticed some events were being missed. I tried tracing <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">forester</fr:link>, and only the initial read of <html:code>forest.toml</html:code> was logged. It dawned on me that the reason for this was that <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">forester</fr:link><![CDATA[ (via]]> <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">eio</fr:link><![CDATA[) was using]]> <fr:link href="https://patrick.sirref.org/io_uring/" type="external">io_uring</fr:link> 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 <html:code>openat2</html:code>-style call!</html:p>
                    <html:p>This is not news to seasoned, Linux systems programmers. Io_uring <fr:link href="https://blog.0x74696d.com/posts/iouring-and-seccomp/" type="external">bypasses <html:code>SECCOMP</html:code> filters</fr:link> for exactly the same reasons.</html:p>
                    <html: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]]></html:pre>
                    <html:p>It is interesting to note two things here:</html:p>
                    <html:ol>
                      <html:li>
                        <html:p>We can tell that <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">forester</fr:link> reads the configuration file probably using something like <html:code>In_channel</html:code><![CDATA[ in OCaml (]]> <fr:link href="https://git.sr.ht/~jonsterling/ocaml-forester/tree/7f275290e211db2590b0d715d8fb47fc1de36550/item/lib/frontend/Config.ml#L22" type="external">it does</fr:link><![CDATA[).]]></html:p>
                      </html:li>
                      <html:li>
                        <html:p>It appears that Uring is performing IO in both worker threads and directly.</html:p>
                      </html:li>
                    </html:ol>
                    <html: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. <![CDATA[I have tried quite a few methods (e.g. tracing]]> <html:code>do_filp_open</html:code><![CDATA[) and at the moment I am tracing]]> <html:code>io_openat2</html: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!</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>5</fr:month>
                  <fr:day>26</fr:day>
                </fr:date>
                <fr:title text="Supervisions">Supervisions</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>The first year students I teach will be doing their first year exams soon. I have been helping them revise for foundations of computer science and discrete mathematics. Whilst doing so, I have been thinking a good deal about <fr:link href="/jonmsterling/" title="Jon Sterling" uri="https://patrick.sirref.org/jonmsterling/" display-uri="jonmsterling" type="local">Jon Sterling</fr:link>'s <fr:link href="https://www.jonmsterling.com/2025-W21/index.xml" type="external">post about assessment bureaucracy</fr:link>. In particular:</html:p>
                <html:blockquote>
                  <html:p><![CDATA[At moments like this, it is a good idea to pause and reflect on whether it is better for our students that each faculty member spend a cumulative two months doing literally nothing but assessment and higher-order practices related to assessment, vs. other activities that could benefit our students more (including actual teaching, of which we do astonishingly little at Cambridge).]]></html:p>
                </html:blockquote>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>5</fr:month>
              <fr:day>19</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/weekly-2025-05-12/</fr:uri>
            <fr:display-uri>weekly-2025-05-12</fr:display-uri>
            <fr:route>/weekly-2025-05-12/</fr:route>
            <fr:title text="Metashells">Metashells</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>This week, I feel I have been stuck fighting the OCaml ecosystem trying to keep my <fr:link href="/try-oxcaml/" title="Try OxCaml" uri="https://patrick.sirref.org/try-oxcaml/" display-uri="try-oxcaml" type="local">OxCaml work afloat</fr:link>. Aside from that, <fr:link href="/ryangibb/" title="Ryan Gibb" uri="https://patrick.sirref.org/ryangibb/" display-uri="ryangibb" type="local">Ryan</fr:link> and I made some really nice progress with Shelter, culminating in <fr:link href="/ryangibb/" title="Ryan Gibb" uri="https://patrick.sirref.org/ryangibb/" display-uri="ryangibb" type="local">Ryan</fr:link> describing it as a <html:em>metashell</html:em>.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>5</fr:month>
                  <fr:day>19</fr:day>
                </fr:date>
                <fr:title text="Shelter the metashell">Shelter the metashell</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>The main progress this week with Shelter was composing <fr:link href="https://github.com/opencontainers/runc" type="external">runc</fr:link>'s <html:code>terminal</html:code> mode with entering raw terminal input mode on the Shelter side. This is inspired by <fr:link href="/ryangibb/" title="Ryan Gibb" uri="https://patrick.sirref.org/ryangibb/" display-uri="ryangibb" type="local">Ryan</fr:link>'s own work on <fr:link href="https://github.com/ryangibb/eon" type="external">capability interfaces</fr:link>.</html:p>
                <html:p>Shelter remains mostly intact, acting as an interactive shell. However, just before executing a command we switch to receiving and sending raw terminal inputs and outputs. This means tools like <html:code>vim</html:code> now work in Shelter! Not only that, but users can now <html:em>activate</html:em><![CDATA[ an inner shell (e.g.]]> <html:code>zsh</html:code><![CDATA[) and enjoy all the usual features]]>  <![CDATA[of a fully-fledged shell (tab complete, fuzzy history search etc.) and upon exiting that shell, Shelter will]]>  snapshot the session. This lets you alter the granularity of snapshots from the command-line.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>5</fr:month>
                  <fr:day>19</fr:day>
                </fr:date>
                <fr:title text="Louis Pouzin's &quot;Shell&quot;">Louis Pouzin's "Shell"</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I spent some time reading <fr:link href="/pouzin-shell-2013/" title="The Origin of the Shell" uri="https://patrick.sirref.org/pouzin-shell-2013/" display-uri="pouzin-shell-2013" type="local">part of the multics design documentation</fr:link> 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</html:p>
                <html:blockquote>
                  <html: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.</html:p>
                </html:blockquote>
                <html:p>And then later, when defining the "SHELL".</html:p>
                <html:blockquote>
                  <html: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 <![CDATA[no other process in active execution under console control (presently called]]>  <![CDATA[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, <html:em>inside of another program if it were called</html:em>. Hereafter, for simplification, we shall refer to that procedure as the "SHELL".</html:p>
                </html:blockquote>
                <html:p>It still surprises how little the undergraduate degree in computer science at <fr:link href="/ucam/" title="University of Cambridge" uri="https://patrick.sirref.org/ucam/" display-uri="ucam" type="local">Cambridge</fr:link> focuses on writing skills.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>5</fr:month>
                  <fr:day>19</fr:day>
                </fr:date>
                <fr:title text="OxCaml">OxCaml</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Last week, I got a <fr:link href="/try-oxcaml/" title="Try OxCaml" uri="https://patrick.sirref.org/try-oxcaml/" display-uri="try-oxcaml" type="local">toplevel with OxCaml working</fr:link>. This required a serious amount of work to understand the changes Janestreet have made to obscure parts of the OCaml compiler and then working those into tools like <html:code>js_of_ocaml</html:code>.</html:p>
                <html:p>This week, Janestreet pushed their latest rounds of changes and of course everything broke! I spent some more time fixing it all back up. I'm not entirely sure how maintainable this is. The problem is that, whilst things compile, the programs do not work together! Only when someone uses the program do the bugs surface.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>5</fr:month>
                  <fr:day>19</fr:day>
                </fr:date>
                <fr:title text="Other OCaml Work">Other OCaml Work</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I worked on some other parts of the ecosystem this week.</html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>5</fr:month>
                      <fr:day>19</fr:day>
                    </fr:date>
                    <fr:title text="Ppxlib">Ppxlib</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p><![CDATA[I helped review some changes to enable Janestreet to have ppx rewriters via attributes (usually they are via extension]]>  <![CDATA[points). It is a bit of a controversial change to]]> <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> as we try to keep the API predictable for users:</html:p>
                    <html:ol>
                      <html:li>
                        <html:p>Extension points are rewritten: this means the part that is rewritten is nicely delimited by the extension points start and end.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>Attributes extend: attributes do not rewrite the code they are attached to but rather extend the code with new AST nodes.</html:p>
                      </html:li>
                    </html:ol>
                    <html:p><fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/574" type="external"><![CDATA[We will see what we decided to do (most likely provide the functionality behind some kind of "expert" interface)]]> </fr:link>.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>5</fr:month>
                      <fr:day>19</fr:day>
                    </fr:date>
                    <fr:title text="Tiff">Tiff</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>See <fr:link href="/mdales/" title="Michael W. Dales" uri="https://patrick.sirref.org/mdales/" display-uri="mdales" type="local">Michael</fr:link>'s <fr:link href="https://digitalflapjack.com/weeknotes/2025-05-19b/" type="external">notes</fr:link>.</html:p>
                    <html:p><![CDATA[I spent some time trying to speedup the LZW decompression of TIFF files in the pure OCaml tiff library this week(end).]]>  The two big changes to help with this are pretty common when speeding up these parts OCaml programs:</html:p>
                    <html:ol>
                      <html:li>
                        <html:p>Allocate less</html:p>
                      </html:li>
                      <html:li>
                        <html:p>Does less work</html:p>
                      </html:li>
                    </html:ol>
                    <html:p>In terms of allocating less, the original implementation was using a <html:code>char list</html:code> to represent LZW strings. Manipulating these becomes quite costly, particularly since the most common operation is appending a single character to the end of a list. Converting this to use OCaml's immutable <html:code>string</html:code> saved a ton of allocations.</html:p>
                    <html:p>In terms of doing less work, I opted to bypass <html:code>Cstruct</html:code><![CDATA[s sane (but slow) bounds checks in some of the "hotter" parts of]]>  the code. In particular, LZW ends up reading potentially <html:em>huge</html:em> arrays full of bytes one-by-one. So reading each byte needs to be quite snappy. This is a bit of a trade-off in terms of "safety" but we are in control of this code so I'm not too worried about that.</html:p>
                    <html:p>Here are some results decompressing a fairly large array of some elevation data.</html:p>
                    <html:pre><![CDATA[before: | tiff/lzw/cea │ 523851.2259 mjw/run │ 3289761.5414 mnw/run │ 9806796.7121 ns/run│
after:  │ tiff/lzw/cea │  27846.2408 mjw/run │  587928.7527 mnw/run │ 8457161.3761 ns/run│]]></html:pre>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>5</fr:month>
              <fr:day>10</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/weekly-2025-05-04/</fr:uri>
            <fr:display-uri>weekly-2025-05-04</fr:display-uri>
            <fr:route>/weekly-2025-05-04/</fr:route>
            <fr:title text="Hazel and OxCaml">Hazel and OxCaml</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>I missed a week of posting last week, mainly because I spent more time writing <fr:link href="/posts/" title="Posts" uri="https://patrick.sirref.org/posts/" display-uri="posts" type="local">posts</fr:link>.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>5</fr:month>
                  <fr:day>10</fr:day>
                </fr:date>
                <fr:title text="Hazel of OCaml">Hazel of OCaml</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I mentioned previously that I was building a tool to transpile OCaml code to Hazel. This work is now in a good enough state that, along with one of my students, we have transpiled a good number of OCaml programs to help them write their evaluation for their third-year project.</html:p>
                <html:p>I wrote up a little summary of that work, which I've <fr:link href="https://www.jonmsterling.com/foreign/www.forester-notes.org/jms-007L/index.xml" type="external">transcluded</fr:link> below.</html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>5</fr:month>
                      <fr:day>2</fr:day>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/hazel-of-ocaml/</fr:uri>
                    <fr:display-uri>hazel-of-ocaml</fr:display-uri>
                    <fr:route>/hazel-of-ocaml/</fr:route>
                    <fr:title text="A Transpiler from OCaml to Hazel">A Transpiler from OCaml to Hazel</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Over the past few months, I have been piecing together a transpiler from <fr:link href="/hazel/" title="Hazel" uri="https://patrick.sirref.org/hazel/" display-uri="hazel" type="local">Hazel</fr:link> to OCaml. This is, in part, to help one of my third-year undergraduate students who is working on <fr:link href="/part-ii-hazel/" title="Type Error Debugging in Hazel" uri="https://patrick.sirref.org/part-ii-hazel/" display-uri="part-ii-hazel" type="local">type error debugging in Hazel</fr:link>.</html:p>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>5</fr:month>
                          <fr:day>2</fr:day>
                        </fr:date>
                        <fr:title text="Typed Holes">Typed Holes</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p><fr:link href="/hazel/" title="Hazel" uri="https://patrick.sirref.org/hazel/" display-uri="hazel" type="local">Hazel</fr:link> is a <fr:link href="/omar-hazel-2017/" title="Hazelnut: a bidirectionally typed structure editor calculus" uri="https://patrick.sirref.org/omar-hazel-2017/" display-uri="omar-hazel-2017" type="local">functional programming language with typed holes</fr:link>. 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.</html:p>
                        <html:p>To get a flavour of Hazel, take a regular map function for lists.</html:p>
                        <html: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])]]></html:pre>
                        <html:p><![CDATA[The question mark (]]> <html:code>?</html:code><![CDATA[) is a hole. The program evaluates to the following expression of type]]> <html:code><![CDATA[[?]]]></html:code><![CDATA[ (for people more]]>  familiar with OCaml types <html:code>? list</html:code><![CDATA[).]]></html:p>
                        <html:pre><![CDATA[[ ?, ?, ? ]]]></html:pre>
                        <html:p>Hazel supports <fr:link href="/zhao-typeerror-2024/" title="Total Type Error Localization and Recovery with Holes" uri="https://patrick.sirref.org/zhao-typeerror-2024/" display-uri="zhao-typeerror-2024" type="local">local type inference</fr:link> but nothing involving unification variables. For example, a simple <html:code>add_one</html:code> function in <fr:link href="/hazel/" title="Hazel" uri="https://patrick.sirref.org/hazel/" display-uri="hazel" type="local">Hazel</fr:link><![CDATA[ (]]> <html:code>fun x -&gt; x + 1</html:code><![CDATA[) has type]]> <html:code>? -&gt; Int</html:code>.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>5</fr:month>
                          <fr:day>2</fr:day>
                        </fr:date>
                        <fr:title text="From OCaml to Hazel">From OCaml to Hazel</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html: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 <![CDATA[boilerplate code (e.g. URI parsing or standard library functions for strings).]]></html:p>
                        <fr:tree show-metadata="false" numbered="false">
                          <fr:frontmatter>
                            <fr:authors>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                              </fr:author>
                            </fr:authors>
                            <fr:date>
                              <fr:year>2025</fr:year>
                              <fr:month>5</fr:month>
                              <fr:day>2</fr:day>
                            </fr:date>
                            <fr:title text="A Transformation of Syntax">A Transformation of Syntax</fr:title>
                          </fr:frontmatter>
                          <fr:mainmatter>
                            <html:p>Hazel markets itself as an "Elm/ML-like functional programming language". From the previous example of <html:code>map</html:code>, it should be apparent just how close to OCaml the language is.</html:p>
                            <html:p>It turns out that a majority of the transpiler is a <html:em>transformation of syntax</html:em>. Take a simple ADT for an arithmetic programming language.</html:p>
                            <html:pre class="hilite">
                              <html:code><html:span class="ocaml-keyword-other">type</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">expr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Float</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">of</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">float</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Add</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">of</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">expr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">*</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">expr</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Sub</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">of</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">expr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">*</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">expr</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Mul</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">of</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">expr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">*</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">expr</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Div</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">of</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">expr</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">*</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">expr</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                            </html:pre>
                            <html:p>And when we run <fr:link href="/hazel_of_ocaml/" title="hazel_of_ocaml" uri="https://patrick.sirref.org/hazel_of_ocaml/" display-uri="hazel_of_ocaml" type="local">hazel_of_ocaml</fr:link> over this OCaml type declaration.</html:p>
                            <html:pre><![CDATA[type expr =
  + Float(Float)
  + Add((expr, expr))
  + Sub((expr, expr))
  + Mul((expr, expr))
  + Div((expr, expr))
 in ?]]></html:pre>
                            <html:p>Not much has changed expect some syntax. <fr:link href="/hazel/" title="Hazel" uri="https://patrick.sirref.org/hazel/" display-uri="hazel" type="local">Hazel</fr:link> does not have a notion of top-level expression so <fr:link href="/hazel_of_ocaml/" title="hazel_of_ocaml" uri="https://patrick.sirref.org/hazel_of_ocaml/" display-uri="hazel_of_ocaml" type="local">hazel_of_ocaml</fr:link> 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 <![CDATA[with no support for modules or labelled records out of the box (there are plenty of development branches]]>  <![CDATA[with these features).]]></html:p>
                            <html:p>If we try out the same <html:code>map</html:code> function but written in OCaml and transpiled to Hazel we get.</html:p>
                            <html:pre class="hilite">
                              <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword">rec </html:span><html:span class="ocaml-entity-name-function-binding">map</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">f</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">function</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-list"><![CDATA[[]]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-list"><![CDATA[[]]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">x</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">xs</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">f</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">x</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">map</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">f</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">xs</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                            </html:pre>
                            <html:p>Which becomes the following hazel program.</html:p>
                            <html:pre><![CDATA[let map = fun f -> fun x1 -> case x1
  | [] => []
  | x :: xs => f(x) :: map(f)(xs)
end in ?]]></html:pre>
                            <html:p>We could have a field day discussing the syntax of OCaml and Hazel <![CDATA[(parentheses for function arguments, well-scoped cases for pattern-matching, a]]>  <![CDATA[different arrow for pattern-matching etc.). What would be more interesting is]]>  taking a look at how to handle polymorphism in Hazel.</html:p>
                          </fr:mainmatter>
                        </fr:tree>
                        <fr:tree show-metadata="false" numbered="false">
                          <fr:frontmatter>
                            <fr:authors>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                              </fr:author>
                            </fr:authors>
                            <fr:date>
                              <fr:year>2025</fr:year>
                              <fr:month>5</fr:month>
                              <fr:day>2</fr:day>
                            </fr:date>
                            <fr:title text="Explicit Polymorphism">Explicit Polymorphism</fr:title>
                          </fr:frontmatter>
                          <fr:mainmatter>
                            <html:p>Hazel has <html:em>explicit polymorphism</html:em>. So far, we have not seen it as we have let the types have holes in them. The <html:code>map</html:code> function in OCaml has the following type.</html:p>
                            <html:pre class="hilite">
                              <html:code><html:span class="ocaml-keyword-other">val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">map</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> 
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-storage-type">'a</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-storage-type">'b</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-storage-type">'a</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">list</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-storage-type">'b</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">list</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                            </html:pre>
                            <html:p><![CDATA[We must remind ourselves (by reading]]> <fr:link href="https://www.craigfe.io/posts/polymorphic-type-constraints" type="external">Craig's excellent blogpost on the matter</fr:link><![CDATA[) that in OCaml]]></html:p>
                            <html:blockquote>
                              <html:p>... type variables in signatures are implicitly universally-quantified</html:p>
                            </html:blockquote>
                            <html:p>So in reality, we have that <html:code>map</html:code> has the following type.</html:p>
                            <html:pre><![CDATA[val map : ∀ a b. (a ->  b) -> a list -> b list]]></html:pre>
                            <html:p>In Hazel, we have to explicitly type our <html:code>map</html: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 <html:code>map</html:code><![CDATA[ function (whether that be recursively or somewhere later in our]]>  <![CDATA[program).]]></html:p>
                            <html: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])]]></html:pre>
                            <html:p><html:code>forall</html:code> introduces a universally quantified type variable into our type annotation, and <html:code>typfun</html:code><![CDATA[ introduces it into the function itself (à la System F). Type application]]>  requires <html:code>@&lt;T&gt;</html:code> where <html:code>T</html:code> is some type. This allows hazel to quite easily support higher rank polymorphism, but we will not worry too much about that.</html:p>
                          </fr:mainmatter>
                        </fr:tree>
                        <fr:tree show-metadata="false" numbered="false">
                          <fr:frontmatter>
                            <fr:authors>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                              </fr:author>
                            </fr:authors>
                            <fr:date>
                              <fr:year>2025</fr:year>
                              <fr:month>5</fr:month>
                              <fr:day>2</fr:day>
                            </fr:date>
                            <fr:title text="Propagating OCaml Types into Hazel">Propagating OCaml Types into Hazel</fr:title>
                          </fr:frontmatter>
                          <fr:mainmatter>
                            <html:p>Most often, OCaml users interact with <html:em>prenex</html:em><![CDATA[ polymorphism (rank-1) where the universal quantifiers are]]>  at the front of the type. <fr:link href="https://ocaml.org/manual/5.2/polymorphism.html#s:higher-rank-poly" type="external">OCaml does support quantifiers inside certain types like records</fr:link>.</html:p>
                            <html:p>What this means for the transpiler is that we can <html:strong>reuse OCaml's type inference</html:strong> to safely instantiate the correct type annotations and type applications in Hazel! To do this, <html:code>hazel_of_ocaml</html:code> uses <fr:link href="https://ocaml.github.io/merlin/" type="external">Merlin</fr:link> to inspect the type of the function in either a value binding or at the point of a function application.</html:p>
                            <html:p>Take a simple, polymorphic <html:code>length</html:code> function.</html:p>
                            <html:pre class="hilite">
                              <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword">rec </html:span><html:span class="ocaml-entity-name-function-binding">length</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">function</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-list"><![CDATA[[]]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">0</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language">_</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">xs</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">+</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">length</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">xs</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">int_len</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">length</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">1</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">2</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">3</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">str_len</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">length</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">only</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">two</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                            </html:pre>
                            <html:p>When we run this through <html:code>hazel_of_ocaml</html:code> with the <html:code>-type</html:code> flag we get.</html:p>
                            <html: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 ?]]></html:pre>
                            <html:p><html:code>hazel_of_ocaml</html:code> has correctly instantiated the type for <html:code>length</html:code> inside the recursive function and then in each case with the integer list and the string list.</html:p>
                          </fr:mainmatter>
                        </fr:tree>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>5</fr:month>
                          <fr:day>2</fr:day>
                        </fr:date>
                        <fr:title text="A Corpus of Hazel Programs">A Corpus of Hazel Programs</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>The impetus for this work was to derive a corpus of ill-typed Hazel programs. Luckily, such a corpus exists for OCaml! <fr:link href="/ocaml-corpus/" title="A Collection of Novice Interactions with the OCaml Top-Level System" uri="https://patrick.sirref.org/ocaml-corpus/" display-uri="ocaml-corpus" type="local">Seidel et al.</fr:link> created a corpus of OCaml programs from their undergraduate students at UC San Diego. <fr:link href="https://github.com/patricoferris/hazel-corpus" type="external">Some of these programs have been transpiled to Hazel</fr:link>.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>5</fr:month>
                          <fr:day>2</fr:day>
                        </fr:date>
                        <fr:title text="Future Work">Future Work</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p><fr:link href="/hazel/" title="Hazel" uri="https://patrick.sirref.org/hazel/" display-uri="hazel" type="local">Hazel</fr:link> 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 <![CDATA[(e.g. handling the]]> <html:code>cmi</html:code><![CDATA[ files).]]></html:p>
                        <html: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?</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>5</fr:month>
                  <fr:day>10</fr:day>
                </fr:date>
                <fr:title text="OxCaml">OxCaml</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I spent some time this week getting more familiar with <fr:link href="/oxcaml-2024/" title="Oxidizing OCaml with Modal Memory Management" uri="https://patrick.sirref.org/oxcaml-2024/" display-uri="oxcaml-2024" type="local">Oxidized OCaml</fr:link>. I have a habit of wrapping <html:em>new</html:em> OCaml tools and libraries into toplevel, browser applications. For example, <fr:link href="https://patricoferris.github.io/try-irmin" type="external">try-irmin</fr:link> and <fr:link href="https://patricoferris.github.io/try-eio/" type="external">try-eio</fr:link>.</html:p>
                <html:p>Naturally, I tried to wrap OxCaml into a toplevel so people could play around with the new modes that <![CDATA[are part of the OxCaml type system. This turned out to be a lengthy debugging session (where type declarations]]>  did not align so the raw <html:code>Obj.repr</html:code><![CDATA[ js_of_ocaml representation was broken for some parts of the toplevel).]]>  I would say that I do question the time-spent/value trade-off, but a mostly working toplevel with OxCaml is available at: <fr:link href="https://patrick.sirref.org/oxcaml" type="external">https://patrick.sirref.org/oxcaml</fr:link>.</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>4</fr:month>
              <fr:day>21</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/weekly-2025-04-21/</fr:uri>
            <fr:display-uri>weekly-2025-04-21</fr:display-uri>
            <fr:route>/weekly-2025-04-21/</fr:route>
            <fr:title text="Shelter in the Forest">Shelter in the Forest</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>I spent much of this week working on Shelter and things related to it. Some of that time was also spent on Forester.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>4</fr:month>
                  <fr:day>21</fr:day>
                </fr:date>
                <fr:title text="Forester">Forester</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I added two important quality-of-life features to my frontend to Forester this week.</html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>4</fr:month>
                      <fr:day>21</fr:day>
                    </fr:date>
                    <fr:title text="Bibtex Support">Bibtex Support</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>I had previously mentioned adding support to <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link> for <fr:link href="/weekly-2025-01-20/" title="Forester, ICFP, Wikis" uri="https://patrick.sirref.org/weekly-2025-01-20/" display-uri="weekly-2025-01-20" type="local">Markdown</fr:link>. This week I added support for Bibtex too. From any <html:code>*.bib</html:code> file in your forest, <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link> will now dutifully recognise it as a Bibtex file and convert, as best it can, all the entries into <html:code>Reference</html:code> trees.</html:p>
                    <html:p>I'm becoming quite convinced of this model at the moment. I'm using Forester's <html:code>Code.t</html:code> as a target representation. In fact, to ease the process, I really shouldn't spend <html:em>all my time</html:em> on my website, I have reused my <html:code>Yaml.t -&gt; Code.t</html:code> and <html:code>Markdown.t -&gt; Code.t</html:code> functions in the Bibtex parser.</html:p>
                    <html:p>To see it in action, you could have a look at the <fr:link href="/mokhov-build-systems/" title="Build systems a la carte" uri="https://patrick.sirref.org/mokhov-build-systems/" display-uri="mokhov-build-systems" type="local">Build Systems à la Carte</fr:link> paper which is generated completely from Bibtex.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>4</fr:month>
                      <fr:day>21</fr:day>
                    </fr:date>
                    <fr:title text="Full Heading Support">Full Heading Support</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>The eagled-eyed viewer may have noticed that the table of contents for this page has <html:em>more than one level</html:em>. I finally caved and spent an evening rejigging my <html:code>Cmarkit.Doc.t -&gt; Tree</html:code> code which was hacky and broken and is now less hacky and less broken.</html:p>
                    <html:p>In addition, headings support links and emphasis etc.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>4</fr:month>
                      <fr:day>21</fr:day>
                    </fr:date>
                    <fr:title text="Lunch with Jon Sterling">Lunch with <fr:link href="/jonmsterling/" title="Jon Sterling" uri="https://patrick.sirref.org/jonmsterling/" display-uri="jonmsterling" type="local">Jon Sterling</fr:link></fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>I had a delightful lunch with <fr:link href="/jonmsterling/" title="Jon Sterling" uri="https://patrick.sirref.org/jonmsterling/" display-uri="jonmsterling" type="local">Jon Sterling</fr:link> discussing the future of Forester, the nature of <![CDATA[the Web (old and new) and the success posting weekly updates for our colleagues. Thanks Jon.]]></html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>4</fr:month>
                  <fr:day>21</fr:day>
                </fr:date>
                <fr:title text="Shelter Fixes"><fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> Fixes</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I spent a good chunk of my week fixing bugs in <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> with the aim to perhaps setup a VM somewhere and let people kick the tyres of what we've got so far.</html:p>
                <html:p>The first bug is pretty annoying. At the moment, our filsystem backend is ZFS and we make heavy use of snapshots and cloning in order to provide time-travelling capabilities. Unfortunately, ZFS will take a snapshot before <![CDATA[data has fully made it to disk (or whatever is the equivalent point it should reach in ZFS). Commands that generated]]>  lots of disk activity would be snapshotted in a half finished state and this would cause all sorts of problems. Thanks to <fr:link href="https://patrick.sirref.org/mtelvers/" type="external">Mark Elvers</fr:link> for the pointer to how OBuilder uses ZFS for the OCaml macOS builders which unmount datasets immediately therefore inducing a <html:em>flush</html:em> of sorts. Shelter now follows a similar model with all of the slow downs that create. <fr:link href="/anilmadhavapeddy/" title="Anil Madhavapeddy" uri="https://patrick.sirref.org/anilmadhavapeddy/" display-uri="anilmadhavapeddy" type="local">Anil</fr:link> and I discussed some amalgamation of overlayfs, tmpfs and ZFS to alleviate some of this but for now that's a premature optimisation.</html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>4</fr:month>
                      <fr:day>21</fr:day>
                    </fr:date>
                    <fr:title text="A small eDSL for Shelter">A small eDSL for <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link></fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Whilst testing <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link>, I ended up wanting a way to programmatically invoke the different run commands. This is similar to say a Dockerfile, but maybe with a little more expressivity.</html:p>
                    <html:p>This lead me to revisit the <fr:link href="/mokhov-build-systems/" title="Build systems a la carte" uri="https://patrick.sirref.org/mokhov-build-systems/" display-uri="mokhov-build-systems" type="local">Build systems à la Carte</fr:link> paper and rediscover <fr:link href="/mokhov-selective-2019/" title="Selective applicative functors" uri="https://patrick.sirref.org/mokhov-selective-2019/" display-uri="mokhov-selective-2019" type="local">selective applicative functors</fr:link>.</html:p>
                    <html:p><![CDATA[I started playing around with a selective applicative interface to Shelter, this would allow you to express your dependencies statically but select them dynamically (as the paper says).]]></html:p>
                    <html:pre class="hilite">
                      <html:code><html:span class="ocaml-keyword-other">module</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">D</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Shl</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Identity</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">shelterfile</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword">open</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">D</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">in</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">base_image</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">from</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">alpine</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">in</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">is_node_lst</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">img</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">String</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">equal</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">v22.15.0</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">stdout</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">img</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">in</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">cmds</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">base</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">node_version</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">run</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">node --version</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">base</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">in</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-constant-language-capital-identifier">Select</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">if'</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Select</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">map</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">f</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source">is_node_lst</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">node_version</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">run</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double"><![CDATA[node -e 'console.log('success!')]]> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">run</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double"><![CDATA[node -e 'console.log('failure!')]]> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">      </html:span><html:span class="ocaml-source">base</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">in</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-source">with_session</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">node</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">cmds</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">base_image</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                    </html:pre>
                    <html:p>From this, we get a slightly more expressive way to describe images.</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>4</fr:month>
                  <fr:day>21</fr:day>
                </fr:date>
                <fr:title text="Geocaml TIFF Library"><fr:link href="/geocaml/" title="Geocaml" uri="https://patrick.sirref.org/geocaml/" display-uri="geocaml" type="local">Geocaml</fr:link> TIFF Library</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I was pleasantly surprised to receive a pull request from <fr:link href="/mdales/" title="Michael W. Dales" uri="https://patrick.sirref.org/mdales/" display-uri="mdales" type="local">Michael</fr:link> adding support to ocaml-tiff for reading TIFF files compressed using LZW. I was also surprised to hear the TIFF LZW is a little different to others.</html:p>
                <html:p>In trying to get this PR merged, I moved the initialisation of the Eio eventloop to outside each individual test case. This one change then completely broke the entire test suite. After a period of debugging and help from <fr:link href="/talex5/" title="Thomas Leonard" uri="https://patrick.sirref.org/talex5/" display-uri="talex5" type="local">Thomas Leonard</fr:link> the root cause was OCaml's <html:code>OUnit2</html:code><![CDATA[ library using process-level parallelism (via]]> <html:code>Unix.fork</html:code><![CDATA[), sharing the ring between the parent and the child]]>  lead to the issues.</html:p>
                <html:p><fr:link href="https://github.com/ocaml-multicore/eio/issues/801" type="external">Read more about that issue on the Eio issue tracker</fr:link>.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>4</fr:month>
                  <fr:day>21</fr:day>
                </fr:date>
                <fr:title text="Part II Students"><fr:link href="/part-ii-2024/" title="Part II Students 2024" uri="https://patrick.sirref.org/part-ii-2024/" display-uri="part-ii-2024" type="local">Part II</fr:link> Students</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>As the new term begins, it signals that there are only just over two weeks for the final year undegrads at <fr:link href="/ucam/" title="University of Cambridge" uri="https://patrick.sirref.org/ucam/" display-uri="ucam" type="local">Cambridge</fr:link> to submit their dissertations.</html:p>
                <html:p><![CDATA[The four students that I help supervise have been sending me drafts of their work (and reminder you can]]> <fr:link href="/part-ii-2024/" title="Part II Students 2024" uri="https://patrick.sirref.org/part-ii-2024/" display-uri="part-ii-2024" type="local">read about their projects</fr:link><![CDATA[)]]>  and I'm very impressed. I'm sure the next two weeks will be stressful, but I'm proud of what they have accomplished over the past academic year.</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>4</fr:month>
              <fr:day>21</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/weekly-2025-04-14/</fr:uri>
            <fr:display-uri>weekly-2025-04-14</fr:display-uri>
            <fr:route>/weekly-2025-04-14/</fr:route>
            <fr:title text="Catching Up!">Catching Up!</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>This is a bit of a catch-up post. A week or so in Belfast has thrown me a little off course with the weeklies.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>4</fr:month>
                  <fr:day>21</fr:day>
                </fr:date>
                <fr:title text="Outreachy December 2024 and Beyond">Outreachy December 2024 and Beyond</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>In the last week or so, we have come to the end of the December 2024 round of <fr:link href="https://outreachy.org/" type="external">Outreachy</fr:link>. For those who do not know about Outreachy, it facilitates and organises internships in open-source. Internships for those who are historically underrepresented and impacted by systematic bias in tech.</html:p>
                <html:p>We, the OCaml community, held our biannual <html:em>Demo Day</html:em> where our current cohort of interns can show off what they have been building for three months. This round, we only had one intern, <fr:link href="https://github.com/azzsal" type="external">Abdulaziz</fr:link>, who worked on the <fr:link href="https://github.com/ocaml-semver/ocaml-api-watch" type="external">OCaml API diffing tool</fr:link>.</html:p>
                <html:p style="text-align: center">
    <html:iframe title="Outreachy December 2024 Demo" width="600" height="315" src="https://watch.ocaml.org/videos/embed/eWRikkpwoox1SboAwrDshD" frameborder="0" allowfullscreen="" sandbox="allow-same-origin allow-scripts allow-popups allow-forms" />
</html:p>
                <html:p>The next round has just completed the contribution phase and our next cohort of interns is being selected.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>4</fr:month>
                  <fr:day>21</fr:day>
                </fr:date>
                <fr:title text="Ppxlib Supports OCaml 5.4 (mostly) "><![CDATA[Ppxlib Supports OCaml 5.4 (mostly)]]> </fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>This week, I <fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/570" type="external">added support for OCaml 5.4</fr:link> to <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link>. A rather non-trivial change to the codebase due to changes in the representation in <html:code>Longident</html:code><![CDATA[s (which now have location information for all segments of the]]> <html:code>Longident</html:code><![CDATA[). OCaml 5.4 has]]> <html:em>labelled tuples</html:em>, a light-weight record-like syntax similar to labelled arguments in functions.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">x</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">x</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-constant-numeric-decimal-integer">1</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">10</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">y</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-constant-numeric-decimal-integer">1</html:span><html:span class="ocaml-source"> 
</html:span>
<html:span class="ocaml-keyword-other">val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">x</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">x</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-support-type">int</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">*</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">int</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">*</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">y</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-support-type">int</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">add</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">~</html:span><html:span class="ocaml-source">x</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">y</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">x</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">+</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">y</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">add</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">x</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-support-type">int</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">*</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">y</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-support-type">int</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">int</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html:p>As of writing this post, we are waiting for the full OCaml 5.4 feature freeze and magic number bump. Note this is <html:em>support for OCaml 5.4</html:em><![CDATA[ (in ppxlib terms, we know have migration functions for 5.3 <-> 5.4) not a bump to use the 5.4 parsetree in ppxlib.]]></html:p>
                <html:p>
                  <html:strong>(ppxlib)[Ppxlib]The Future of </html:strong>
                </html:p>
                <html:p>I have now been helping maintain <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">Ppxlib</fr:link> for a while and I am beginning to wonder about the long-term vision for the project. <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">Ppxlib</fr:link> is a central component to any modern OCaml library or tool, <fr:link href="https://sherlocode.com/" type="external">Sherlocode</fr:link> reckons there's <html:em>18.3k</html:em> instances of <html:code><![CDATA[[@@deriving]]></html:code><![CDATA[. Yet, every compiler release is a painful, two-phase process for the maintainers. First, we have to support the new release of the compiler. This is mostly okay but does involve adding lots of code to Ppxlib (we need a whole copy of the Parsetree!). Later on down the line, we have to bump the AST and this often breaks many ppxes.]]></html:p>
                <html:p>The biggest issue is still the tension between abstract types and pattern-matching. By exposing the Parsetree directly to user's, they can pattern-match against the AST and build their ppxes in a rather straight forward way. However, this comes with the risk that the type may change thus breaking their code.</html:p>
                <html:p>I have mentioned <fr:link href="/ppxlib-5-2/" title="Bumping Ppxlib's AST to 5.2" uri="https://patrick.sirref.org/ppxlib-5-2/" display-uri="ppxlib-5-2" type="local">before</fr:link> about plans to use "views" to help with this, but I do not see that happening any time soon. It feels to me, we should be able to allow a user to <html:em>select</html:em> their AST to work with. How this interacts with modules like <html:code>Ast_builder</html:code> is unclear to me, but it would mean user's can remain on older ASTs even when <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> bumps the internal, main AST.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>4</fr:month>
                  <fr:day>21</fr:day>
                </fr:date>
                <fr:title text="Sherlorocq">Sherlorocq</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><fr:link href="https://rocq-prover.org/" type="external">Rocq</fr:link><![CDATA[ is a theorem prover (originally called]]> <html:code>coq</html:code><![CDATA[) from many of the same folks who brought you OCaml.]]>  I have been interested in theorem provers for a while, more from an engineering perspective and less from a theoretical one. My good friend, <fr:link href="/dhsorens/" title="Derek Sorensen" uri="https://patrick.sirref.org/dhsorens/" display-uri="dhsorens" type="local">Derek Sorenson</fr:link>, taught me about Rocq when we <fr:link href="https://github.com/dhsorens/mrdt" type="external">encoded <html:em>mergeable replicated datatypes</html:em></fr:link>. Later I had a go at encoding <fr:link href="https://github.com/patricoferris/coq-difc" type="external"><html:em>decentralised information flow control</html:em></fr:link><![CDATA[ (also in]]> <fr:link href="https://github.com/patricoferris/difc-star" type="external">Fstar</fr:link><![CDATA[).]]></html:p>
                <html:p>During this process, I found it quite challenging to find Rocq code that I could learn from. Compared to using say OCaml's <html:code>Stdlib</html:code><![CDATA[, using Rocq's standard library of datatypes and proofs did not come naturally (not helped by the fact that at the time I could not get the LSP to play ball).]]></html:p>
                <html:p>This lead me to port <fr:link href="/artw/" title="Arthur Wendling" uri="https://patrick.sirref.org/artw/" display-uri="artw" type="local">Arthur Wendling's</fr:link> excellent <fr:link href="https://sherlocode.com/" type="external">Sherlocode</fr:link> to do the same thing only for Rocq code. Luckily, it uses <fr:link href="https://swtch.com/~rsc/regexp/regexp4.html" type="external">regular expression matching with a trigram index</fr:link> so it is not tied to any particular programming language. <![CDATA[Additionally, it is somewhat opam-centric (not actually that much) which is perfect for Rocq!]]></html:p>
                <html:p>Anyway, I've had some interest from the people at Inria to bring the server back to life. Their wish is my command!</html:p>
                <html:p><fr:link href="https://sherlorocq.sirref.org/" type="external">Sherlorocq</fr:link> is back online!</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>3</fr:month>
              <fr:day>31</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/weekly-2025-03-31/</fr:uri>
            <fr:display-uri>weekly-2025-03-31</fr:display-uri>
            <fr:route>/weekly-2025-03-31/</fr:route>
            <fr:title text="Shelter, Hazel and More!">Shelter, Hazel and More!</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>Last week I focused on <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> -- our idea that shells should have the same ability as reproducible build tools like Nix or Docker. To this end I now have a fairly fleshed out prototype.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>3</fr:month>
                  <fr:day>31</fr:day>
                </fr:date>
                <fr:title text="Shelter Prototype">Shelter Prototype</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Shelter is a spin-off from the work <fr:link href="/mdales/" title="Michael W. Dales" uri="https://patrick.sirref.org/mdales/" display-uri="mdales" type="local">Michael</fr:link> and I started with <fr:link href="https://github.com/quantifyearth/shark" type="external">Shark</fr:link>. It takes the same ideas but applies them directly to a shell-like interface.</html:p>
                <html:p>We're still in the middle of working all of this, but you can read more about it at <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link>.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>3</fr:month>
                  <fr:day>31</fr:day>
                </fr:date>
                <fr:title text="Forester Hacking">Forester Hacking</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>As you can probably tell, my website is still using <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link>. I rebased my Markdown branch to include the new Atom syndication feature.</html:p>
                <html:p>Alongside that I added support for arbitrary HTML injection into Forester via codeblocks in Markdown. This was actually very straightforward thanks to <fr:link href="https://ocaml.org/p/markup" type="external">Markup</fr:link> and being able to re-parse Forester syntax in the middle of converting a Markdown document. The HTML for the shell in <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> uses this feature.</html:p>
                <html:p>If you are interested in taking this custom Forester for a spin, there's <fr:link href="https://github.com/patricoferris/ocaml-forester/tree/5-dev-md" type="external">a branch on Github</fr:link>. In fact, nearly the only change beyond letting the core engine know about markdown files, is <fr:link href="https://github.com/patricoferris/ocaml-forester/blob/5-dev-md/lib/compiler/Parse_md.ml" type="external">adding a new parser frontend</fr:link>.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>3</fr:month>
                  <fr:day>31</fr:day>
                </fr:date>
                <fr:title text="Hazel">Hazel</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>For one of my <fr:link href="/part-ii-2024/" title="Part II Students 2024" uri="https://patrick.sirref.org/part-ii-2024/" display-uri="part-ii-2024" type="local">Part II</fr:link> students, I've been prototyping a transpiler from OCaml to Hazel. This has gone pretty well and now supports type annotations as well as straight-forward implementation translation.</html:p>
                <html:p>Consider the following OCaml <html:code>map</html:code> function.</html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword">rec </html:span><html:span class="ocaml-entity-name-function-binding">map</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">f</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">function</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-list"><![CDATA[[]]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-list"><![CDATA[[]]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">|</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">x</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">xs</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">f</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">x</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">map</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">f</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">xs</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html:p>The tool, <fr:link href="https://github.com/patricoferris/hazel_of_ocaml" type="external"><html:code>hazel_of_ocaml</html:code></fr:link> can translate this to Hazel code, including making the polymorphism explicit.</html:p>
                <html:pre><![CDATA[let map : forall a -> forall b -> (a -> b) -> [a] -> [b] 
  = typfun a -> typfun b -> fun f -> fun x1 -> case x1
  | [] => []
  | x :: xs => f(x) :: map(f)(xs)
end in ?]]></html:pre>
                <html:p>You can copy and paste that codeblock into the <fr:link href="https://hazel.org/build/dev/" type="external">hazel playground</fr:link><![CDATA[. But do note that it still needs some manual editing to add the type applications in directly (]]> <html:code>map@&lt;a&gt;@&lt;b&gt;</html:code><![CDATA[). With the right amount of type-inferencing and scoping I actually think that you could place those type applications in yourself. This could make a nice Part II project I think.]]></html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>3</fr:month>
                  <fr:day>31</fr:day>
                </fr:date>
                <fr:title text="Ppxlib">Ppxlib</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I recently wrote about the painful experience of <fr:link href="/ppxlib-5-2/" title="Bumping Ppxlib's AST to 5.2" uri="https://patrick.sirref.org/ppxlib-5-2/" display-uri="ppxlib-5-2" type="local">miragrating ppxlib to the 5.2 OCaml AST</fr:link>. This week, Nathan Rebours and I merged a PR to add the <fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/558" type="external">5.3 AST</fr:link>! Ppxlib has been playing catch-up with the compiler and we decided it was best to try to catch up quickly and deal with the ecosystem fallout all at once rather than incrementally. With this new AST merged, ppx authors can now use the new <html:code>Pexp_effect</html:code> parsetree node. I'll write a little more about this in a separate post soon.</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>2</fr:month>
              <fr:day>17</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/weekly-2025-02-17/</fr:uri>
            <fr:display-uri>weekly-2025-02-17</fr:display-uri>
            <fr:route>/weekly-2025-02-17/</fr:route>
            <fr:title text="Vpnkit, Void Processes, LSP Servers">Vpnkit, Void Processes, LSP Servers</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>Previous <fr:link href="/weeklies/" title="Patrick Ferris' Weeklies" uri="https://patrick.sirref.org/weeklies/" display-uri="weeklies" type="local">weeklies</fr:link> used <html:strong>strong</html:strong> emphasis to distinguish sections. This comes from <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link>'s philosophy about atomicity of the content in your <html:em>forest</html:em>.</html:p>
            <html:p>However, <html:em>subtrees</html:em> are supported! I quickly hacked together the ability to use <html:em>subheadings</html:em> to indicate <html:em>subtrees</html:em>. This is strictly less expressive than the <html:code><![CDATA[\subtree{}]]></html:code> of <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link>'s default syntax as we cannot <html:em>close</html:em> heading sections in Markdown.</html:p>
            <html:p>This weekly uses subtrees.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>2</fr:month>
                  <fr:day>17</fr:day>
                </fr:date>
                <fr:title text="Vpnkit">Vpnkit</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I spent some time this week trying to upgrade vpnkit to OCaml 5. I was originally working on <fr:link href="/vpnkit-er/" title="Vpnkit (Experience Report)" uri="https://patrick.sirref.org/vpnkit-er/" display-uri="vpnkit-er" type="local">a paper idea</fr:link> which might need benchmarks, but <fr:link href="/anilmadhavapeddy/" title="Anil Madhavapeddy" uri="https://patrick.sirref.org/anilmadhavapeddy/" display-uri="anilmadhavapeddy" type="local">Anil</fr:link> and I decided we could simply point to the port I did and show how it has simplified much of the code.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>2</fr:month>
                  <fr:day>17</fr:day>
                </fr:date>
                <fr:title text="Void Processes">Void Processes</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><![CDATA[Work continued on implementing (and fully exploring)]]> <fr:link href="/void-process/" title="Void Process" uri="https://patrick.sirref.org/void-process/" display-uri="void-process" type="local">void processes</fr:link>. A lot of the groundwork already exists in <fr:link href="https://blog.hillion.co.uk/posts/void-processes/dissertation/jsh77-dissertation.pdf" type="external">Jake Hillion's master's thesis</fr:link>.</html:p>
                <html:p>This week I added a feature that I needed to help build the processes we need for the shell I'm building: mount points with modes!</html:p>
                <html:p><![CDATA[In addition to the root mount (taken care of with]]> <fr:link href="https://man7.org/linux/man-pages/man2/pivot_root.2.html" type="external">pivot_root</fr:link><![CDATA[), we need to be able to add additional mounts into the process' environment. These can now be added. All mount points can be mounted]]> <html:code>readonly</html:code> or <html:code>readwrite</html:code>.</html:p>
                <html:p><![CDATA[Here is the "Hello, World!" example (the]]> <html:code>/say/hey</html:code> program has been statically compiled using <html:code>musl-gcc</html:code><![CDATA[).]]></html:p>
                <html:pre class="hilite">
                  <html:code><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">status</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">void</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-source">empty</html:span><html:span class="ocaml-source"> 
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword-operator">|&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">mount</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">mode</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-constant-language-capital-identifier">R</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">src</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source">hey_dir</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">tgt</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">say</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">    </html:span><html:span class="ocaml-keyword-operator">|&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">exec</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[[]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">/say/hey</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[]]]> </html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword-other">in</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Void</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">spawn</html:span><html:span class="ocaml-source"> ~</html:span><html:span class="ocaml-source">sw</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">void</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other">in</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">  </html:span><html:span class="ocaml-constant-language-capital-identifier">Promise</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">await</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-language-capital-identifier">Void</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">exit_status</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source">
</html:span>
</html:code>
                </html:pre>
                <html:p>There really is nothing else in there. Without specifying a <html:code>root</html:code> mount, the void process is started with an empty <html:code>tmpfs</html:code> root. Next on the list is networking!</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>2</fr:month>
                  <fr:day>17</fr:day>
                </fr:date>
                <fr:title text="LSP Servers">LSP Servers</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I got a little side-tracked building a library for writing <fr:link href="https://microsoft.github.io/language-server-protocol/" type="external">LSP</fr:link> servers in OCaml: <fr:link href="/mlsp/" title="Mlsp" uri="https://patrick.sirref.org/mlsp/" display-uri="mlsp" type="local">mlsp</fr:link>. This may seem a little unrelated, but it isn't. The LSP has become the de facto standard for communicating between an editor and a programming language environment. If you have used VSCode to write a program in Python, chances are you are using <fr:link href="https://marketplace.visualstudio.com/items?itemName=ms-python.python" type="external">the official extension</fr:link> which gives you linting, formatting, code navigation etc. All of these features are communicating using the LSP.</html:p>
                <html:p>It seems <fr:link href="https://github.com/FurqanSoftware/codemirror-languageserver" type="external">Code Mirror</fr:link><![CDATA[ can already proxy over a websocket for LSP support too (we might not even need that as we can compile OCaml directly to JavaScript/Webassembly and have the whole thing running locally!).]]></html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>2</fr:month>
                  <fr:day>17</fr:day>
                </fr:date>
                <fr:title text="Open-Source &amp; Community">Open-Source &amp; Community</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><fr:link href="/anilmadhavapeddy/" title="Anil Madhavapeddy" uri="https://patrick.sirref.org/anilmadhavapeddy/" display-uri="anilmadhavapeddy" type="local">Anil</fr:link> and I had a great conversation this week about building community especially as it pertains to open-source and OCaml.</html:p>
                <html:p>I've been going back over <fr:link href="/ostrom-gtc/" title="Governing the Commons" uri="https://patrick.sirref.org/ostrom-gtc/" display-uri="ostrom-gtc" type="local">Governing the Commons</fr:link>, but have already discovered <fr:link href="/franklin-rwt/" title="The Real World of Technology" uri="https://patrick.sirref.org/franklin-rwt/" display-uri="franklin-rwt" type="local">The Real World of Technology</fr:link>!</html:p>
                <html:p>More thoughts on all of this soon... maybe</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>2</fr:month>
              <fr:day>10</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/weekly-2025-02-10/</fr:uri>
            <fr:display-uri>weekly-2025-02-10</fr:display-uri>
            <fr:route>/weekly-2025-02-10/</fr:route>
            <fr:title text="Teaching, teaching, teaching...">Teaching, teaching, teaching...</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p><![CDATA[On paper, I don't have that many students. I teach four undergraduates (first]]>  <![CDATA[year students at Pembroke College)]]> <fr:link href="/discrete-maths/" title="Discrete Mathematics" uri="https://patrick.sirref.org/discrete-maths/" display-uri="discrete-maths" type="local">Discrete Maths</fr:link>. I supervise three third year students for their <fr:link href="/part-ii-2024/" title="Part II Students 2024" uri="https://patrick.sirref.org/part-ii-2024/" display-uri="part-ii-2024" type="local">final year project</fr:link> and another one I co-supervise with <fr:link href="/mdales/" title="Michael W. Dales" uri="https://patrick.sirref.org/mdales/" display-uri="mdales" type="local">Michael Dales</fr:link>. However, I do end up spending at least two full days a week on teaching. Something I really enjoy and take seriously. The time it takes is also quite unpredictable; last week for instance all the third year students <![CDATA[had their mid-project demonstrations (a five-minute presentation in front of]]>  <![CDATA[their peers and a few professor-types). My first year students also found two]]>  slides particularly challenging to understand from their lectures and asked if I could help explain what was going on, so I <fr:link href="https://patrick.sirref.org/dm-note.pdf" type="external">produced some materials for that</fr:link>.</html:p>
            <html:p>
              <html:strong>OCaml</html:strong>
            </html:p>
            <html:p>Within the OCaml universe I spent a good bit of time trying to maintain a couple of different packages:</html:p>
            <html:ol>
              <html:li>
                <html:p>Mirage Crypto: this library provides cryptographic primitives for OCaml programs. Unfortunately, the maintainers removed direct support for Eio replacing it with a "Unix" alternative. This is not a fair swap as now Eio programs must make a dependency to Unix! Speaking to <fr:link href="/anilmadhavapeddy/" title="Anil Madhavapeddy" uri="https://patrick.sirref.org/anilmadhavapeddy/" display-uri="anilmadhavapeddy" type="local">Anil</fr:link>, the best approach might be to make Eio programs handle this directly. I think this highlighted how fragmented open-source maintenance can be as no user of Eio seems to have bumped into this yet and the upstream maintainers did not communicate a rather large breaking change.</html:p>
              </html:li>
              <html:li>
                <html:p>Ppxlib: In addition to the <fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/514" type="external">5.2 AST bump</fr:link><![CDATA[ (which is nearly ready to be merged), I queued up a]]> <fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/558" type="external">5.3 AST bump</fr:link> right behind it. I plan to write up a more detailed post about the challenges of maintaining this part of ppxlib.</html:p>
              </html:li>
            </html:ol>
            <html:p>
              <html:strong>Paris</html:strong>
            </html:p>
            <html:p>I spent some time in Paris at the end of the week. I enjoyed visiting the Musée d'Orsay and in particular their collection of impressionist paintings. Here's my favourite from that visit by Camille Pissarro.</html:p>
            <html:figure>
  <html:img src="pissarro.jpeg" width="400" alt="Woman in an Orchard (Spring Sunshine in the Meadow at Eragny)." />
  <html:figcaption>Woman in an Orchard (Spring Sunshine in the Meadow at Eragny)</html:figcaption>
</html:figure>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>1</fr:month>
              <fr:day>27</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/weekly-2025-01-27/</fr:uri>
            <fr:display-uri>weekly-2025-01-27</fr:display-uri>
            <fr:route>/weekly-2025-01-27/</fr:route>
            <fr:title text="AT Protocol and an IR for Wikis">AT Protocol and an IR for Wikis</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>
              <html:strong>AT Protocol</html:strong>
            </html:p>
            <html:p>This week I've been diving into the <fr:link href="https://atproto.com/" type="external">AT Protocol</fr:link>.</html:p>
            <html:blockquote>
              <html:p>The Authenticated Transfer Protocol, aka atproto, is a decentralized protocol for large-scale social web applications.</html:p>
            </html:blockquote>
            <html:p>The protocol could be a candidate for the glue that holds together a distributed, computational wiki network. The protocol, it seems, is very similar to <fr:link href="/ipfs/" title="Interplanetary Filesystem" uri="https://patrick.sirref.org/ipfs/" display-uri="ipfs" type="local">IPFS</fr:link>. Thankfully, a few years ago, I was working on building out a suite of OCaml libraries for working with <fr:link href="/ipfs/" title="Interplanetary Filesystem" uri="https://patrick.sirref.org/ipfs/" display-uri="ipfs" type="local">IPFS</fr:link>. For example, <fr:link href="https://github.com/patricoferris/ocaml-cid" type="external">ocaml-cid</fr:link>, self-describing content-addressed identifiers.</html:p>
            <html:pre class="hilite">
              <html:code><html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">s</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">s</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-support-type">string</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-string-quoted-double">zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA</html:span><html:span class="ocaml-string-quoted-double">"</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword">let</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-entity-name-function-binding">cid</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Cid</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">of_string</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">s</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">|&gt;</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Result</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">get_ok</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">val</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">cid</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Cid</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">t</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">=</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">&lt;</html:span><html:span class="ocaml-source">abstr</html:span><html:span class="ocaml-keyword-operator">&gt;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-keyword-other">#</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Cid</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">pp_human</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-language-capital-identifier">Format</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span><html:span class="ocaml-source">std_formatter</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">cid</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">cidv1</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">base58btc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">raw</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-keyword-operator">-</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">ident</html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">sha2</html:span><html:span class="ocaml-keyword-operator">-</html:span><html:span class="ocaml-constant-numeric-decimal-integer">256</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">length</html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">32</html:span><html:span class="ocaml-source"><![CDATA[)]]> </html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">digest</html:span><html:span class="ocaml-source"><![CDATA[(]]> </html:span><html:span class="ocaml-source">6e 6f </html:span><html:span class="ocaml-source">f7</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">95</html:span><html:span class="ocaml-source"> 0a </html:span><html:span class="ocaml-constant-numeric-decimal-integer">36</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">18</html:span><html:span class="ocaml-source"> 7a  </html:span><html:span class="ocaml-constant-numeric-decimal-integer">80</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">16</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">13</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">42</html:span><html:span class="ocaml-source"> 6e </html:span><html:span class="ocaml-constant-numeric-decimal-integer">85</html:span><html:span class="ocaml-source"> 8d </html:span><html:span class="ocaml-source">ce</html:span><html:span class="ocaml-source">
</html:span>
<html:span class="ocaml-source">                                                            </html:span><html:span class="ocaml-constant-numeric-decimal-integer">68</html:span><html:span class="ocaml-source"> 6c </html:span><html:span class="ocaml-source">d7</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">d7</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">e3</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">c0</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-source">fc</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">42</html:span><html:span class="ocaml-source">  </html:span><html:span class="ocaml-source">ee</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">03</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">30</html:span><html:span class="ocaml-source"> </html:span><html:span class="ocaml-constant-numeric-decimal-integer">07</html:span><html:span class="ocaml-source"> 2d </html:span><html:span class="ocaml-constant-numeric-decimal-integer">24</html:span><html:span class="ocaml-source"> 5c </html:span><html:span class="ocaml-constant-numeric-decimal-integer">95</html:span><html:span class="ocaml-source">
</html:span>
</html:code>
            </html:pre>
            <html:p>To this end I have built out some more OCaml libraries for working with atproto, including:</html:p>
            <html:ul>
              <html:li>
                <html:p><fr:link href="https://github.com/patricoferris/ocaml-atproto-data" type="external">atproto-data</fr:link>: the atproto data model, similar to JSON-LD.</html:p>
              </html:li>
              <html:li>
                <html:p><fr:link href="https://github.com/patricoferris/ocaml-did" type="external">ocaml-did</fr:link>: an OCaml library for working with decentralized identifiers.</html:p>
              </html:li>
              <html:li>
                <html:p><fr:link href="https://github.com/patricoferris/ocaml-atproto-lexicon" type="external">atproto-lexicon</fr:link>: atproto's schema format, I've been building a quick tool for doing an OCaml translation from these schemas.</html:p>
              </html:li>
            </html:ul>
            <html:p>I managed to get <fr:link href="https://bsky.app/profile/patrick.sirref.org/post/3lh24rrjngw24" type="external">a post published from the OCaml library</fr:link> after fixing it up and porting it to <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link>.</html:p>
            <html:p>
              <html:strong>An IR for Wikis</html:strong>
            </html:p>
            <html:p>I started working on a proof-of-concept intermediate representation for Wikis -- I imagine it a bit like <fr:link href="https://github.com/stedolan/malfunction" type="external">malfunction</fr:link> but for computational wikis i.e. a target for Wiki building tools that allows different front-ends and servers to communicate in a common IR for exposing key functionalities of a wiki:</html:p>
            <html:ul>
              <html:li>
                <html:p>Links: External links, cross-wiki backlinks</html:p>
              </html:li>
              <html:li>
                <html:p>Versioned, temporal feeds</html:p>
              </html:li>
              <html:li>
                <html:p>Etc.</html:p>
              </html:li>
            </html:ul>
            <html:p>
              <html:strong>Other PhD Work</html:strong>
            </html:p>
            <html:p>I met with most of my <fr:link href="/part-ii/" title="Part II Projects" uri="https://patrick.sirref.org/part-ii/" display-uri="part-ii" type="local">Part II</fr:link> students this week, and I'm excited about their work. Progress reports are due this week and next they have a presentation to give.</html:p>
            <html:p>In <fr:link href="/discrete-maths/" title="Discrete Mathematics" uri="https://patrick.sirref.org/discrete-maths/" display-uri="discrete-maths" type="local">discrete maths</fr:link> this week we did induction. Next up is a big section on sets, functions, bijections etc.</html:p>
            <html:p>
              <html:strong>Misc.</html:strong>
            </html:p>
            <html:p>I was happy to find the <fr:link href="https://www.opentech.fund/fellowships/icfp/" type="external">Information Controls Fellowship Program</fr:link>.</html:p>
            <html:blockquote>
              <html:p><![CDATA[The Information Controls Fellowship Program (ICFP) cultivates research, outputs, and creative collaboration on topics related to repressive internet censorship and surveillance.]]></html:p>
            </html:blockquote>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="false" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>1</fr:month>
              <fr:day>20</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/weekly-2025-01-20/</fr:uri>
            <fr:display-uri>weekly-2025-01-20</fr:display-uri>
            <fr:route>/weekly-2025-01-20/</fr:route>
            <fr:title text="Forester, ICFP, Wikis">Forester, ICFP, Wikis</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>This week was my first full week back from the break and I found it challenging trying to get back into what I had been working on previously.</html:p>
            <html:p>
              <html:strong>ICFP Papers</html:strong>
            </html:p>
            <html:p>In conversation with <fr:link href="/anilmadhavapeddy/" title="Anil Madhavapeddy" uri="https://patrick.sirref.org/anilmadhavapeddy/" display-uri="anilmadhavapeddy" type="local">Anil</fr:link>, we looked at options for submitting a paper to ICFP. I wrote up some notes on some options <fr:link href="/icfp25-ideas/" title="ICFP Paper Ideas" uri="https://patrick.sirref.org/icfp25-ideas/" display-uri="icfp25-ideas" type="local">we discussed</fr:link>.</html:p>
            <html:p>
              <html:strong>Forester</html:strong>
            </html:p>
            <html:p>I spent some time this week converting this website to using <fr:link href="https://www.jonmsterling.com/foreign-forester-jms-005P.xml" type="external">Forester</fr:link>. I'm not a huge fan of the syntax, especially as a lot of my site's content was already in markdown. So I wrote a markdown frontend to forester which is <fr:link href="https://github.com/patricoferris/ocaml-forester/tree/markdown" type="external">available on Github</fr:link>.</html:p>
            <html:p>The markdown frontend integrates very nicely and only a few changes were needed in the core logic of <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link> itself. Additionally, for any features not directly supported in markdown there is an escape hatch using code blocks such as:</html:p>
            <html:pre><![CDATA[```forester
\put\transclude/numbered{false}

\transclude{pxf-1000}
```]]></html:pre>
            <html:p>Personally, I'm still getting to grips with the <html:em>bottom-up</html:em> approach to building this site, atomically creating notes and reference cards that then are linked in many places.</html:p>
            <html:p>I'm excited to see how I can integrate some of the Forester concepts into "Shark".</html:p>
            <html:p>
              <html:strong>OCaml</html:strong>
            </html:p>
            <html:p>In the OCaml world, I spent time on <html:code>ppxlib</html:code>, reviewing PRs to update the lower bounds of the library, fixing effect syntax problems and bumping internal AST to 5.2. I've also spent some time looking into de-objecting Eio, making the OCaml types more friendly to new users. I need to revive my port of Vpnkit to Eio for the thoughts on <fr:link href="/icfp25-ideas/" title="ICFP Paper Ideas" uri="https://patrick.sirref.org/icfp25-ideas/" display-uri="icfp25-ideas" type="local">ICFP 2025</fr:link> too.</html:p>
            <html:p>I also want to modernise and make more public my OCaml code for creating little shells in OCaml too -- I think the ideas here really have legs and would like to find a conference to submit them too.</html:p>
            <html:p>I also met with the single, OCaml Outreachy intern working on <fr:link href="https://github.com/ocaml-semver/ocaml-api-watch" type="external">ocaml-api-watch</fr:link>.</html:p>
            <html:p>
              <html:strong>Misc.</html:strong>
            </html:p>
            <html:p>I met with most of my <fr:link href="/part-ii-2024/" title="Part II Students 2024" uri="https://patrick.sirref.org/part-ii-2024/" display-uri="part-ii-2024" type="local">Part II</fr:link> students this week which was nice to catch up and see how their projects are going. I also started marking work for my first year students who are at the <html:em>induction</html:em> part of their <fr:link href="/discrete-maths/" title="Discrete Mathematics" uri="https://patrick.sirref.org/discrete-maths/" display-uri="discrete-maths" type="local">Discrete Maths</fr:link> course.</html:p>
          </fr:mainmatter>
        </fr:tree>
      </fr:mainmatter>
    </fr:tree>
  </fr:mainmatter>
  <fr:backmatter>
    <fr:tree show-metadata="false" hidden-when-empty="true">
      <fr:frontmatter>
        <fr:authors />
        <fr:title text="References">References</fr:title>
      </fr:frontmatter>
      <fr:mainmatter>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Zhengpeng Feng/" type="external">Zhengpeng Feng</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Clement Atzberger/" type="external">Clement Atzberger</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Sadiq Jaffer/" type="external">Sadiq Jaffer</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Jovana Knezevic/" type="external">Jovana Knezevic</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Silja Sormunen/" type="external">Silja Sormunen</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Robin Young/" type="external">Robin Young</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Madeline C. Lisaius" type="external">Madeline C. Lisaius</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Markus Immitzer/" type="external">Markus Immitzer</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/David A. Coomes" type="external">David A. Coomes</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Andrew Blake/" type="external">Andrew Blake</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Srinivasan Keshav/" type="external">Srinivasan Keshav</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/tessera2025/</fr:uri>
            <fr:display-uri>tessera2025</fr:display-uri>
            <fr:route>/tessera2025/</fr:route>
            <fr:title text="TESSERA: Temporal Embeddings of Surface Spectra for Earth Representation and Analysis">TESSERA: Temporal Embeddings of Surface Spectra for Earth Representation and Analysis</fr:title>
            <fr:taxon>Reference</fr:taxon>
            <fr:meta name="external">http://arxiv.org/abs/2506.20380</fr:meta>
            <fr:meta name="doi">10.48550/arXiv.2506.20380</fr:meta>
          </fr:frontmatter>
          <fr:mainmatter>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Zhengpeng Feng/" type="external">Zhengpeng Feng</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Clement Atzberger/" type="external">Clement Atzberger</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Sadiq Jaffer/" type="external">Sadiq Jaffer</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Jovana Knezevic/" type="external">Jovana Knezevic</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Silja Sormunen/" type="external">Silja Sormunen</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Robin Young/" type="external">Robin Young</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Madeline C. Lisaius" type="external">Madeline C. Lisaius</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Markus Immitzer/" type="external">Markus Immitzer</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/David A. Coomes" type="external">David A. Coomes</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Andrew Blake/" type="external">Andrew Blake</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Srinivasan Keshav/" type="external">Srinivasan Keshav</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                </fr:date>
                <fr:title text="Abstract">Abstract</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><![CDATA[	Petabytes of satellite Earth Observation (EO) data are freely available and can address critical global challenges. However, EO data quality is poor due to clouds and variable lighting conditions. To address this, practitioners typically use compositing, but this critically removes the temporal phenological signal. Moreover, supervised machine learning to map composited pixels to task-specific classes requires accurately labelled data that are rarely available. We present TESSERA, a pixel-oriented foundation model for EO time series that creates 128-dimensional latent embeddings requiring only a few labels for task-specific training to achieve state-of-the-art performance across diverse complex tasks. TESSERA uses two encoders that combine optical data with synthetic aperture radar backscatter coefficients at 10m resolution, creating embeddings fused with a multilayer perceptron to generate annual global embedding maps. TESSERA closely matches or outperforms state-of-the-art task-specific models and other foundation models across five diverse downstream tasks. It is unprecedented in ease of use, scale, and accuracy: no other open foundation model provides precomputed outputs with global, annual coverage at 10m resolution.]]></html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Anton Lorenzen/" type="external">Anton Lorenzen</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Leo White/" type="external">Leo White</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Stephen Dolan/" type="external">Stephen Dolan</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Richard Eisenberg/" type="external">Richard Eisenberg</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Sam Lindley/" type="external">Sam Lindley</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2024</fr:year>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/oxcaml-2024/</fr:uri>
            <fr:display-uri>oxcaml-2024</fr:display-uri>
            <fr:route>/oxcaml-2024/</fr:route>
            <fr:title text="Oxidizing OCaml with Modal Memory Management">Oxidizing OCaml with Modal Memory Management</fr:title>
            <fr:taxon>Reference</fr:taxon>
            <fr:meta name="external">https://doi.org/10.1145/3674642</fr:meta>
            <fr:meta name="journal">Proceedings of the ACM on Programming Languages</fr:meta>
            <fr:meta name="doi">10.1145/3674642</fr:meta>
          </fr:frontmatter>
          <fr:mainmatter>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Anton Lorenzen/" type="external">Anton Lorenzen</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Leo White/" type="external">Leo White</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Stephen Dolan/" type="external">Stephen Dolan</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Richard Eisenberg/" type="external">Richard Eisenberg</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Sam Lindley/" type="external">Sam Lindley</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2024</fr:year>
                </fr:date>
                <fr:title text="Abstract">Abstract</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Programmers can often improve the performance of their programs by reducing heap allocations: either by allocating on the stack or reusing existing memory in-place. However, without safety guarantees, these optimizations can easily lead to use-after-free errors and even type unsoundness. In this paper, we present a design based on modes which allows programmers to safely reduce allocations by using stack allocation and in-place updates of immutable structures. We focus on three mode axes: affinity, uniqueness and locality. Modes are fully backwards compatible with existing OCaml code and can be completely inferred. Our work makes manual memory management in OCaml safe and convenient and charts a path towards bringing the benefits of Rust to OCaml.</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Eric Zhao/" type="external">Eric Zhao</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Raef Maroof/" type="external">Raef Maroof</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Anand Dukkipati/" type="external">Anand Dukkipati</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Andrew Blinn/" type="external">Andrew Blinn</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Zhiyi Pan/" type="external">Zhiyi Pan</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Cyrus Omar/" type="external">Cyrus Omar</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2024</fr:year>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/zhao-typeerror-2024/</fr:uri>
            <fr:display-uri>zhao-typeerror-2024</fr:display-uri>
            <fr:route>/zhao-typeerror-2024/</fr:route>
            <fr:title text="Total Type Error Localization and Recovery with Holes">Total Type Error Localization and Recovery with Holes</fr:title>
            <fr:taxon>Reference</fr:taxon>
            <fr:meta name="external">https://doi.org/10.1145/3632910</fr:meta>
            <fr:meta name="journal">Proceedings of the ACM on Programming Languages</fr:meta>
            <fr:meta name="doi">10.1145/3632910</fr:meta>
          </fr:frontmatter>
          <fr:mainmatter>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Eric Zhao/" type="external">Eric Zhao</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Raef Maroof/" type="external">Raef Maroof</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Anand Dukkipati/" type="external">Anand Dukkipati</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Andrew Blinn/" type="external">Andrew Blinn</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Zhiyi Pan/" type="external">Zhiyi Pan</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Cyrus Omar/" type="external">Cyrus Omar</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2024</fr:year>
                </fr:date>
                <fr:title text="Abstract">Abstract</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Type systems typically only define the conditions under which an expression is well-typed, leaving ill-typed expressions formally meaningless. This approach is insufficient as the basis for language servers driving modern programming environments, which are expected to recover from simultaneously localized errors and continue to provide a variety of downstream semantic services. This paper addresses this problem, contributing the first comprehensive formal account of total type error localization and recovery: the marked lambda calculus. In particular, we define a gradual type system for expressions with marked errors, which operate as non-empty holes, together with a total procedure for marking arbitrary unmarked expressions. We mechanize the metatheory of the marked lambda calculus in Agda and implement it, scaled up, as the new basis for Hazel, a full-scale live functional programming environment with, uniquely, no meaningless editor states.  

The marked lambda calculus is bidirectionally typed, so localization decisions are systematically predictable based on a local flow of typing information. Constraint-based type inference can bring more distant information to bear in discovering inconsistencies but this notoriously complicates error localization. We approach this problem by deploying constraint solving as a type-hole-filling layer atop this gradual bidirectionally typed core. Errors arising from inconsistent unification constraints are localized exclusively to type and expression holes, i.e. the system identifies unfillable holes using a system of traced provenances, rather than localized in an ad hoc manner to particular expressions. The user can then interactively shift these errors to particular downstream expressions by selecting from suggested partially consistent type hole fillings, which returns control back to the bidirectional system. We implement this type hole inference system in Hazel.</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Vimala Soundarapandian/" type="external">Vimala Soundarapandian</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Adharsh Kamath/" type="external">Adharsh Kamath</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Kartik Nagar/" type="external">Kartik Nagar</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/KC Sivaramakrishnan/" type="external">KC Sivaramakrishnan</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2022</fr:year>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/kcrsk-mrdts-2022/</fr:uri>
            <fr:display-uri>kcrsk-mrdts-2022</fr:display-uri>
            <fr:route>/kcrsk-mrdts-2022/</fr:route>
            <fr:title text="Certified mergeable replicated data types">Certified mergeable replicated data types</fr:title>
            <fr:taxon>Reference</fr:taxon>
            <fr:meta name="external">https://doi.org/10.1145/3519939.3523735</fr:meta>
            <fr:meta name="journal">Proceedings of the 43rd ACM SIGPLAN International Conference on Programming Language Design and Implementation</fr:meta>
            <fr:meta name="doi">10.1145/3519939.3523735</fr:meta>
          </fr:frontmatter>
          <fr:mainmatter>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Vimala Soundarapandian/" type="external">Vimala Soundarapandian</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Adharsh Kamath/" type="external">Adharsh Kamath</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Kartik Nagar/" type="external">Kartik Nagar</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/KC Sivaramakrishnan/" type="external">KC Sivaramakrishnan</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2022</fr:year>
                </fr:date>
                <fr:title text="Abstract">Abstract</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><![CDATA[Replicated data types (RDTs) are data structures that permit concurrent modification of multiple, potentially geo-distributed, replicas without coordination between them. RDTs are designed in such a way that conflicting operations are eventually deterministically reconciled ensuring convergence. Constructing correct RDTs remains a difficult endeavour due to the complexity of reasoning about independently evolving states of the replicas. With the focus on the correctness of RDTs (and rightly so), existing approaches to RDTs are less efficient compared to their sequential counterparts in terms of the time and space complexity of local operations. This is unfortunate since RDTs are often used in a local-first setting where the local operations far outweigh remote communication. This paper presents PEEPUL, a pragmatic approach to building and verifying efficient RDTs. To make reasoning about correctness easier, we cast RDTs in the mould of the distributed version control system, and equip it with a three-way merge function for reconciling conflicting versions. Further, we go beyond just verifying convergence, and provide a methodology to verify arbitrarily complex specifications. We develop a replication-aware simulation relation to relate RDT specifications to their efficient purely functional implementations. We implement PEEPUL as an F* library that discharges proof obligations to an SMT solver. The verified efficient RDTs are extracted as OCaml code and used in Irmin, a distributed database built on the principles of Git.]]></html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Andrey Mokhov/" type="external">Andrey Mokhov</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Georgy Lukyanov/" type="external">Georgy Lukyanov</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Simon Marlow/" type="external">Simon Marlow</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Jeremie Dimino/" type="external">Jeremie Dimino</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2019</fr:year>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/mokhov-selective-2019/</fr:uri>
            <fr:display-uri>mokhov-selective-2019</fr:display-uri>
            <fr:route>/mokhov-selective-2019/</fr:route>
            <fr:title text="Selective applicative functors">Selective applicative functors</fr:title>
            <fr:taxon>Reference</fr:taxon>
            <fr:meta name="external">https://doi.org/10.1145/3341694</fr:meta>
            <fr:meta name="journal">Proceedings of the ACM on Programming Languages</fr:meta>
            <fr:meta name="doi">10.1145/3341694</fr:meta>
          </fr:frontmatter>
          <fr:mainmatter>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Andrey Mokhov/" type="external">Andrey Mokhov</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Georgy Lukyanov/" type="external">Georgy Lukyanov</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Simon Marlow/" type="external">Simon Marlow</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Jeremie Dimino/" type="external">Jeremie Dimino</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2019</fr:year>
                </fr:date>
                <fr:title text="Abstract">Abstract</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Applicative functors and monads have conquered the world of functional programming by providing general and powerful ways of describing effectful computations using pure functions. Applicative functors provide a way to compose independent effects that cannot depend on values produced by earlier computations, and all of which are declared statically. Monads extend the applicative interface by making it possible to compose dependent effects, where the value computed by one effect determines all subsequent effects, dynamically.  This paper introduces an intermediate abstraction called selective applicative functors that requires all effects to be declared statically, but provides a way to select which of the effects to execute dynamically. We demonstrate applications of the new abstraction on several examples, including two industrial case studies.</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Andrey Mokhov/" type="external">Andrey Mokhov</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Neil Mitchell/" type="external">Neil Mitchell</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Simon Jones/" type="external">Simon Jones</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2018</fr:year>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/mokhov-build-systems/</fr:uri>
            <fr:display-uri>mokhov-build-systems</fr:display-uri>
            <fr:route>/mokhov-build-systems/</fr:route>
            <fr:title text="Build systems a la carte">Build systems a la carte</fr:title>
            <fr:taxon>Reference</fr:taxon>
            <fr:meta name="external">https://doi.org/10.1145/3236774</fr:meta>
            <fr:meta name="journal">Proceedings of the ACM on Programming Languages</fr:meta>
            <fr:meta name="doi">10.1145/3236774</fr:meta>
          </fr:frontmatter>
          <fr:mainmatter>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Andrey Mokhov/" type="external">Andrey Mokhov</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Neil Mitchell/" type="external">Neil Mitchell</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Simon Jones/" type="external">Simon Jones</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2018</fr:year>
                </fr:date>
                <fr:title text="Abstract">Abstract</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Build systems are awesome, terrifying -- and unloved. They are used by every developer around the world, but are rarely the object of study. In this paper we offer a systematic, and executable, framework for developing and comparing build systems, viewing them as related points in landscape rather than as isolated phenomena. By teasing apart existing build systems, we can recombine their components, allowing us to prototype new build systems with desired properties.</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Eric Seidel/" type="external">Eric Seidel</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Ranjit Jhala/" type="external">Ranjit Jhala</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2017</fr:year>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/ocaml-corpus/</fr:uri>
            <fr:display-uri>ocaml-corpus</fr:display-uri>
            <fr:route>/ocaml-corpus/</fr:route>
            <fr:title text="A Collection of Novice Interactions with the OCaml Top-Level System">A Collection of Novice Interactions with the OCaml Top-Level System</fr:title>
            <fr:taxon>Reference</fr:taxon>
            <fr:meta name="external">https://doi.org/10.5281/zenodo.806814</fr:meta>
            <fr:meta name="journal">Zenodo</fr:meta>
            <fr:meta name="doi">10.5281/zenodo.806814</fr:meta>
          </fr:frontmatter>
          <fr:mainmatter>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Eric Seidel/" type="external">Eric Seidel</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Ranjit Jhala/" type="external">Ranjit Jhala</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2017</fr:year>
                </fr:date>
                <fr:title text="Abstract">Abstract</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><![CDATA[We recruited around 50 students each across two instances of the CSE 130 (Undergraduate Programming Languages) course at UC San Diego (IRB #140608) to use an instrumented version of the ocaml-top editor, which logged each of their interactions with the top-level system while they worked on the first three homework assignments.]]></html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Tim Storer/" type="external">Tim Storer</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2017</fr:year>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/storer2017bridging/</fr:uri>
            <fr:display-uri>storer2017bridging</fr:display-uri>
            <fr:route>/storer2017bridging/</fr:route>
            <fr:title text="Bridging the chasm: A survey of software engineering practice in scientific programming">Bridging the chasm: A survey of software engineering practice in scientific programming</fr:title>
            <fr:taxon>Reference</fr:taxon>
            <fr:meta name="journal">ACM Computing Surveys (CSUR)</fr:meta>
            <fr:meta name="doi">10.1145/3084225</fr:meta>
          </fr:frontmatter>
          <fr:mainmatter>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Tim Storer/" type="external">Tim Storer</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2017</fr:year>
                </fr:date>
                <fr:title text="Abstract">Abstract</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>
			The use of software is pervasive in all fields of science.
			Associated software development efforts may be very large,
			long-lived, and complex, requiring the commitment of significant
			resources. However, several authors have argued that the "gap" or
			"chasm" between software engineering and scientific programming is
			a serious risk to the production of reliable scientific results, as
			demonstrated in a number of case studies. This article reviews the
			research that addresses the gap, exploring how both software
			engineering and research practice may need to evolve to accommodate
			the use of software in science.
</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Cyrus Omar/" type="external">Cyrus Omar</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Ian Voysey/" type="external">Ian Voysey</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Michael Hilton/" type="external">Michael Hilton</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Jonathan Aldrich/" type="external">Jonathan Aldrich</fr:link>
              </fr:author>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Matthew Hammer/" type="external">Matthew Hammer</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2017</fr:year>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/omar-hazel-2017/</fr:uri>
            <fr:display-uri>omar-hazel-2017</fr:display-uri>
            <fr:route>/omar-hazel-2017/</fr:route>
            <fr:title text="Hazelnut: a bidirectionally typed structure editor calculus">Hazelnut: a bidirectionally typed structure editor calculus</fr:title>
            <fr:taxon>Reference</fr:taxon>
            <fr:meta name="external">https://doi.org/10.1145/3093333.3009900</fr:meta>
            <fr:meta name="journal">SIGPLAN Not.</fr:meta>
            <fr:meta name="doi">10.1145/3093333.3009900</fr:meta>
          </fr:frontmatter>
          <fr:mainmatter>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Cyrus Omar/" type="external">Cyrus Omar</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Ian Voysey/" type="external">Ian Voysey</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Michael Hilton/" type="external">Michael Hilton</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Jonathan Aldrich/" type="external">Jonathan Aldrich</fr:link>
                  </fr:author>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Matthew Hammer/" type="external">Matthew Hammer</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2017</fr:year>
                </fr:date>
                <fr:title text="Abstract">Abstract</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Structure editors allow programmers to edit the tree structure of a program directly. This can have cognitive benefits, particularly for novice and end-user programmers. It also simplifies matters for tool designers, because they do not need to contend with malformed program text. This paper introduces Hazelnut, a structure editor based on a small bidirectionally typed lambda calculus extended with holes and a cursor. Hazelnut goes one step beyond syntactic well-formedness: its edit actions operate over statically meaningful incomplete terms. Naively, this would force the programmer to construct terms in a rigid "outside-in" manner. To avoid this problem, the action semantics automatically places terms assigned a type that is inconsistent with the expected type inside a hole. This meaningfully defers the type consistency check until the term inside the hole is finished. Hazelnut is not intended as an end-user tool itself. Instead, it serves as a foundational account of typed structure editing. To that end, we describe how Hazelnut's rich metatheory, which we have mechanized using the Agda proof assistant, serves as a guide when we extend the calculus to include binary sum types. We also discuss various interpretations of holes, and in so doing reveal connections with gradual typing and contextual modal type theory, the Curry-Howard interpretation of contextual modal logic. Finally, we discuss how Hazelnut's semantics lends itself to implementation as an event-based functional reactive program. Our simple reference implementation is written using js_of_ocaml.</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Louis Pouzin/" type="external">Louis Pouzin</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2013</fr:year>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/pouzin-shell-2013/</fr:uri>
            <fr:display-uri>pouzin-shell-2013</fr:display-uri>
            <fr:route>/pouzin-shell-2013/</fr:route>
            <fr:title text="The Origin of the Shell">The Origin of the Shell</fr:title>
            <fr:taxon>Reference</fr:taxon>
            <fr:meta name="external">https://people.csail.mit.edu/saltzer/Multics/Multics-Documents/MDN/MDN-4.pdf</fr:meta>
            <fr:meta name="journal">Multics Documents</fr:meta>
            <fr:meta name="doi" />
          </fr:frontmatter>
          <fr:mainmatter>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Louis Pouzin/" type="external">Louis Pouzin</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2013</fr:year>
                </fr:date>
                <fr:title text="Abstract">Abstract</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>How RUNCOM was created for CTSS and the shell was designed for Multics by Louis Pouzin.</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
      </fr:mainmatter>
    </fr:tree>
    <fr:tree show-metadata="false" hidden-when-empty="true">
      <fr:frontmatter>
        <fr:authors />
        <fr:title text="Context">Context</fr:title>
      </fr:frontmatter>
      <fr:mainmatter />
    </fr:tree>
    <fr:tree show-metadata="false" hidden-when-empty="true">
      <fr:frontmatter>
        <fr:authors />
        <fr:title text="Backlinks">Backlinks</fr:title>
      </fr:frontmatter>
      <fr:mainmatter />
    </fr:tree>
    <fr:tree show-metadata="false" hidden-when-empty="true">
      <fr:frontmatter>
        <fr:authors />
        <fr:title text="Related">Related</fr:title>
      </fr:frontmatter>
      <fr:mainmatter>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:uri>https://patrick.sirref.org/camcst/</fr:uri>
            <fr:display-uri>camcst</fr:display-uri>
            <fr:route>/camcst/</fr:route>
            <fr:title text="Department of Computer Science and Technology, University of Cambridge">Department of Computer Science and Technology, University of Cambridge</fr:title>
            <fr:taxon>department</fr:taxon>
            <fr:meta name="external">https://www.cst.cam.ac.uk/</fr:meta>
          </fr:frontmatter>
          <fr:mainmatter />
        </fr:tree>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:uri>https://patrick.sirref.org/geocaml/</fr:uri>
            <fr:display-uri>geocaml</fr:display-uri>
            <fr:route>/geocaml/</fr:route>
            <fr:title text="Geocaml">Geocaml</fr:title>
            <fr:taxon>Github Organisation</fr:taxon>
            <fr:meta name="external">https://github.com/geocaml</fr:meta>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>Geocaml is an attempt to provide the OCaml community with a suite of geospatial libraries, for example:</html:p>
            <html:ul>
              <html:li>
                <html:p>A <fr:link href="https://github.com/geocaml/ocaml-geojson" type="external">Geojson</fr:link> library in pure OCaml.</html:p>
              </html:li>
              <html:li>
                <html:p>A tool for querying <fr:link href="https://github.com/geocaml/carbon-intensity" type="external">carbon intensity APIs</fr:link>.</html:p>
              </html:li>
              <html:li>
                <html:p><fr:link href="https://github.com/geocaml/ISO3166" type="external">ISO3166 country codes</fr:link>.</html:p>
              </html:li>
            </html:ul>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:uri>https://patrick.sirref.org/ni-forests/</fr:uri>
            <fr:display-uri>ni-forests</fr:display-uri>
            <fr:route>/ni-forests/</fr:route>
            <fr:title text="Northern Irish Forests">Northern Irish Forests</fr:title>
            <fr:taxon>Project</fr:taxon>
            <fr:meta name="external">https://patricoferris.github.io/ni-forests/</fr:meta>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>A small and simple application written during <fr:link href="https://ukcop26.org/" type="external">COP26</fr:link> to learn more about forests/habitats in Northern Ireland. It is <fr:link href="https://patricoferris.github.io/ni-forests/" type="external">available online</fr:link> and there's a more accessible, low-bandwidth <fr:link href="https://patricoferris.github.io/ni-forests/text.html" type="external">text version too</fr:link>.</html:p>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:uri>https://patrick.sirref.org/outreachy/</fr:uri>
            <fr:display-uri>outreachy</fr:display-uri>
            <fr:route>/outreachy/</fr:route>
            <fr:title text="Outreachy">Outreachy</fr:title>
            <fr:taxon>Project</fr:taxon>
            <fr:meta name="external">https://www.outreachy.org/</fr:meta>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:blockquote>
              <html:p>Outreachy provides internships in open source and open science. Outreachy provides internships to people subject to systemic bias and impacted by underrepresentation in the technical industry where they are living.</html:p>
            </html:blockquote>
            <html:p>I am one of the coordinators for the <html:em>OCaml community</html:em> for Outreachy. I have also mentored multiple three-month internships for the community.</html:p>
            <html:hr />
            <fr:tree show-metadata="true" expanded="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2026</fr:year>
                  <fr:month>2</fr:month>
                  <fr:day>9</fr:day>
                </fr:date>
                <fr:uri>https://patrick.sirref.org/outreachy-ocaml-tiff/</fr:uri>
                <fr:display-uri>outreachy-ocaml-tiff</fr:display-uri>
                <fr:route>/outreachy-ocaml-tiff/</fr:route>
                <fr:title text="Write support in OCaml TIFF library">Write support in OCaml TIFF library</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I am mentoring <fr:link href="/tambe-salome/" title="Tambe Salome" uri="https://patrick.sirref.org/tambe-salome/" display-uri="tambe-salome" type="local">Tambe Salome</fr:link> during the December 2025 Outreachy round to add support for writing TIFF files in the <fr:link href="/ocaml-tiff/" title="ocaml-tiff" uri="https://patrick.sirref.org/ocaml-tiff/" display-uri="ocaml-tiff" type="local">ocaml-tiff</fr:link> library.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="true" expanded="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2022</fr:year>
                  <fr:month>12</fr:month>
                  <fr:day>1</fr:day>
                </fr:date>
                <fr:uri>https://patrick.sirref.org/topojson-0001/</fr:uri>
                <fr:display-uri>topojson-0001</fr:display-uri>
                <fr:route>/topojson-0001/</fr:route>
                <fr:title text="Implement a non-blocking, streaming codec for TopoJSON">Implement a non-blocking, streaming codec for TopoJSON</fr:title>
                <fr:meta name="external">https://github.com/geocaml/ocaml-geojson</fr:meta>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>GeoJSON is a JSON standardised format for handling simple geographical data. One common use of GeoJSON is to add map overlays such as with the popular JavaScript library leaflet. One issue with GeoJSON is redundant data, for example when two polygons share boundaries ideally only one would contain the full data about the boundary, however, with GeoJSON the data is duplicated.</html:p>
                <html:p>TopoJSON is an extension to GeoJSON to encode topology. This allows for redundant data to be removed and file sizes to be greatly reduced. This is often very desirable especially when working with data in the browser. In a previous Outreachy internship a new OCaml library was implemented to provide an OCaml library for TopoJSON, this project will build on this adding more functionality to the library and providing a non-blocking, streaming codec version similar to the geojsone library.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="true" expanded="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2022</fr:year>
                  <fr:month>6</fr:month>
                  <fr:day>1</fr:day>
                </fr:date>
                <fr:uri>https://patrick.sirref.org/topojson-0002/</fr:uri>
                <fr:display-uri>topojson-0002</fr:display-uri>
                <fr:route>/topojson-0002/</fr:route>
                <fr:title text="Extend OCaml's GeoJSON library to support TopoJSON">Extend OCaml's GeoJSON library to support TopoJSON</fr:title>
                <fr:meta name="external">https://github.com/geocaml/ocaml-geojson</fr:meta>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>GeoJSON is a JSON standardised format for handling simple geographical data. One common use of GeoJSON is to add map overlays such as with the popular JavaScript library leaflet. One issue with GeoJSON is redundant data, for example when two polygons share boundaries ideally only one would contain the full data about the boundary, however, with GeoJSON the data is duplicated.</html:p>
                <html:p>TopoJSON is an extension to GeoJSON to encode topology. This allows for redundant data to be removed and file sizes to be greatly reduced. This is often very desirable especially when working with data in the browser. In a previous Outreachy internship a new OCaml library was implemented to provide an OCaml library for TopoJSON, this project will build on this adding more functionality to the library and providing a non-blocking, streaming codec version similar to the geojsone library.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="true" expanded="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2021</fr:year>
                  <fr:month>6</fr:month>
                  <fr:day>1</fr:day>
                </fr:date>
                <fr:uri>https://patrick.sirref.org/ocamlorg-0001/</fr:uri>
                <fr:display-uri>ocamlorg-0001</fr:display-uri>
                <fr:route>/ocamlorg-0001/</fr:route>
                <fr:title text="Improve the ocaml.org Website">Improve the ocaml.org Website</fr:title>
                <fr:meta name="external">https://ocaml.org</fr:meta>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>OCaml.org is the main website for OCaml, a functional, typed, high-level programming language. This project revolves around improving the website on multiple different fronts including: layout, accessibility and content.</html:p>
                <html:p>Because a lot of the content of the website is about OCaml and the website itself is written in OCaml, this would be a great opportunity for interns to learn the language and functional programming concepts.</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:uri>https://patrick.sirref.org/ucam/</fr:uri>
            <fr:display-uri>ucam</fr:display-uri>
            <fr:route>/ucam/</fr:route>
            <fr:title text="University of Cambridge">University of Cambridge</fr:title>
            <fr:taxon>institution</fr:taxon>
            <fr:meta name="external">https://www.cam.ac.uk/</fr:meta>
          </fr:frontmatter>
          <fr:mainmatter />
        </fr:tree>
      </fr:mainmatter>
    </fr:tree>
    <fr:tree show-metadata="false" hidden-when-empty="true">
      <fr:frontmatter>
        <fr:authors />
        <fr:title text="Contributions">Contributions</fr:title>
      </fr:frontmatter>
      <fr:mainmatter />
    </fr:tree>
  </fr:backmatter>
</fr:tree>
