<?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="false" base-url="/">
  <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> an inner shell (e.g. <html:code>zsh</html:code>) and enjoy all the usual features 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:uri>https://patrick.sirref.org/pouzin-shell/</fr:uri>
        <fr:display-uri>pouzin-shell</fr:display-uri>
        <fr:route>/pouzin-shell/</fr:route>
        <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 no other process in active execution under console control (presently called command level). This procedure acts as an interface between console messages and subroutine. The purpose of such a procedure is to create a medium of exchange into which one could activate any procedure, <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>I helped review some changes to enable Janestreet to have ppx rewriters via attributes (usually they are via extension 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">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>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>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: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/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 show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:uri>https://patrick.sirref.org/weeklies-2025/</fr:uri>
            <fr:display-uri>weeklies-2025</fr:display-uri>
            <fr:route>/weeklies-2025/</fr:route>
            <fr:title text="Patrick Ferris' Weeklies › 2025 "><fr:link href="/weeklies/" title="Patrick Ferris' Weeklies" uri="https://patrick.sirref.org/weeklies/" display-uri="weeklies" type="local">Patrick Ferris' Weeklies</fr:link> › 2025 </fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <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> 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 local opens (e.g. <html:code>let open M in</html:code>). This has now been extended to include any 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>This tends to be used for things like function arguments (e.g. <html:code>fun (x : int) -&gt; x + 1</html:code>). 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>Our type constraint (<html:code>: int</html:code>) 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> (which <html:code>repr</html:code> was still using) actually transforms instances of <html:code>let x : t = ...</html:code> into <html:code>let (x : t) = ...</html:code>! This limitation does not seem inherent to the parsetree, the printer or the migrations. But I have asked the (very kind and friendly) previous maintainers about these changes.</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 becomes much easier to swap out one resource for another (provided they have 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> 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> 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>('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> 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>, 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 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> 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>). 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 (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>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 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>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>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>. 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>We also get the name of the current executable linked to the task (<html:code>comm</html:code>). 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> (or), <html:code>&amp;</html:code> (and), and <html:code>~</html:code> (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> 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> 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> (<html:code>clone</html:code>). 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>. 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> (via <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">eio</fr:link>) 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> 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>).</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. I have tried quite a few methods (e.g. tracing <html:code>do_filp_open</html:code>) 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>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> an inner shell (e.g. <html:code>zsh</html:code>) and enjoy all the usual features 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:uri>https://patrick.sirref.org/pouzin-shell/</fr:uri>
                    <fr:display-uri>pouzin-shell</fr:display-uri>
                    <fr:route>/pouzin-shell/</fr:route>
                    <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 no other process in active execution under console control (presently called command level). This procedure acts as an interface between console messages and subroutine. The purpose of such a procedure is to create a medium of exchange into which one could activate any procedure, <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>I helped review some changes to enable Janestreet to have ppx rewriters via attributes (usually they are via extension 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">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>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>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>The question mark (<html:code>?</html:code>) is a hole. The program evaluates to the following expression of type <html:code><![CDATA[[?]]]></html:code> (for people more familiar with OCaml types <html:code>? list</html:code>).</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> (<html:code>fun x -&gt; x + 1</html:code>) 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 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 with no support for modules or labelled records out of the box (there are plenty of development branches 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 (parentheses for function arguments, well-scoped cases for pattern-matching, a different arrow for pattern-matching etc.). What would be more interesting is taking a look at how to handle polymorphism in Hazel.</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>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>) 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> function (whether that be recursively or somewhere later in our 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> 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> 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 (e.g. handling the <html:code>cmi</html:code> 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 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> 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 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 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>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> library using process-level parallelism (via <html:code>Unix.fork</html:code>), 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>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>) 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)">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>s (which now have location information for all segments of the <html:code>Longident</html:code>). 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> (in ppxlib terms, we know have migration functions for 5.3 &lt;-&gt; 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>. 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> is a theorem prover (originally called <html:code>coq</html:code>) 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> (also in <fr:link href="https://github.com/patricoferris/difc-star" type="external">Fstar</fr:link>).</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>, 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. 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>. 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>). 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:uri>https://patrick.sirref.org/void-processes/</fr:uri>
                    <fr:display-uri>void-processes</fr:display-uri>
                    <fr:route>/void-processes/</fr:route>
                    <fr:title text="Void Processes ">Void Processes </fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>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>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>), 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>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>).</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> 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>On paper, I don't have that many students. I teach four undergraduates (first 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 had their mid-project demonstrations (a five-minute presentation in front of 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> (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-mdx-hash">#</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-mdx-hash">#</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-mdx-hash">#</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>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: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: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> (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>). 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> 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="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:uri>https://patrick.sirref.org/mdales/</fr:uri>
            <fr:display-uri>mdales</fr:display-uri>
            <fr:route>/mdales/</fr:route>
            <fr:title text="Michael W. Dales">Michael W. Dales</fr:title>
            <fr:meta name="external">https://digitalflapjack.com</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/ppxlib/</fr:uri>
            <fr:display-uri>ppxlib</fr:display-uri>
            <fr:route>/ppxlib/</fr:route>
            <fr:title text="Ppxlib">Ppxlib</fr:title>
            <fr:meta name="external">https://github.com/ocaml-ppx/ppxlib</fr:meta>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>An OCaml library and ecosystem for preprocessing.</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/ryangibb/</fr:uri>
            <fr:display-uri>ryangibb</fr:display-uri>
            <fr:route>/ryangibb/</fr:route>
            <fr:title text="Ryan Gibb">Ryan Gibb</fr:title>
            <fr:meta name="postion">PhD Student and Nix Guru</fr:meta>
            <fr:meta name="external">https://ryan.freumh.org</fr:meta>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>Fellow <fr:link href="https://github.com/fn06" type="external">FN06</fr:link> hacker.</html:p>
          </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>
