<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <updated>2025-11-24T00:00:00-00:00</updated>
  <title>Patrick Ferris' Weeklies</title>
  <id>https://patrick.sirref.org/weeklies/</id>
  <link rel="alternate" href="https://patrick.sirref.org/weeklies/" />
  <link rel="self" href="https://patrick.sirref.org/weeklies/atom.xml" />
  <entry>
    <title>Data Provenance in Shelter</title>
    <published>2025-11-24T00:00:00-00:00</published>
    <updated>2025-11-24T00:00:00-00:00</updated>
    <author>
      <name>https://patrick.sirref.org/Patrick/</name>
      <uri>https://patrick.sirref.org/Patrick/</uri>
    </author>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/weekly-2025-w49/" />
    <id>https://patrick.sirref.org/weekly-2025-w49/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>A late update that stretches more than a week...</p>
        <section>
          <header>
            <h2>@ How?</h2>
          </header>
          <p>A quick update on a new feature that was added recently, the <code>@ how</code> <a href="https://shelter.sirref.org/shelter-0002/">meta-command</a>.</p>
          <p><![CDATA[One of the issues facing any exploratory programmer (or indeed anybody]]>  <![CDATA[returning to a project) is the]]> <em>provenance</em> of a given file. How that file came to be and who and what processes have interacted with it since.</p>
          <p>Shelter now has a command for asking exactly that of any given file in the system.</p>
          <pre><![CDATA[echo hello > hello.txt
echo world > world.txt
cat world.txt > hello.txt
@ how hello.txt]]></pre>
          <p>The previous snippet of shell script will output:</p>
          <pre><![CDATA[Ran echo hello > hello.txt
Ran cat world.txt > hello.txt (read: "world.txt")]]></pre>
          <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.</p>
        </section>
        <section>
          <header>
            <h2>OCaml Roundup: November 2025</h2>
          </header>
          <p>A roundup of <em>some</em> of my OCaml activity this month!</p>
          <section>
            <header>
              <h3>Ppxlib Updates</h3>
            </header>
            <p>I managed to get a substantial amount of ppxlib work completed in the last month. Some of those bits are described in detail below.</p>
            <section>
              <header>
                <h4>Initial OCaml 5.5 Support </h4>
              </header>
              <p>We <a href="https://github.com/ocaml-ppx/ppxlib/pull/606">recently merged 5.5 support</a> into our <code>main</code><![CDATA[ branch (thanks to Nathan for the review). It cast a light on]]>  some new features coming to OCaml including the ability to define <em>any</em> structure <em>locally</em>. Most OCaml programmers will be familiar with things like <![CDATA[local opens (e.g.]]> <code>let open M in</code><![CDATA[). This has now been extended to include any]]>  <![CDATA[structure item (more or less, you cannot nest value bindings).]]></p>
              <p><em>External</em> types have also landed, bringing with them a new "type kind" in the AST. You can <a href="https://github.com/gasche/ocaml/blob/44e69a0eb6d57ea2e7dc14c6ea4bac4a260a2d5b/manual/src/refman/extensions/externaltypes.etex">read about them in the manual</a>.</p>
            </section>
            <section>
              <header>
                <h4>Bug Fixes for Attribute Rewriters</h4>
              </header>
              <p>There <a href="https://github.com/ocaml-ppx/ppxlib/pull/613">was a bug</a> in the error handling for attribute rewriters -- a relatively new feature to have been added to ppxlib.</p>
              <p>In some places, ppxlib makes use of a <code>With_error.t</code> monad. Unlike the <code>Result.t</code> monad, <code>With_error.t</code> allows you to <em>collect</em> errors rather than find the first error and thread it through your program. This can make sense if your program can meaningfully do work after encountering an error. Unfortunately, in the logic for replacing attributes, the code could not recover from an error where there were duplicate attributes.</p>
            </section>
            <section>
              <header>
                <h4>Value binding constraints in ppxlib</h4>
              </header>
              <p>I spent a good few hours understanding why the <a href="https://github.com/mirage/repr/pull/110">CI tests in my PR to mirage/repr</a> were still failing. It turns out, the bug, is fairly simple to reproduce. Consider the following OCaml code:</p>
              <pre class="hilite">
                <code><span class="ocaml-keyword">let</span><span class="ocaml-source"> </span><span class="ocaml-entity-name-function-binding">g</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source"> </span><span class="ocaml-support-type">int</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source"> </span><span class="ocaml-constant-numeric-decimal-integer">1</span><span class="ocaml-source">
</span>
</code>
              </pre>
              <p>We have a let-binding that contains a type constraint. Where, in the abstract syntax tree sense, do we attach the constraint? Since OCaml 5.1, we have quite a few options for how this can be represented.</p>
              <p>The first is using the <code>Ppat_constraint</code> AST node which allows you to attach a type constraint to any pattern.</p>
              <pre class="hilite">
                <code><span class="ocaml-source">    </span><span class="ocaml-keyword-other">|</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">Ppat_constraint</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other">of</span><span class="ocaml-source"> </span><span class="ocaml-source">pattern</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">*</span><span class="ocaml-source"> </span><span class="ocaml-source">core_type</span><span class="ocaml-source">
</span>
<span class="ocaml-source">    </span><span class="ocaml-comment-block"><![CDATA[(*]]> </span><span class="ocaml-comment-block"><![CDATA[ (P : T)]]> </span><span class="ocaml-comment-block"><![CDATA[*)]]> </span><span class="ocaml-source">
</span>
</code>
              </pre>
              <p><![CDATA[This tends to be used for things like function arguments (e.g.]]> <code><![CDATA[fun (x : int) -> x + 1]]></code><![CDATA[).]]>  So it doesn't quite capture what we want for this binding constraint.</p>
              <p>On older OCaml compilers, <code>let g : int = 1</code> also includes a <code>Pexp_constraint</code> on the body of the value binding. This makes sense if we consider a more general case of the syntax where we allow functions.</p>
              <pre class="hilite">
                <code><span class="ocaml-keyword">let</span><span class="ocaml-source"> </span><span class="ocaml-entity-name-function-binding">g</span><span class="ocaml-source"> </span><span class="ocaml-source">x</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source"> </span><span class="ocaml-support-type">int</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source"> </span><span class="ocaml-source">x</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">+</span><span class="ocaml-source"> </span><span class="ocaml-constant-numeric-decimal-integer">1</span><span class="ocaml-source">
</span>
</code>
              </pre>
              <p>In this example, we no longer parse a <code>Ppat_constraint</code> and instead this is treated as syntactic sugar for:</p>
              <pre class="hilite">
                <code><span class="ocaml-keyword">let</span><span class="ocaml-source"> </span><span class="ocaml-entity-name-function-binding">g</span><span class="ocaml-source"> </span><span class="ocaml-source">x</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source"> </span><span class="ocaml-source"><![CDATA[(]]> </span><span class="ocaml-source">x</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">+</span><span class="ocaml-source"> </span><span class="ocaml-constant-numeric-decimal-integer">1</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source"> </span><span class="ocaml-support-type">int</span><span class="ocaml-source"><![CDATA[)]]> </span><span class="ocaml-source">
</span>
</code>
              </pre>
              <p>In <a href="https://github.com/ocaml/ocaml/pull/12119">OCaml 5.1 a new field for value bindings was added</a> allowing type constraints to be tracked directly in the bindings themselves.</p>
              <pre class="hilite">
                <code><span class="ocaml-keyword-other">and</span><span class="ocaml-source"> </span><span class="ocaml-source">value_binding</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-source"><![CDATA[{]]> </span><span class="ocaml-source">
</span>
<span class="ocaml-source">    </span><span class="ocaml-source">pvb_pat</span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source"> </span><span class="ocaml-source">pattern</span><span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span><span class="ocaml-source">
</span>
<span class="ocaml-source">    </span><span class="ocaml-source">pvb_expr</span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source"> </span><span class="ocaml-source">expression</span><span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span><span class="ocaml-source">
</span>
<span class="ocaml-source">    </span><span class="ocaml-source">pvb_constraint</span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source"> </span><span class="ocaml-source">poly_constraint</span><span class="ocaml-source"> </span><span class="ocaml-source">option</span><span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span><span class="ocaml-source">
</span>
<span class="ocaml-source">    </span><span class="ocaml-source">pvb_attributes</span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source"> </span><span class="ocaml-source">attributes</span><span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span><span class="ocaml-source">
</span>
<span class="ocaml-source">    </span><span class="ocaml-source">pvb_loc</span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">Location</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">t</span><span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-source"><![CDATA[}]]> </span><span class="ocaml-comment-doc"><![CDATA[(**]]> </span><span class="ocaml-comment-doc"><![CDATA[ [let pat : type_constraint = exp]]]> </span><span class="ocaml-comment-doc"><![CDATA[*)]]> </span><span class="ocaml-source">
</span>
</code>
              </pre>
              <p><![CDATA[Our type constraint (]]> <code>: int</code><![CDATA[) can be recorded in the]]> <code>pvb_constraint</code> directly. This is a nice change, bringing the concrete syntax of the language closer to the parsetree. For ppxlib, however, it does create a bit of a headache as we now have to encode the different versions of expressing type constraints into the AST of the compiler <em>before</em> 5.1!</p>
              <p>So what was the bug? The author's of <code>repr</code> had added some value bindings to circumvent some "unused value warnings" in OCaml. They choose to write these bindings like:</p>
              <pre class="hilite">
                <code><span class="ocaml-keyword-other">let</span><span class="ocaml-source"> </span><span class="ocaml-source"><![CDATA[(]]> </span><span class="ocaml-constant-language">_</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source"> </span><span class="ocaml-support-type">int</span><span class="ocaml-source"><![CDATA[)]]> </span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source"> </span><span class="ocaml-constant-numeric-decimal-integer">1</span><span class="ocaml-source">
</span>
</code>
              </pre>
              <p>Here, I have simplified the types and the body of the binding. The significant thing to notice is the parentheses surrounding the value binding's pattern. This <em>forces</em> the AST representation to be a single <code>Ppat_constraint</code> node regardless of the current compiler version. No <code>Pexp_constraint</code> and no <code>pvb_constraint</code>.</p>
              <p>However, using ppxlib with a compiler less than 5.1 meant that this did not roundtrip cleanly. Instead, the value <em>after</em> passing through ppxlib's migrations was:</p>
              <pre class="hilite">
                <code><span class="ocaml-keyword">let</span><span class="ocaml-source"> </span><span class="ocaml-entity-name-function-binding">_</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source"> </span><span class="ocaml-support-type">int</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source"> </span><span class="ocaml-constant-numeric-decimal-integer">1</span><span class="ocaml-source">
</span>
</code>
              </pre>
              <p>After bottoming out at the issue, I discovered we <a href="https://github.com/ocaml-ppx/ppxlib/blob/22778658345fce526e6146da188cdc2d6d2e5286/test/501_migrations/reverse_migrations.t#L142">already had a test case for this in ppxlib</a>! Whatsomore, <code>ocamlformat.0.20.0</code><![CDATA[ (which]]> <code>repr</code><![CDATA[ was still using) actually]]>  transforms instances of <code>let x : t = ...</code> into <code><![CDATA[let (x : t) = ...]]></code>! This limitation does not seem inherent to the parsetree, the printer or the migrations. But I have <![CDATA[asked the (very kind and friendly) previous maintainers about these changes.]]></p>
            </section>
          </section>
          <section>
            <header>
              <h3>Outreachy</h3>
            </header>
            <p>December 8th 2025 marks the start of the next round of Outreachy. I have been preparing some issues for <a href="https://github.com/geocaml/ocaml-tiff">geocaml/ocaml-tiff</a> and I am excited to get started with <a href="https://github.com/giftcup">Tambe Salome</a>!</p>
          </section>
          <section>
            <header>
              <h3>Graft and Bib </h3>
            </header>
            <p>I spent some time at the start of the month updating and fixing <a href="https://patrick.sirref.org/graft/">Graft</a> and <a href="https://patrick.sirref.org/bib/">Bib</a>.</p>
            <p>I added <a href="https://graft.sirref.org/named-subtrees">named subtrees</a> to the markdown syntax. This allows users to create subtrees with headings that are also externally linkable.</p>
            <p>With some more bug fixing, I hope to release both libraries before the new year!</p>
          </section>
        </section>
      </div>
    </content>
  </entry>
  <entry>
    <title>Shelter imports</title>
    <published>2025-11-15T00:00:00-00:00</published>
    <updated>2025-11-15T00:00:00-00:00</updated>
    <author>
      <name>https://patrick.sirref.org/Patrick Ferris/</name>
      <uri>https://patrick.sirref.org/Patrick%20Ferris/</uri>
    </author>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/weekly-2025-w46/" />
    <id>https://patrick.sirref.org/weekly-2025-w46/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>Most of this week was spent fixing bugs in <a href="https://patrick.sirref.org/shelter/">Shelter</a> in an attempt to get it ready to run the <a href="https://github.com/quantifyearth/LIFE">LIFE</a> pipeline.</p>
        <p>To do so, <a href="https://patrick.sirref.org/shelter/">Shelter</a> 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 <code>@ import</code> statement. In true <a href="https://patrick.sirref.org/forester/">Forester</a> fashion, I have transcluded the <em>foreign</em> tree from my <a href="https://shelter.sirref.org/logs">Shelter logs</a>.</p>
        <section>
          <header>
            <h2>Import statements</h2>
          </header>
          <p>Welcome to the first <a href="https://shelter.sirref.org/index/">Shelter</a> log! In this log I will explain the work I have been doing to add an <code>@ import</code> <a href="https://shelter.sirref.org/shelter-0002/">meta-command</a>.</p>
          <p>The syntax thus far is relatively straightforward.</p>
          <pre><![CDATA[@ import --name=<optional-name> <URI> <DST>]]></pre>
          <p>There are a few key principles underlying <code>@ import</code>.</p>
          <ol>
            <li>
              <p>It should be at least as expressive as Docker's <code>COPY ...</code> command.</p>
            </li>
            <li>
              <p>It should deal with a wider variety of import sources. In addition to local <![CDATA[file paths this could be data over HTTP (]]> <code>https://</code><![CDATA[), git repositories, zip]]>  archives over ssh etc.</p>
            </li>
            <li>
              <p>Imports, where possible, should be catalogued and shared across <a href="https://shelter.sirref.org/at-session/">sessions</a>.</p>
            </li>
          </ol>
          <section>
            <header>
              <h3>URIs as Sources</h3>
            </header>
            <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:</p>
            <pre><![CDATA[@ import shelter.opam .
opam install . --deps-only --with-test]]></pre>
            <p>By allowing arbitrary URIs in the import command, we hope to force users away from downloading data via <code>curl</code> or python scripts. Lifting these side-effectful imports into <a href="https://shelter.sirref.org/shelter/">Shelter</a> allows us to manage the data in a much cleaner fashion.</p>
          </section>
          <section>
            <header>
              <h3>Scripts as Sources</h3>
            </header>
            <p>One idea I had was to allow users to invoke scripts as there "import source". Something like:</p>
            <pre><![CDATA[@ import -- python download_gedi_data.py]]></pre>
            <p>And using the same <a href="https://shelter.sirref.org/shelter-tracing/">eBPF tracing</a> we use during normal execution we can capture a fairly good idea of the tools and files needed to perform an import.</p>
          </section>
          <section>
            <header>
              <h3>Sharing Imports</h3>
            </header>
            <p>One example of better data management is that <a href="https://shelter.sirref.org/shelter/">Shelter</a> imports can be <![CDATA[explicitly shared across sessions via the naming mechanism (also by hash).]]></p>
            <p>When a user imports some data, they can optionally name that piece of data. For example:</p>
            <pre><![CDATA[@ import
  --name=belfast-trees \
  https://www.belfastcity.gov.uk/getmedia/262a1f01-f219-4780-835e-7a833bdd1e1c/odTrees.csv \
  /home]]></pre>
            <p><a href="https://shelter.sirref.org/shelter/">Shelter</a> 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:</p>
            <pre><![CDATA[@ import --name=belfast-trees /var/lib]]></pre>
            <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 <em>version</em> the data and have a means by which to update said data, one could imagine:</p>
            <pre><![CDATA[@ update --name=belfast-trees]]></pre>
            <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.</p>
          </section>
        </section>
        <section>
          <header>
            <h2>Eio Debugging </h2>
          </header>
          <p>One of the promises of <a href="https://patrick.sirref.org/eio/">Eio</a>'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 <code>load_config</code> function, more than likely it will need access to the file-system.</p>
          <pre class="hilite">
            <code><span class="ocaml-keyword-other">val</span><span class="ocaml-source"> </span><span class="ocaml-source">load_config</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source"> </span><span class="ocaml-constant-language">_</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">Eio</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-constant-language-capital-identifier">Path</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">t</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">-&gt;</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">Config</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">t</span><span class="ocaml-source">
</span>
<span class="ocaml-comment-doc"><![CDATA[(**]]> </span><span class="ocaml-comment-doc"><![CDATA[ [load_config path] loads a configuration from [path].]]> </span><span class="ocaml-comment-doc"><![CDATA[*)]]> </span><span class="ocaml-source">
</span>
</code>
          </pre>
          <p>Once all of your resources are explicit and threaded through your program, it <![CDATA[becomes much easier to swap out one resource for another (provided they have]]>  <![CDATA[the same interface).]]></p>
          <p>This week I was trying to get the <a href="https://github.com/quantifyearth/LIFE">LIFE</a> pipeline running in <a href="https://patrick.sirref.org/shelter/">shelter</a>. Part of that involves pulling the <a href="ghcr.io/osgeo/gdal:ubuntu-small-3.11.4">appropriate geospatial container image</a>, but my code was terrifically broken, failing with what looked to me with a Docker error.</p>
          <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 <code>_ Eio.Process.mgr</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!</p>
          <pre class="hilite">
            <code><span class="ocaml-keyword">let</span><span class="ocaml-source"> </span><span class="ocaml-entity-name-function-binding">debug_process_mgr</span><span class="ocaml-source"> </span><span class="ocaml-source"><![CDATA[(]]> </span><span class="ocaml-source">mgr</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source"> </span><span class="ocaml-storage-type">'a</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">Eio_unix</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-constant-language-capital-identifier">Process</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">mgr</span><span class="ocaml-source"><![CDATA[)]]> </span><span class="ocaml-source"> </span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source"> </span><span class="ocaml-storage-type">'a</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">Eio_unix</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-constant-language-capital-identifier">Process</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">mgr</span><span class="ocaml-source">
</span>
<span class="ocaml-source">    </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-keyword">let</span><span class="ocaml-source"> </span><span class="ocaml-keyword">module</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">D</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other">struct</span><span class="ocaml-source">
</span>
<span class="ocaml-source">    </span><span class="ocaml-keyword-other">type</span><span class="ocaml-source"> </span><span class="ocaml-source">t</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source"> </span><span class="ocaml-support-type">unit</span><span class="ocaml-source">
</span>
<span class="ocaml-source">
</span>
<span class="ocaml-source">    </span><span class="ocaml-keyword">let</span><span class="ocaml-source"> </span><span class="ocaml-entity-name-function-binding">spawn_unix</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-unit"><![CDATA[()]]> </span><span class="ocaml-source"> ~</span><span class="ocaml-source">sw</span><span class="ocaml-source"> ?</span><span class="ocaml-source">cwd</span><span class="ocaml-source"> ?</span><span class="ocaml-source">pgid</span><span class="ocaml-source"> ?</span><span class="ocaml-source">uid</span><span class="ocaml-source"> ?</span><span class="ocaml-source">gid</span><span class="ocaml-source"> ~</span><span class="ocaml-source">env</span><span class="ocaml-source"> ~</span><span class="ocaml-source">fds</span><span class="ocaml-source"> ~</span><span class="ocaml-source">executable</span><span class="ocaml-source"> </span><span class="ocaml-source">args</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source">
</span>
<span class="ocaml-source">      </span><span class="ocaml-constant-language-capital-identifier">Eio</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">traceln</span><span class="ocaml-source"> </span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-string-quoted-double">Spawning subprocess... </span><span class="ocaml-constant-character-printf"><![CDATA[%a]]> </span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">Fmt</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source"><![CDATA[(]]> </span><span class="ocaml-source">list</span><span class="ocaml-source"> </span><span class="ocaml-support-type">string</span><span class="ocaml-source"><![CDATA[)]]> </span><span class="ocaml-source"> </span><span class="ocaml-source">args</span><span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span><span class="ocaml-source">
</span>
<span class="ocaml-source">      </span><span class="ocaml-constant-language-capital-identifier">Eio_unix</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-constant-language-capital-identifier">Process</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">spawn_unix</span><span class="ocaml-source"> ~</span><span class="ocaml-source">sw</span><span class="ocaml-source"> ?</span><span class="ocaml-source">cwd</span><span class="ocaml-source"> ?</span><span class="ocaml-source">pgid</span><span class="ocaml-source"> ?</span><span class="ocaml-source">uid</span><span class="ocaml-source"> ?</span><span class="ocaml-source">gid</span><span class="ocaml-source"> </span><span class="ocaml-source">mgr</span><span class="ocaml-source"> ~</span><span class="ocaml-source">env</span><span class="ocaml-source"> ~</span><span class="ocaml-source">fds</span><span class="ocaml-source">
</span>
<span class="ocaml-source">        ~</span><span class="ocaml-source">executable</span><span class="ocaml-source"> </span><span class="ocaml-source">args</span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-keyword-other">end</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other">in</span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-keyword">let</span><span class="ocaml-source"> </span><span class="ocaml-keyword">module</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">V</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">Eio_unix</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-constant-language-capital-identifier">Process</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-constant-language-capital-identifier">Make_mgr</span><span class="ocaml-source"> </span><span class="ocaml-source"><![CDATA[(]]> </span><span class="ocaml-constant-language-capital-identifier">D</span><span class="ocaml-source"><![CDATA[)]]> </span><span class="ocaml-source"> </span><span class="ocaml-keyword-other">in</span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-constant-language-capital-identifier">Eio</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-constant-language-capital-identifier">Resource</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-constant-language-capital-identifier">T</span><span class="ocaml-source"> </span><span class="ocaml-source"><![CDATA[(]]> </span><span class="ocaml-constant-language-unit"><![CDATA[()]]> </span><span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">Eio_unix</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-constant-language-capital-identifier">Process</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-constant-language-capital-identifier">Pi</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">mgr_unix</span><span class="ocaml-source"> </span><span class="ocaml-source"><![CDATA[(]]> </span><span class="ocaml-keyword-other">module</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">V</span><span class="ocaml-source"><![CDATA[)]]> </span><span class="ocaml-source"><![CDATA[)]]> </span><span class="ocaml-source">
</span>
</code>
          </pre>
          <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 <a href="https://github.com/ocaml-multicore/eio/pull/823">this helper function</a>, I can push that into my <a href="https://patrick.sirref.org/standard%20environment/">standard environment</a>.</p>
          <pre class="hilite">
            <code><span class="ocaml-keyword">let</span><span class="ocaml-source"> </span><span class="ocaml-entity-name-function-binding">env</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-constant-language-capital-identifier">Eio_unix</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-constant-language-capital-identifier">Stdenv</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">with_env</span><span class="ocaml-source">
</span>
<span class="ocaml-source">  ~</span><span class="ocaml-source">process_mgr</span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source"><![CDATA[(]]> </span><span class="ocaml-source">debug_process_mgr</span><span class="ocaml-source"> </span><span class="ocaml-source">env</span><span class="ocaml-keyword-other">#</span><span class="ocaml-source">process_mgr</span><span class="ocaml-source"><![CDATA[)]]> </span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-source">env</span><span class="ocaml-source">
</span>
<span class="ocaml-keyword-other">in</span><span class="ocaml-source">
</span>
<span class="ocaml-constant-language-capital-identifier">Shelter</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">main</span><span class="ocaml-source"> </span><span class="ocaml-source">config</span><span class="ocaml-source"> </span><span class="ocaml-source"><![CDATA[(]]> </span><span class="ocaml-source">env</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-keyword-operator">&gt;</span><span class="ocaml-source"> </span><span class="ocaml-constant-language">_</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">Shelter</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">env</span><span class="ocaml-source"><![CDATA[)]]> </span><span class="ocaml-source"> </span><span class="ocaml-source">dir</span><span class="ocaml-source"> </span><span class="ocaml-source">cmd_file</span><span class="ocaml-source">
</span>
</code>
          </pre>
          <p>And sure enough I was querying for the Docker user <em>before</em> pulling the image! I hadn't run into this, as for the last while I have been using <code>alpine</code> and <code>debian</code> images that already exists locally.</p>
        </section>
      </div>
    </content>
  </entry>
  <entry>
    <title>Taking stock &amp; Graft updates</title>
    <published>2025-11-10T00:00:00-00:00</published>
    <updated>2025-11-10T00:00:00-00:00</updated>
    <author>
      <name>https://patrick.sirref.org/Patrick Ferris/</name>
      <uri>https://patrick.sirref.org/Patrick%20Ferris/</uri>
    </author>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/weekly-2025-w45/" />
    <id>https://patrick.sirref.org/weekly-2025-w45/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <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 <a href="https://patrick.sirref.org/icfp-2025/">ICFP recap</a> and a deeper-dive into the random bits of <a href="https://patrick.sirref.org/ocaml-roundup-october-2025/">OCaml hacking</a>. 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.</p>
        <section>
          <header>
            <h2>Graft Updates </h2>
          </header>
          <p>It would seem that there is a potential <em>second</em> user of <a href="https://patrick.sirref.org/graft/">Graft</a>! A great source of motivation for some tidying and feature implementing. At the end of last week I fixed some little bugs in <a href="https://patrick.sirref.org/graft/">Graft</a><![CDATA[ and (more importantly) allowed]]>  <a href="https://graft.sirref.org/named-subtrees">users to name their subtrees</a>. Upstream <a href="https://patrick.sirref.org/graft/">Graft</a> also now pins and uses my <a href="https://patrick.sirref.org/bib/">Bibtex implementation</a>.</p>
        </section>
        <section>
          <header>
            <h2>OCaml Geotessera</h2>
          </header>
          <p>As I discussed in my <a href="https://patrick.sirref.org/ocaml-roundup-october-2025/">OCaml roundup</a>, I spent a bit of time polishing the <a href="https://tangled.org/@patrick.sirref.org/ocaml-geotessera">OCaml geotessera code</a>. 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 <a href="https://patrick.sirref.org/mdales/">Michael</a> has carved out with <a href="https://github.com/quantifyearth/yirgacheffe/">Yirgacheffe</a>. I'm following <a href="https://digitalflapjack.com/weeknotes/2025-11-10/">along with his work excitedly</a> and we had a good catch-up last week discussing how libraries should handle things like automatic, numeric precision conversion.</p>
          <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 <a href="https://ocaml.org/p/nx">Nx</a><![CDATA[ library in OCaml (a numpy equivalent). Take a look at this]]>  sum function:</p>
          <pre class="hilite">
            <code><span class="ocaml-keyword">let</span><span class="ocaml-source"> </span><span class="ocaml-entity-name-function-binding">sum</span><span class="ocaml-source"> </span><span class="ocaml-source">nx</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">Nx</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">sum</span><span class="ocaml-source"> </span><span class="ocaml-source">nx</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">|&gt;</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">Nx</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">item</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-list"><![CDATA[[]]]> </span><span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span><span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span><span class="ocaml-source">
</span>
<span class="ocaml-keyword-other">val</span><span class="ocaml-source"> </span><span class="ocaml-source">sum</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source"> </span><span class="ocaml-source"><![CDATA[(]]> </span><span class="ocaml-storage-type">'a</span><span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span><span class="ocaml-source"> </span><span class="ocaml-storage-type">'b</span><span class="ocaml-source"><![CDATA[)]]> </span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">Nx</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">t</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">-&gt;</span><span class="ocaml-source"> </span><span class="ocaml-storage-type">'a</span><span class="ocaml-source">
</span>
<span class="ocaml-keyword">let</span><span class="ocaml-source"> </span><span class="ocaml-entity-name-function-binding">arr</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">Nx</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">create</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">Nx</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">int8</span><span class="ocaml-source"> </span><span class="ocaml-source"><![CDATA[[|]]> </span><span class="ocaml-source"> </span><span class="ocaml-constant-numeric-decimal-integer">2</span><span class="ocaml-source"> </span><span class="ocaml-source"><![CDATA[|]]]> </span><span class="ocaml-source"> </span><span class="ocaml-source"><![CDATA[[|]]> </span><span class="ocaml-source"> </span><span class="ocaml-constant-numeric-decimal-integer">64</span><span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span><span class="ocaml-source"> </span><span class="ocaml-constant-numeric-decimal-integer">64</span><span class="ocaml-source"> </span><span class="ocaml-source"><![CDATA[|]]]> </span><span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span><span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span><span class="ocaml-source">
</span>
<span class="ocaml-keyword-other">val</span><span class="ocaml-source"> </span><span class="ocaml-source">arr</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source"> </span><span class="ocaml-source"><![CDATA[(]]> </span><span class="ocaml-support-type">int</span><span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">Bigarray</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">int8_signed_elt</span><span class="ocaml-source"><![CDATA[)]]> </span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">Nx</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">t</span><span class="ocaml-source">
</span>
<span class="ocaml-source">sum</span><span class="ocaml-source"> </span><span class="ocaml-source">arr</span><span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span><span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span><span class="ocaml-source">
</span>
<span class="ocaml-keyword-operator">-</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source"> </span><span class="ocaml-support-type">int</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">-</span><span class="ocaml-constant-numeric-decimal-integer">128</span><span class="ocaml-source">
</span>
</code>
          </pre>
          <p>Even though <code>sum</code> takes an <code><![CDATA[('a, 'b) Nx.t]]></code> array that stores elements with representation <code>'b</code> and allows you to read/write to the elements with OCaml values of type <code>'a</code>, the <code>sum</code> function performs the calculation in the world of the <code>'b</code><![CDATA[ representation type (here signed 8-bit integers). So we get an]]>  overflow! Perhaps not too surprising but easy to overlook! The moral of the story is that we still need to be careful in the OCaml world too.</p>
        </section>
        <section>
          <header>
            <h2>Shelter</h2>
          </header>
          <p>I did a little cleaning up of the <a href="https://patrick.sirref.org/shelter/">Shelter</a> code too. I noticed a few bugs from the demos I did at <a href="https://patrick.sirref.org/icfp-2025/">ICFP</a>. Most were pretty straight-forward to fix, and the test-suite is now checking <a href="https://github.com/fn06/shelter/blob/main/test/fixtures/for.shl">parallel for-loops</a> and <a href="https://github.com/fn06/shelter/blob/main/test/fixtures/if.shl">conditional execution</a> are working.</p>
        </section>
        <section>
          <header>
            <h2>This week</h2>
          </header>
          <p>I hope to get a few things done this week:</p>
          <ul>
            <li>
              <p>Run some part of the <a href="https://github.com/quantifyearth/LIFE">LIFE</a> pipeline through <a href="https://patrick.sirref.org/shelter/">Shelter</a>.</p>
            </li>
            <li>
              <p>Deploy the <a href="https://patrick.sirref.org/shelter/">Shelter</a> daemon allowing other people to connect and take it for a spin.</p>
            </li>
            <li>
              <p>Spend some time writing and reading, pulling ideas together rather than always writing code!</p>
            </li>
            <li>
              <p>I have a slightly harebrained scheme that combines <a href="https://patrick.sirref.org/shelter/">Shelter</a>, atproto, <a href="https://patrick.sirref.org/forester/">Forester</a><![CDATA[, capn(proto/web) and webcomponents... I want to see if I can]]>  pull that together.</p>
            </li>
          </ul>
        </section>
      </div>
    </content>
  </entry>
  <entry>
    <title>Back to shelter</title>
    <published>2025-07-18T00:00:00-00:00</published>
    <updated>2025-07-18T00:00:00-00:00</updated>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/weekly-2025-07-18/" />
    <id>https://patrick.sirref.org/weekly-2025-07-18/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <section>
          <header>
            <h2>Capnproto Interface to Shelter</h2>
          </header>
          <p>I spent some time this week thinking about decoupling <a href="https://patrick.sirref.org/shelter/">Shelter</a>'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 <a href="https://patrick.sirref.org/shelter/">Shelter</a> on Windows and macOS.</p>
          <p>The design so far keeps the metadata local, in an <a href="https://irmin.org/">Irmin</a> database. I will probably then augment the stored information with some kind of unique daemon identifier to know where the actual data is.</p>
          <p>This is all still quite fresh, and I will have more by the end of next week.</p>
        </section>
        <section>
          <header>
            <h2>OCaml-related Things</h2>
          </header>
          <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 <a href="https://patrick.sirref.org/ocaml-weeklies/">weeklies for OCaml related things</a>.</p>
          <p>Fear not, the <a href="https://patrick.sirref.org/ocaml-weeklies/">OCaml weeklies</a> are a subset of these weeklies and so I will, when I remember, transclude them for you.</p>
          <section>
            <header>
              <h3>OCaml Weekly 2025 w29</h3>
            </header>
            <section>
              <header>
                <h4>Ppxlib</h4>
              </header>
              <p>I met with <a href="https://patrick.sirref.org/nathanreb/">Nathan</a> this week to discuss future plans for <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a>. The current state of affairs is that <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> is becoming unmaintainable. This is primarily a knock-on effect from changes being made to <![CDATA[OCaml's parsetree (e.g. labelled tuples being added in 5.4).]]>  <a href="https://patrick.sirref.org/nathanreb/">Nathan</a> has a plan that will provide two key properties.</p>
              <ol>
                <li>
                  <p>Migrations, which allow old compilers to be used with new <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> releases, will be more compatible. For example, we will be able to migrate new features downwards and back up without raising an error.</p>
                </li>
                <li>
                  <p>Ppx authors will be able to use new features in an opt-in workflow, rather than <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a><![CDATA[ bumping the internal AST (like we did]]> <a href="https://patrick.sirref.org/ppxlib-5-2/">in ppxlib.0.36.0</a><![CDATA[). This will reduce the maintenance burden]]>  significantly whilst still allowing users to write ppxes for new OCaml features.</p>
                </li>
              </ol>
              <p>I also started looking into some older issues in <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> related to performance. This is work-in-progress, but I am trying to improve the performance of some passes done by <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a>. To better understand what was making <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> slow, I wanted to use <a href="https://github.com/tarides/runtime_events_tools">runtime_events_tools</a> but I was dismayed to see it wanting to install over 100 packages! I <a href="https://github.com/tarides/runtime_events_tools/pull/57">opened a PR to reduce the number of packages</a>. I think this kind of work goes a little unrecognised as it is not very glamorous. However, I think it really benefits the OCaml community in the long run.</p>
            </section>
            <section>
              <header>
                <h4>Outreachy</h4>
              </header>
              <p>In <a href="https://patrick.sirref.org/outreachy/">Outreachy</a> news, we had a wonderful mid-internship video call with all the interns and mentors to catch-up on how everyone is getting along. Seeing the progress everyone has made was great! I am very grateful for the work that <a href="https://patrick.sirref.org/mdales/">Michael</a> and <a href="https://github.com/gridbugs">Steve</a> have put in so far to make this a very successful Outreachy round for OCaml.</p>
              <p>In sadder news, an email was shared with all <a href="https://patrick.sirref.org/outreachy/">Outreachy</a> mentors detailing the increasingly critical financial situation the project finds itself in. There are ongoing discussions about how costs can be cut including potentially only running a single round a year.</p>
            </section>
            <section>
              <header>
                <h4>Graft</h4>
              </header>
              <p>With the release of <a href="https://patrick.sirref.org/Forester/">Forester.5.0</a>, I made a plan to make a release of <a href="https://patrick.sirref.org/Graft/">Graft.0.1</a>. Unfortunately this is blocked by a new release of <a href="https://github.com/ocaml/opam-repository/pull/28172">hilite</a>, a tool I built for doing build-time syntax highlighting for OCaml code. This powers the syntax highlighting on <a href="https://ocaml.org/">ocaml.org</a>.</p>
            </section>
          </section>
        </section>
      </div>
    </content>
  </entry>
  <entry>
    <title>PhD Work and Scientific Programming</title>
    <published>2025-06-30T00:00:00-00:00</published>
    <updated>2025-06-30T00:00:00-00:00</updated>
    <author>
      <name>https://patrick.sirref.org/Patrick Ferris/</name>
      <uri>https://patrick.sirref.org/Patrick%20Ferris/</uri>
    </author>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/rest-of-monthly-2025-06/" />
    <id>https://patrick.sirref.org/rest-of-monthly-2025-06/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>I have been away on holidays. Some of that was spent hiking in the Massif de Calanques in Marseille, unfortunately this week <a href="https://www.theguardian.com/world/2025/jul/08/marseille-airport-cancels-all-flights-as-wildfire-encroaches-on-city">they were on fire</a>. Anyway, this "weekly" fills in the blanks for the rest of June 2025.</p>
        <p style="text-align: center">
  <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" />
</p>
        <section>
          <header>
            <h2>Revisiting <a href="https://patrick.sirref.org/hazel_of_ocaml/">hazel_of_ocaml</a></h2>
          </header>
          <p>I spent some time thinking and writing about <a href="https://patrick.sirref.org/hazel_of_ocaml/">hazel_of_ocaml</a> 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.</p>
          <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.</p>
        </section>
        <section>
          <header>
            <h2>A second year report</h2>
          </header>
          <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.</p>
          <p>Part of that was working on my <a href="https://patrick.sirref.org/publications/">publications</a> page and, through a conversation with <a href="https://patrick.sirref.org/anilmadhavapeddy/">Anil</a>, realising that my work on <a href="https://patrick.sirref.org/graft/">Graft</a> was in many ways a part of my own research.</p>
          <p>If you are interested, feel free to peruse both my <a href="/bafkrmigsvxp4qr3tltethz6oznlgxkkx2dwjjkovjvhemi3k3ljpcydvu4.pdf">first year</a> and <a href="/bafkrmifhsh5b6mgzdomyfz6harcm2hrzxzxtupije7mqjiwxotupmz4bgy.pdf">second year</a> 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.</p>
          <section>
            <header>
              <h3>What is <em>scientific programming</em>?</h3>
            </header>
            <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: <a href="https://patrick.sirref.org/storer2017bridging/">Bridiging the chasm: A survey of Software Engineering Practice in Scientific Programming</a>. I enjoyed a few aspects of this paper.</p>
            <ul>
              <li>
                <p>Relating scientific programming to the scientific method so directly was pretty useful insight for me. <em>Falsifable hypotheses</em>, <em>repeatable experiments</em> and <em>reproducible results</em> when applied as characteristics of the computer stack <![CDATA[(e.g. OS, programming language, filesystem etc.) might be a useful lens to]]>  argue for better tools to enable this.</p>
              </li>
              <li>
                <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.</p>
              </li>
            </ul>
          </section>
        </section>
        <section>
          <header>
            <h2>Ppxlib</h2>
          </header>
          <p>I was reminded again of the pain of helping maintain <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a>. We are coming to the conclusion, that in its current form, it is becoming unmaintainable. I took a stab at updating <a href="https://github.com/aantron/bisect_ppx/pull/448">bisect_ppx</a> 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!</p>
        </section>
        <section>
          <header>
            <h2>Geocaml</h2>
          </header>
          <p>Work on <a href="https://patrick.sirref.org/ocaml-tiff/">ocaml-tiff</a> has stalled, which is totally fine. <a href="https://patrick.sirref.org/mdales/">Michael</a> 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.</p>
        </section>
      </div>
    </content>
  </entry>
  <entry>
    <title>Forester as a Target Syntax</title>
    <published>2025-06-02T00:00:00-00:00</published>
    <updated>2025-06-02T00:00:00-00:00</updated>
    <author>
      <name>https://patrick.sirref.org/Patrick Ferris/</name>
      <uri>https://patrick.sirref.org/Patrick%20Ferris/</uri>
    </author>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/weekly-2025-06-02/" />
    <id>https://patrick.sirref.org/weekly-2025-06-02/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>This week included some time finishing <a href="https://patrick.sirref.org/open-trace/">opentrace</a> and subsequently folding it into <a href="https://patrick.sirref.org/shelter/">shelter</a>. I have been writing up some more of the draft paper for <a href="https://patrick.sirref.org/shelter/">shelter</a> which I am excited to share in the near future.</p>
        <p>I revisited the <a href="https://patrick.sirref.org/vpnkit-upgrade/">upgrading vpnkit</a> 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. <em>C'est la vie</em>.</p>
        <section>
          <header>
            <h2>Forester and Graft</h2>
          </header>
          <p>I spent a bit of time finally pulling out my changes to <a href="https://patrick.sirref.org/forester/">Forester</a> to add markdown and bibtex support into a standalone tool: <a href="https://patrick.sirref.org/graft/">graft</a>.</p>
          <section>
            <header>
              <h3>Graft</h3>
            </header>
            <p>Graft is a <a href="https://patrick.sirref.org/forester/">Forester</a> preprocessor.</p>
            <p><![CDATA[It takes a forester (a directory of trees) written in a mixture of Markdown, Bibtex and]]>  <a href="https://patrick.sirref.org/forester/">Forester</a> syntax and produces a new forest completely written in <a href="https://patrick.sirref.org/forester/">Forester</a> syntax.</p>
            <section>
              <header>
                <h4>Usage</h4>
              </header>
              <p><code>graft</code> simply preprocesses a forest generating Forester trees from <code>.md</code>, <code>.bib</code> and <code>.tree</code> files. It will copy the structure of the input directory in the output directory.</p>
              <pre class="hilite">
                <code><span class="sh-source">$ graft preprocess --output=grafted-trees trees
</span>
<span class="sh-source">$ forester build
</span>
</code>
              </pre>
              <p>This assumes that you have updated your Forester <code>toml</code> file to put the <code>grafted-trees</code> directory as your source of trees.</p>
              <pre><![CDATA[[forest]
trees = [ "grafted-trees" ]]]></pre>
            </section>
            <section>
              <header>
                <h4>Example</h4>
              </header>
              <p>A typical "tree" might look something like</p>
              <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}
```]]></pre>
              <p>A few things to note:</p>
              <ol>
                <li>
                  <p>The <code>yaml</code> frontmatter allows you to add some of the metadata fields from Forester.</p>
                </li>
                <li>
                  <p>At any point in your markdown there is an escape hatch to Forester using a <code>forester</code> codeblock.</p>
                </li>
              </ol>
            </section>
          </section>
          <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 <a href="https://patrick.sirref.org/forester/">Forester</a>. 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 <a href="https://patrick.sirref.org/graft/">graft</a> including extra input formats. I am also considering extending the <a href="https://patrick.sirref.org/forester/">Forester</a> configuration to contain some <a href="https://patrick.sirref.org/graft/">graft</a> configuration for how it should generate <![CDATA[new trees (e.g. at the moment every entry in a bibtex file is given a new tree).]]></p>
          <section>
            <header>
              <h3>Maths Support</h3>
            </header>
            <p>As part of that process, <a href="https://patrick.sirref.org/graft/">graft</a> now supports Markdown KaTeX. For example:</p>
            <section>
              <header>
                <h4>Mergeable Replicated Data Type Implementation</h4>
              </header>
              <p>A <strong><![CDATA[mergeable replicated data type (MRDT) implementation]]></strong> for a data type <code>\tau </code> is a tuple <code>D_{\tau } = (\Sigma , \sigma _{0}, do, merge)</code> where:</p>
              <ul>
                <li>
                  <p><code>\Sigma </code> is the set of all possible states at a branch,</p>
                </li>
                <li>
                  <p><code>\sigma _{0} \in  \Sigma </code> is the initial state,</p>
                </li>
                <li>
                  <p><code>do : Op_{\tau } \times  \Sigma  \times  Timestamp \rightarrow  \Sigma  \times  Val_{\tau }</code> implements every data type operation,</p>
                </li>
                <li>
                  <p><code>merge : \Sigma  \times  \Sigma  \times  \Sigma  \rightarrow  \Sigma </code> implements the <em>three-way merge strategy</em>.</p>
                </li>
              </ul>
              <p><a href="https://patrick.sirref.org/kcrsk-mrdts-2022/">Definition 2.1 from "Certified Mergeable Replicated Data Types"</a>.</p>
            </section>
          </section>
        </section>
        <section>
          <header>
            <h2>Revision Supervisions</h2>
          </header>
          <p>I have been doing revision supervisions for <a href="https://patrick.sirref.org/discrete-maths/">Discrete Maths</a> and <a href="https://patrick.sirref.org/focs.md">Foundations of Computer Science</a>. I have also been marking Operating Systems past paper questions for the same group of first years.</p>
        </section>
      </div>
    </content>
  </entry>
  <entry>
    <title>Opentrace and Supervisions</title>
    <published>2025-05-26T00:00:00-00:00</published>
    <updated>2025-05-26T00:00:00-00:00</updated>
    <author>
      <name>https://patrick.sirref.org/Patrick Ferris/</name>
      <uri>https://patrick.sirref.org/Patrick%20Ferris/</uri>
    </author>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/weekly-2025-05-26/" />
    <id>https://patrick.sirref.org/weekly-2025-05-26/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p><![CDATA[Over the past two weeks I have mainly split my time (amongst many things) developing]]> <a href="https://patrick.sirref.org/open-trace/">opentrace</a> and doing revision supervisions.</p>
        <section>
          <header>
            <h2>Opentrace</h2>
          </header>
          <p>Thanks to <a href="https://github.com/koonwen/">Koonwen's</a> excellent <a href="https://github.com/koonwen/ocaml-libbpf">libbpf bindings in OCaml</a>, I have been building a little tool called <code>opentrace</code> to make it easier to track an executable's inputs and outputs.</p>
          <p>This work was inspired my <a href="https://patrick.sirref.org/mdales/">Michael's</a> self-proclaimed "gross hack": <a href="https://github.com/quantifyearth/pyshark">pyshark</a>. Whilst pyshark achieves its goals by injecting code into commonly used python objects and methods, <a href="https://patrick.sirref.org/opentrace/">opentrace</a> uses <a href="https://ebpf.io/">eBPF</a><![CDATA[. By using a lower-level API (hooks in the kernel),]]> <a href="https://patrick.sirref.org/opentrace/">opentrace</a> can remain programming language agnostic. However, less information is none about the user's intent compared to something like pyshark.</p>
          <section>
            <header>
              <h3>Monitoring the System</h3>
            </header>
            <p><a href="https://patrick.sirref.org/opentrace/">opentrace</a> has an <code>all</code> command that will trace the entire system.</p>
            <pre><![CDATA[$ sudo opentrace all --flags=O_WRONLY
pid,cgid,comm,kind,flags,mode,filename,return
16324,4417,".nheko-wrapped",openat,577,438,"/home/patrick/.cache/nheko/nheko/curl_alt_svc_cache.txt",47
16324,4417,".nheko-wrapped",openat,193,33188,"/home/patrick/.cache/nheko/nheko/cr3ZUHqBErIOe3PlwJ1SuU8zFKKxL12VzrRoHYMH.tmp",47
16324,4417,".nheko-wrapped",openat,577,438,"/home/patrick/.cache/nheko/nheko/curl_alt_svc_cache.txt",47
16324,4417,".nheko-wrapped",openat,193,33188,"/home/patrick/.cache/nheko/nheko/QfZTdZSuC56NdcDQ3aMxJc3BhMhAj8PmtYW1zFDP.tmp",47
2530,4235,"systemd",openat,524865,438,"/sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/app.slice/gammastep.service/cgroup.subtree_control",41
2530,4235,"systemd",openat,524545,0,"/sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/app.slice/gammastep.service/memory.min",41
2530,4235,"systemd",openat,524545,0,"/sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/app.slice/gammastep.service/memory.low",41
2530,4235,"systemd",openat,524545,0,"/sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/app.slice/gammastep.service/memory.high",41
2530,4235,"systemd",openat,524545,0,"/sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/app.slice/gammastep.service/memory.max",41]]></pre>
            <p>The <code>--flags=O_WRONLY</code> argument filters the events where the <code>O_WRONLY</code> flag was set in the call to <code>open</code>.</p>
            <p><![CDATA[We also get the name of the current executable linked to the task (]]> <code>comm</code><![CDATA[). The]]> <code>-wrapped</code> is an artefact of using Nix.</p>
          </section>
          <section>
            <header>
              <h3>Tracing an Executable</h3>
            </header>
            <p>The primary use case for this tool is to inspect what files your program might be reading and writing.</p>
            <pre><![CDATA[$ sudo opentrace exec --format=json --flags=O_CREAT -- opam list
$ cat trace.json | jq ".[] | .fname"
"/home/patrick/.opam/cshell/.opam-switch/packages/cache"
"/home/patrick/.opam/log/log-118747-29da3d.out"
"/home/patrick/.opam/log/log-118747-29da3d.err"
"/home/patrick/.opam/log/log-118747-29da3d.env"
"/home/patrick/.opam/log/log-118747-29da3d.info"]]></pre>
            <p>The "flags" argument can specify a small boolean formula for checking the open flags of a particular event with <code>|</code><![CDATA[ (or),]]> <code>&amp;</code><![CDATA[ (and), and]]> <code>~</code><![CDATA[ (not).]]>  Parentheses can be used for precedence.</p>
            <pre><![CDATA[$ sudo opentrace exec --flags="O_WRONLY|O_RDONLY" -- ocaml --version]]></pre>
          </section>
          <section>
            <header>
              <h3>Spawning Subprocesses</h3>
            </header>
            <p>One feature <a href="https://patrick.sirref.org/opentrace/">opentrace</a><![CDATA[ needs (in this proof-of-concept phase) is the ability to also trace subprocesses.]]></p>
            <p><a href="https://patrick.sirref.org/opentrace/">opentrace</a> is primarily an eBPF program that is loaded into the kernel and communicates with an OCaml program. Events are communicated via a ring buffer and most of the post-processing happens in OCaml. To capture subprocesses, <a href="https://patrick.sirref.org/opentrace/">opentrace</a><![CDATA[ creates a new control group (cgroup) and places the new process into that group.]]>  This gives <a href="https://patrick.sirref.org/opentrace/">opentrace</a> a new identifier to track, namely the cgroup.</p>
            <p>So consider the following program.</p>
            <pre class="hilite">
              <code><span class="ocaml-keyword-other">let</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-unit"><![CDATA[()]]> </span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-constant-language-capital-identifier">Eio_posix</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">run</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">@@</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other">fun</span><span class="ocaml-source"> </span><span class="ocaml-source">env</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">-&gt;</span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-constant-language-capital-identifier">Eio</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-constant-language-capital-identifier">Path</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source"><![CDATA[(]]> </span><span class="ocaml-source">save</span><span class="ocaml-source"> ~</span><span class="ocaml-source">create</span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source"><![CDATA[(]]> </span><span class="ocaml-constant-language-polymorphic-variant">`Or_truncate</span><span class="ocaml-source"> </span><span class="ocaml-constant-numeric-octal-integer">0o664</span><span class="ocaml-source"><![CDATA[)]]> </span><span class="ocaml-source"> </span><span class="ocaml-source"><![CDATA[(]]> </span><span class="ocaml-source">env</span><span class="ocaml-keyword-other">#</span><span class="ocaml-source">fs</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">/</span><span class="ocaml-source"> </span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-string-quoted-double">hello.txt</span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-source"><![CDATA[)]]> </span><span class="ocaml-source"> </span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-string-quoted-double">hello</span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-source"><![CDATA[)]]> </span><span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-constant-language-capital-identifier">Eio</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-constant-language-capital-identifier">Process</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">run</span><span class="ocaml-source"> </span><span class="ocaml-source">env</span><span class="ocaml-keyword-other">#</span><span class="ocaml-source">process_mgr</span><span class="ocaml-source">
</span>
<span class="ocaml-source">    </span><span class="ocaml-source"><![CDATA[[]]> </span><span class="ocaml-source"> </span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-string-quoted-double">/bin/bash</span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span><span class="ocaml-source"> </span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-string-quoted-double">-c</span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span><span class="ocaml-source"> </span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-string-quoted-double">echo 'heya' &gt; heya.txt</span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-source"> </span><span class="ocaml-source"><![CDATA[]]]> </span><span class="ocaml-source">
</span>
</code>
            </pre>
            <p>It first creates a file using direct calls to functions like <code>openat</code>. Then it spawns a process which creates a new file called <code>heya.txt</code>. This happens in a separate process. However, with the <code>--cgroups</code> flag we can capture both interactions with the operating system.</p>
            <pre><![CDATA[$ sudo opentrace exec --cgroups --flags="O_CREAT|O_TRUNC" ./main.exe
pid,cgid,comm,kind,flags,mode,filename,return
153187,530807,"main.exe",openat,526914,436,"hello.txt",5
153192,530807,"bash",openat,577,438,"heya.txt",3]]></pre>
            <section>
              <header>
                <h4>Eio's Process API</h4>
              </header>
              <p>I have used the <code>Eio_unix</code> <a href="https://ocaml.org/p/eio/latest/doc/Eio_unix/Process/index.html">fork action process API</a> to be able to extend what happens in the child process. Loading most eBPF programs into the kernel requires special privileges hence the need for <code>sudo</code>. When a user requests for a particular program to be executed and traced, <a href="https://patrick.sirref.org/opentrace/">opentrace</a> spawns a process via the Eio Process API. <a href="https://patrick.sirref.org/opentrace/">Opentrace</a> defines a few new so-called "fork actions", little fragments of C code that are run after the call to <code>fork</code><![CDATA[ (]]> <code>clone</code><![CDATA[).]]>  Most likely this ends with a call to <code>execve</code>, but other calls are possible for example <code>setuid</code> allowing <a href="https://patrick.sirref.org/opentrace/">opentrace</a> to change the user of the child process so it does not run as <code>root</code><![CDATA[. Similarly, this is where (if used) we create the cgroup and place the process]]>  into that group.</p>
            </section>
          </section>
          <section>
            <header>
              <h3>Limitations: Io_uring</h3>
            </header>
            <p>Whilst testing <code>opentrace</code> against some of the tools I use nearly daily, I noticed some events were being missed. I tried tracing <a href="https://patrick.sirref.org/forester/">forester</a>, and only the initial read of <code>forest.toml</code> was logged. It dawned on me that the reason for this was that <a href="https://patrick.sirref.org/forester/">forester</a><![CDATA[ (via]]> <a href="https://patrick.sirref.org/eio/">eio</a><![CDATA[) was using]]> <a href="https://patrick.sirref.org/io_uring/">io_uring</a> to perform most of the IO. Most attempts to open files were bypassing the open system calls, and instead they were being performed by the kernel after reading a submission request for an <code>openat2</code>-style call!</p>
            <p>This is not news to seasoned, Linux systems programmers. Io_uring <a href="https://blog.0x74696d.com/posts/iouring-and-seccomp/">bypasses <code>SECCOMP</code> filters</a> for exactly the same reasons.</p>
            <pre><![CDATA[$ sudo opentrace exec -- forester build
$ cat trace.csv
pid,cgid,comm,kind,flags,mode,filename,return
155007,535570,"forester",openat,524288,0,"forest.toml",5
155007,535570,"forester",Uring,2621440,0,"",0
155021,535570,"cp",openat,131072,0,"/home/patrick/documents/forest/theme/favicon-32x32.png",4
155007,535570,"forester",Uring,2686976,0,"",0
155007,535570,"iou-wrk-155007",Uring,557634,420,"",0
155007,535570,"iou-wrk-155007",Uring,557634,420,"",0
155007,535570,"iou-wrk-155007",Uring,557634,420,"",0]]></pre>
            <p>It is interesting to note two things here:</p>
            <ol>
              <li>
                <p>We can tell that <a href="https://patrick.sirref.org/forester/">forester</a> reads the configuration file probably using something like <code>In_channel</code><![CDATA[ in OCaml (]]> <a href="https://git.sr.ht/~jonsterling/ocaml-forester/tree/7f275290e211db2590b0d715d8fb47fc1de36550/item/lib/frontend/Config.ml#L22">it does</a><![CDATA[).]]></p>
              </li>
              <li>
                <p>It appears that Uring is performing IO in both worker threads and directly.</p>
              </li>
            </ol>
            <p>The file paths are empty at the moment as I cannot find a clean way to trace openat submission requests into Uring without it sometimes going very wrong. <![CDATA[I have tried quite a few methods (e.g. tracing]]> <code>do_filp_open</code><![CDATA[) and at the moment I am tracing]]> <code>io_openat2</code>, but this seems quite brittle, and often the filename is completely garbled, so I do not set it. If anyone has any ideas to trace Io_uring more reliably, I am all ears!</p>
          </section>
        </section>
        <section>
          <header>
            <h2>Supervisions</h2>
          </header>
          <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 <a href="https://patrick.sirref.org/jonmsterling/">Jon Sterling</a>'s <a href="https://www.jonmsterling.com/2025-W21/index.xml">post about assessment bureaucracy</a>. In particular:</p>
          <blockquote>
            <p><![CDATA[At moments like this, it is a good idea to pause and reflect on whether it is better for our students that each faculty member spend a cumulative two months doing literally nothing but assessment and higher-order practices related to assessment, vs. other activities that could benefit our students more (including actual teaching, of which we do astonishingly little at Cambridge).]]></p>
          </blockquote>
        </section>
      </div>
    </content>
  </entry>
  <entry>
    <title>Metashells</title>
    <published>2025-05-19T00:00:00-00:00</published>
    <updated>2025-05-19T00:00:00-00:00</updated>
    <author>
      <name>https://patrick.sirref.org/Patrick Ferris/</name>
      <uri>https://patrick.sirref.org/Patrick%20Ferris/</uri>
    </author>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/weekly-2025-05-12/" />
    <id>https://patrick.sirref.org/weekly-2025-05-12/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>This week, I feel I have been stuck fighting the OCaml ecosystem trying to keep my <a href="https://patrick.sirref.org/try-oxcaml/">OxCaml work afloat</a>. Aside from that, <a href="https://patrick.sirref.org/ryangibb/">Ryan</a> and I made some really nice progress with Shelter, culminating in <a href="https://patrick.sirref.org/ryangibb/">Ryan</a> describing it as a <em>metashell</em>.</p>
        <section>
          <header>
            <h2>Shelter the metashell</h2>
          </header>
          <p>The main progress this week with Shelter was composing <a href="https://github.com/opencontainers/runc">runc</a>'s <code>terminal</code> mode with entering raw terminal input mode on the Shelter side. This is inspired by <a href="https://patrick.sirref.org/ryangibb/">Ryan</a>'s own work on <a href="https://github.com/ryangibb/eon">capability interfaces</a>.</p>
          <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 <code>vim</code> now work in Shelter! Not only that, but users can now <em>activate</em><![CDATA[ an inner shell (e.g.]]> <code>zsh</code><![CDATA[) and enjoy all the usual features]]>  <![CDATA[of a fully-fledged shell (tab complete, fuzzy history search etc.) and upon exiting that shell, Shelter will]]>  snapshot the session. This lets you alter the granularity of snapshots from the command-line.</p>
        </section>
        <section>
          <header>
            <h2>Louis Pouzin's "Shell"</h2>
          </header>
          <p>I spent some time reading <a href="https://patrick.sirref.org/pouzin-shell-2013/">part of the multics design documentation</a> this week. Louis Pouzin coined the term "Shell" in this document and I was reminded yet again just how important it is to be a good writer even as a "computer science researcher". For example, this excerpt from the requirements section of the document</p>
          <blockquote>
            <p>The previous definitions imply that a command MUST be designed while keeping in mind the user, sitting at his console, wondering about what might be going on, mistyping or forgetting arguments, even if fully aware of the conventions, and possibly interfering with the command by hasty quits, carriage returns, and other temperamental reactions.</p>
          </blockquote>
          <p>And then later, when defining the "SHELL".</p>
          <blockquote>
            <p>We may envision a common procedure called automatically by the supervisor whenever a user types in some message at his console, at a time when he has <![CDATA[no other process in active execution under console control (presently called]]>  <![CDATA[command level). This procedure acts as an interface between console messages]]>  and subroutine. The purpose of such a procedure is to create a medium of exchange into which one could activate any procedure, <em>inside of another program if it were called</em>. Hereafter, for simplification, we shall refer to that procedure as the "SHELL".</p>
          </blockquote>
          <p>It still surprises how little the undergraduate degree in computer science at <a href="https://patrick.sirref.org/ucam/">Cambridge</a> focuses on writing skills.</p>
        </section>
        <section>
          <header>
            <h2>OxCaml</h2>
          </header>
          <p>Last week, I got a <a href="https://patrick.sirref.org/try-oxcaml/">toplevel with OxCaml working</a>. 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 <code>js_of_ocaml</code>.</p>
          <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.</p>
        </section>
        <section>
          <header>
            <h2>Other OCaml Work</h2>
          </header>
          <p>I worked on some other parts of the ecosystem this week.</p>
          <section>
            <header>
              <h3>Ppxlib</h3>
            </header>
            <p><![CDATA[I helped review some changes to enable Janestreet to have ppx rewriters via attributes (usually they are via extension]]>  <![CDATA[points). It is a bit of a controversial change to]]> <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> as we try to keep the API predictable for users:</p>
            <ol>
              <li>
                <p>Extension points are rewritten: this means the part that is rewritten is nicely delimited by the extension points start and end.</p>
              </li>
              <li>
                <p>Attributes extend: attributes do not rewrite the code they are attached to but rather extend the code with new AST nodes.</p>
              </li>
            </ol>
            <p><a href="https://github.com/ocaml-ppx/ppxlib/pull/574"><![CDATA[We will see what we decided to do (most likely provide the functionality behind some kind of "expert" interface)]]> </a>.</p>
          </section>
          <section>
            <header>
              <h3>Tiff</h3>
            </header>
            <p>See <a href="https://patrick.sirref.org/mdales/">Michael</a>'s <a href="https://digitalflapjack.com/weeknotes/2025-05-19b/">notes</a>.</p>
            <p><![CDATA[I spent some time trying to speedup the LZW decompression of TIFF files in the pure OCaml tiff library this week(end).]]>  The two big changes to help with this are pretty common when speeding up these parts OCaml programs:</p>
            <ol>
              <li>
                <p>Allocate less</p>
              </li>
              <li>
                <p>Does less work</p>
              </li>
            </ol>
            <p>In terms of allocating less, the original implementation was using a <code>char list</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 <code>string</code> saved a ton of allocations.</p>
            <p>In terms of doing less work, I opted to bypass <code>Cstruct</code><![CDATA[s sane (but slow) bounds checks in some of the "hotter" parts of]]>  the code. In particular, LZW ends up reading potentially <em>huge</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.</p>
            <p>Here are some results decompressing a fairly large array of some elevation data.</p>
            <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│]]></pre>
          </section>
        </section>
      </div>
    </content>
  </entry>
  <entry>
    <title>Hazel and OxCaml</title>
    <published>2025-05-10T00:00:00-00:00</published>
    <updated>2025-05-10T00:00:00-00:00</updated>
    <author>
      <name>https://patrick.sirref.org/Patrick Ferris/</name>
      <uri>https://patrick.sirref.org/Patrick%20Ferris/</uri>
    </author>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/weekly-2025-05-04/" />
    <id>https://patrick.sirref.org/weekly-2025-05-04/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>I missed a week of posting last week, mainly because I spent more time writing <a href="https://patrick.sirref.org/posts/">posts</a>.</p>
        <section>
          <header>
            <h2>Hazel of OCaml</h2>
          </header>
          <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.</p>
          <p>I wrote up a little summary of that work, which I've <a href="https://www.jonmsterling.com/foreign/www.forester-notes.org/jms-007L/index.xml">transcluded</a> below.</p>
          <section>
            <header>
              <h3>A Transpiler from OCaml to Hazel</h3>
            </header>
            <p>Over the past few months, I have been piecing together a transpiler from <a href="https://patrick.sirref.org/hazel/">Hazel</a> to OCaml. This is, in part, to help one of my third-year undergraduate students who is working on <a href="https://patrick.sirref.org/part-ii-hazel/">type error debugging in Hazel</a>.</p>
            <section>
              <header>
                <h4>Typed Holes</h4>
              </header>
              <p><a href="https://patrick.sirref.org/hazel/">Hazel</a> is a <a href="https://patrick.sirref.org/omar-hazel-2017/">functional programming language with typed holes</a>. Holes are pieces of your program that have not yet been filled in. Holes can appear anywhere in your program both as expression or types. Hazel can still evaluate your program in the presence of holes.</p>
              <p>To get a flavour of Hazel, take a regular map function for lists.</p>
              <pre><![CDATA[let map = fun f -> fun xs -> case xs
  | [] => []
  | x :: xs => f (x) :: map(f)(xs) 
end in
map(fun x -> ?)([1, 2, 3])]]></pre>
              <p><![CDATA[The question mark (]]> <code>?</code><![CDATA[) is a hole. The program evaluates to the following expression of type]]> <code><![CDATA[[?]]]></code><![CDATA[ (for people more]]>  familiar with OCaml types <code>? list</code><![CDATA[).]]></p>
              <pre><![CDATA[[ ?, ?, ? ]]]></pre>
              <p>Hazel supports <a href="https://patrick.sirref.org/zhao-typeerror-2024/">local type inference</a> but nothing involving unification variables. For example, a simple <code>add_one</code> function in <a href="https://patrick.sirref.org/hazel/">Hazel</a><![CDATA[ (]]> <code>fun x -&gt; x + 1</code><![CDATA[) has type]]> <code>? -&gt; Int</code>.</p>
            </section>
            <section>
              <header>
                <h4>From OCaml to Hazel</h4>
              </header>
              <p>The ability to transpile OCaml programs to Hazel programs is motivated by one simple thought: there are more OCaml programs than there are Hazel programs. This could help bootstrap projects by alleviating the need to rewrite <![CDATA[boilerplate code (e.g. URI parsing or standard library functions for strings).]]></p>
              <section>
                <header>
                  <h5>A Transformation of Syntax</h5>
                </header>
                <p>Hazel markets itself as an "Elm/ML-like functional programming language". From the previous example of <code>map</code>, it should be apparent just how close to OCaml the language is.</p>
                <p>It turns out that a majority of the transpiler is a <em>transformation of syntax</em>. Take a simple ADT for an arithmetic programming language.</p>
                <pre class="hilite">
                  <code><span class="ocaml-keyword-other">type</span><span class="ocaml-source"> </span><span class="ocaml-source">expr</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-keyword-other">|</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">Float</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other">of</span><span class="ocaml-source"> </span><span class="ocaml-support-type">float</span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-keyword-other">|</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">Add</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other">of</span><span class="ocaml-source"> </span><span class="ocaml-source">expr</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">*</span><span class="ocaml-source"> </span><span class="ocaml-source">expr</span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-keyword-other">|</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">Sub</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other">of</span><span class="ocaml-source"> </span><span class="ocaml-source">expr</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">*</span><span class="ocaml-source"> </span><span class="ocaml-source">expr</span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-keyword-other">|</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">Mul</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other">of</span><span class="ocaml-source"> </span><span class="ocaml-source">expr</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">*</span><span class="ocaml-source"> </span><span class="ocaml-source">expr</span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-keyword-other">|</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">Div</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other">of</span><span class="ocaml-source"> </span><span class="ocaml-source">expr</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">*</span><span class="ocaml-source"> </span><span class="ocaml-source">expr</span><span class="ocaml-source">
</span>
</code>
                </pre>
                <p>And when we run <a href="https://patrick.sirref.org/hazel_of_ocaml/">hazel_of_ocaml</a> over this OCaml type declaration.</p>
                <pre><![CDATA[type expr =
  + Float(Float)
  + Add((expr, expr))
  + Sub((expr, expr))
  + Mul((expr, expr))
  + Div((expr, expr))
 in ?]]></pre>
                <p>Not much has changed expect some syntax. <a href="https://patrick.sirref.org/hazel/">Hazel</a> does not have a notion of top-level expression so <a href="https://patrick.sirref.org/hazel_of_ocaml/">hazel_of_ocaml</a> wraps the program into one set of value bindings. For the most part, Hazel acts as a subset of the pure, functional part of OCaml. At the time of writing, this subset is fairly limited <![CDATA[with no support for modules or labelled records out of the box (there are plenty of development branches]]>  <![CDATA[with these features).]]></p>
                <p>If we try out the same <code>map</code> function but written in OCaml and transpiled to Hazel we get.</p>
                <pre class="hilite">
                  <code><span class="ocaml-keyword">let</span><span class="ocaml-source"> </span><span class="ocaml-keyword">rec </span><span class="ocaml-entity-name-function-binding">map</span><span class="ocaml-source"> </span><span class="ocaml-source">f</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other">function</span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-keyword-other">|</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-list"><![CDATA[[]]]> </span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">-&gt;</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-list"><![CDATA[[]]]> </span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-keyword-other">|</span><span class="ocaml-source"> </span><span class="ocaml-source">x</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source"> </span><span class="ocaml-source">xs</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">-&gt;</span><span class="ocaml-source"> </span><span class="ocaml-source">f</span><span class="ocaml-source"> </span><span class="ocaml-source">x</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source"> </span><span class="ocaml-source">map</span><span class="ocaml-source"> </span><span class="ocaml-source">f</span><span class="ocaml-source"> </span><span class="ocaml-source">xs</span><span class="ocaml-source">
</span>
</code>
                </pre>
                <p>Which becomes the following hazel program.</p>
                <pre><![CDATA[let map = fun f -> fun x1 -> case x1
  | [] => []
  | x :: xs => f(x) :: map(f)(xs)
end in ?]]></pre>
                <p>We could have a field day discussing the syntax of OCaml and Hazel <![CDATA[(parentheses for function arguments, well-scoped cases for pattern-matching, a]]>  <![CDATA[different arrow for pattern-matching etc.). What would be more interesting is]]>  taking a look at how to handle polymorphism in Hazel.</p>
              </section>
              <section>
                <header>
                  <h5>Explicit Polymorphism</h5>
                </header>
                <p>Hazel has <em>explicit polymorphism</em>. So far, we have not seen it as we have let the types have holes in them. The <code>map</code> function in OCaml has the following type.</p>
                <pre class="hilite">
                  <code><span class="ocaml-keyword-other">val</span><span class="ocaml-source"> </span><span class="ocaml-source">map</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source"> 
</span>
<span class="ocaml-source">  </span><span class="ocaml-source"><![CDATA[(]]> </span><span class="ocaml-storage-type">'a</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">-&gt;</span><span class="ocaml-source"> </span><span class="ocaml-storage-type">'b</span><span class="ocaml-source"><![CDATA[)]]> </span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">-&gt;</span><span class="ocaml-source"> </span><span class="ocaml-storage-type">'a</span><span class="ocaml-source"> </span><span class="ocaml-source">list</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">-&gt;</span><span class="ocaml-source"> </span><span class="ocaml-storage-type">'b</span><span class="ocaml-source"> </span><span class="ocaml-source">list</span><span class="ocaml-source">
</span>
</code>
                </pre>
                <p><![CDATA[We must remind ourselves (by reading]]> <a href="https://www.craigfe.io/posts/polymorphic-type-constraints">Craig's excellent blogpost on the matter</a><![CDATA[) that in OCaml]]></p>
                <blockquote>
                  <p>... type variables in signatures are implicitly universally-quantified</p>
                </blockquote>
                <p>So in reality, we have that <code>map</code> has the following type.</p>
                <pre><![CDATA[val map : ∀ a b. (a ->  b) -> a list -> b list]]></pre>
                <p>In Hazel, we have to explicitly type our <code>map</code> function to be polymorphic. Not only does this mean the type annotation requires universally quantified type variables, but we must also perform type application wherever we choose to apply the <code>map</code><![CDATA[ function (whether that be recursively or somewhere later in our]]>  <![CDATA[program).]]></p>
                <pre><![CDATA[let map : forall a -> forall b -> (a -> b) -> [a] -> [b] =
  typfun a -> typfun b -> fun f -> fun xs -> case xs
    | [] => []
    | x :: xs => f (x) :: map@<a>@<b>(f)(xs) 
end in
map@<Int>@<Int>(fun x -> ?)([1, 2, 3])]]></pre>
                <p><code>forall</code> introduces a universally quantified type variable into our type annotation, and <code>typfun</code><![CDATA[ introduces it into the function itself (à la System F). Type application]]>  requires <code>@&lt;T&gt;</code> where <code>T</code> is some type. This allows hazel to quite easily support higher rank polymorphism, but we will not worry too much about that.</p>
              </section>
              <section>
                <header>
                  <h5>Propagating OCaml Types into Hazel</h5>
                </header>
                <p>Most often, OCaml users interact with <em>prenex</em><![CDATA[ polymorphism (rank-1) where the universal quantifiers are]]>  at the front of the type. <a href="https://ocaml.org/manual/5.2/polymorphism.html#s:higher-rank-poly">OCaml does support quantifiers inside certain types like records</a>.</p>
                <p>What this means for the transpiler is that we can <strong>reuse OCaml's type inference</strong> to safely instantiate the correct type annotations and type applications in Hazel! To do this, <code>hazel_of_ocaml</code> uses <a href="https://ocaml.github.io/merlin/">Merlin</a> to inspect the type of the function in either a value binding or at the point of a function application.</p>
                <p>Take a simple, polymorphic <code>length</code> function.</p>
                <pre class="hilite">
                  <code><span class="ocaml-keyword">let</span><span class="ocaml-source"> </span><span class="ocaml-keyword">rec </span><span class="ocaml-entity-name-function-binding">length</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other">function</span><span class="ocaml-source">
</span>
<span class="ocaml-source"> </span><span class="ocaml-keyword-other">|</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-list"><![CDATA[[]]]> </span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">-&gt;</span><span class="ocaml-source"> </span><span class="ocaml-constant-numeric-decimal-integer">0</span><span class="ocaml-source">
</span>
<span class="ocaml-source"> </span><span class="ocaml-keyword-other">|</span><span class="ocaml-source"> </span><span class="ocaml-constant-language">_</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source"> </span><span class="ocaml-source">xs</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">-&gt;</span><span class="ocaml-source"> </span><span class="ocaml-constant-numeric-decimal-integer">1</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">+</span><span class="ocaml-source"> </span><span class="ocaml-source">length</span><span class="ocaml-source"> </span><span class="ocaml-source">xs</span><span class="ocaml-source">
</span>
<span class="ocaml-source">
</span>
<span class="ocaml-keyword">let</span><span class="ocaml-source"> </span><span class="ocaml-entity-name-function-binding">int_len</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source"> </span><span class="ocaml-source">length</span><span class="ocaml-source"> </span><span class="ocaml-source"><![CDATA[[]]> </span><span class="ocaml-source"> </span><span class="ocaml-constant-numeric-decimal-integer">1</span><span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span><span class="ocaml-source"> </span><span class="ocaml-constant-numeric-decimal-integer">2</span><span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span><span class="ocaml-source"> </span><span class="ocaml-constant-numeric-decimal-integer">3</span><span class="ocaml-source"> </span><span class="ocaml-source"><![CDATA[]]]> </span><span class="ocaml-source">
</span>
<span class="ocaml-keyword">let</span><span class="ocaml-source"> </span><span class="ocaml-entity-name-function-binding">str_len</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source"> </span><span class="ocaml-source">length</span><span class="ocaml-source"> </span><span class="ocaml-source"><![CDATA[[]]> </span><span class="ocaml-source"> </span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-string-quoted-double">only</span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span><span class="ocaml-source"> </span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-string-quoted-double">two</span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-source"> </span><span class="ocaml-source"><![CDATA[]]]> </span><span class="ocaml-source">
</span>
</code>
                </pre>
                <p>When we run this through <code>hazel_of_ocaml</code> with the <code>-type</code> flag we get.</p>
                <pre><![CDATA[let length : forall a -> [a] -> Int = typfun a -> fun x1 -> case x1
  | [] => 0
  | _ :: xs => 1 + length@<a>(xs)
end in
let int_len : Int = length@<Int>(1 :: 2 :: [3]) in
let str_len : Int = length@<String>("only" :: ["two"])
in ?]]></pre>
                <p><code>hazel_of_ocaml</code> has correctly instantiated the type for <code>length</code> inside the recursive function and then in each case with the integer list and the string list.</p>
              </section>
            </section>
            <section>
              <header>
                <h4>A Corpus of Hazel Programs</h4>
              </header>
              <p>The impetus for this work was to derive a corpus of ill-typed Hazel programs. Luckily, such a corpus exists for OCaml! <a href="https://patrick.sirref.org/ocaml-corpus/">Seidel et al.</a> created a corpus of OCaml programs from their undergraduate students at UC San Diego. <a href="https://github.com/patricoferris/hazel-corpus">Some of these programs have been transpiled to Hazel</a>.</p>
            </section>
            <section>
              <header>
                <h4>Future Work</h4>
              </header>
              <p><a href="https://patrick.sirref.org/hazel/">Hazel</a> is a fun, research programming language. Potential third-year students may find it interesting to take this work further. For example, how would this look in terms of a module system? From a purely engineering perspective, plenty of work would be needed to convert a multi-library OCaml project to Hazel <![CDATA[(e.g. handling the]]> <code>cmi</code><![CDATA[ files).]]></p>
              <p>Another line of research would be to have Hazel target one of the intermediate representations in OCaml which would give Hazel a fully functioning compiler to "native" code?</p>
            </section>
          </section>
        </section>
        <section>
          <header>
            <h2>OxCaml</h2>
          </header>
          <p>I spent some time this week getting more familiar with <a href="https://patrick.sirref.org/oxcaml-2024/">Oxidized OCaml</a>. I have a habit of wrapping <em>new</em> OCaml tools and libraries into toplevel, browser applications. For example, <a href="https://patricoferris.github.io/try-irmin">try-irmin</a> and <a href="https://patricoferris.github.io/try-eio/">try-eio</a>.</p>
          <p>Naturally, I tried to wrap OxCaml into a toplevel so people could play around with the new modes that <![CDATA[are part of the OxCaml type system. This turned out to be a lengthy debugging session (where type declarations]]>  did not align so the raw <code>Obj.repr</code><![CDATA[ js_of_ocaml representation was broken for some parts of the toplevel).]]>  I would say that I do question the time-spent/value trade-off, but a mostly working toplevel with OxCaml is available at: <a href="https://patrick.sirref.org/oxcaml">https://patrick.sirref.org/oxcaml</a>.</p>
        </section>
      </div>
    </content>
  </entry>
  <entry>
    <title>Catching Up!</title>
    <published>2025-04-21T00:00:00-00:00</published>
    <updated>2025-04-21T00:00:00-00:00</updated>
    <author>
      <name>https://patrick.sirref.org/Patrick Ferris/</name>
      <uri>https://patrick.sirref.org/Patrick%20Ferris/</uri>
    </author>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/weekly-2025-04-14/" />
    <id>https://patrick.sirref.org/weekly-2025-04-14/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <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.</p>
        <section>
          <header>
            <h2>Outreachy December 2024 and Beyond</h2>
          </header>
          <p>In the last week or so, we have come to the end of the December 2024 round of <a href="https://outreachy.org/">Outreachy</a>. 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.</p>
          <p>We, the OCaml community, held our biannual <em>Demo Day</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, <a href="https://github.com/azzsal">Abdulaziz</a>, who worked on the <a href="https://github.com/ocaml-semver/ocaml-api-watch">OCaml API diffing tool</a>.</p>
          <p style="text-align: center">
    <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" />
</p>
          <p>The next round has just completed the contribution phase and our next cohort of interns is being selected.</p>
        </section>
        <section>
          <header>
            <h2><![CDATA[Ppxlib Supports OCaml 5.4 (mostly)]]> </h2>
          </header>
          <p>This week, I <a href="https://github.com/ocaml-ppx/ppxlib/pull/570">added support for OCaml 5.4</a> to <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a>. A rather non-trivial change to the codebase due to changes in the representation in <code>Longident</code><![CDATA[s (which now have location information for all segments of the]]> <code>Longident</code><![CDATA[). OCaml 5.4 has]]> <em>labelled tuples</em>, a light-weight record-like syntax similar to labelled arguments in functions.</p>
          <pre class="hilite">
            <code><span class="ocaml-keyword">let</span><span class="ocaml-source"> </span><span class="ocaml-entity-name-function-binding">x</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source"> ~</span><span class="ocaml-source">x</span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-constant-numeric-decimal-integer">1</span><span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span><span class="ocaml-source"> </span><span class="ocaml-constant-numeric-decimal-integer">10</span><span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span><span class="ocaml-source"> ~</span><span class="ocaml-source">y</span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-constant-numeric-decimal-integer">1</span><span class="ocaml-source"> 
</span>
<span class="ocaml-keyword-other">val</span><span class="ocaml-source"> </span><span class="ocaml-source">x</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source"> </span><span class="ocaml-source">x</span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-support-type">int</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">*</span><span class="ocaml-source"> </span><span class="ocaml-support-type">int</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">*</span><span class="ocaml-source"> </span><span class="ocaml-source">y</span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-support-type">int</span><span class="ocaml-source">
</span>
<span class="ocaml-source">
</span>
<span class="ocaml-keyword">let</span><span class="ocaml-source"> </span><span class="ocaml-entity-name-function-binding">add</span><span class="ocaml-source"> </span><span class="ocaml-source"><![CDATA[(]]> </span><span class="ocaml-source">~</span><span class="ocaml-source">x</span><span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</span><span class="ocaml-source"> ~</span><span class="ocaml-source">y</span><span class="ocaml-source"><![CDATA[)]]> </span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source"> </span><span class="ocaml-source">x</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">+</span><span class="ocaml-source"> </span><span class="ocaml-source">y</span><span class="ocaml-source">
</span>
<span class="ocaml-keyword-other">val</span><span class="ocaml-source"> </span><span class="ocaml-source">add</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source"> </span><span class="ocaml-source"><![CDATA[(]]> </span><span class="ocaml-source">x</span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-support-type">int</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">*</span><span class="ocaml-source"> </span><span class="ocaml-source">y</span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-support-type">int</span><span class="ocaml-source"><![CDATA[)]]> </span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">-&gt;</span><span class="ocaml-source"> </span><span class="ocaml-support-type">int</span><span class="ocaml-source">
</span>
</code>
          </pre>
          <p>As of writing this post, we are waiting for the full OCaml 5.4 feature freeze and magic number bump. Note this is <em>support for OCaml 5.4</em><![CDATA[ (in ppxlib terms, we know have migration functions for 5.3 <-> 5.4) not a bump to use the 5.4 parsetree in ppxlib.]]></p>
          <p>
            <strong>(ppxlib)[Ppxlib]The Future of </strong>
          </p>
          <p>I have now been helping maintain <a href="https://patrick.sirref.org/ppxlib/">Ppxlib</a> for a while and I am beginning to wonder about the long-term vision for the project. <a href="https://patrick.sirref.org/ppxlib/">Ppxlib</a> is a central component to any modern OCaml library or tool, <a href="https://sherlocode.com/">Sherlocode</a> reckons there's <em>18.3k</em> instances of <code><![CDATA[[@@deriving]]></code><![CDATA[. Yet, every compiler release is a painful, two-phase process for the maintainers. First, we have to support the new release of the compiler. This is mostly okay but does involve adding lots of code to Ppxlib (we need a whole copy of the Parsetree!). Later on down the line, we have to bump the AST and this often breaks many ppxes.]]></p>
          <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.</p>
          <p>I have mentioned <a href="https://patrick.sirref.org/ppxlib-5-2/">before</a> 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 <em>select</em> their AST to work with. How this interacts with modules like <code>Ast_builder</code> is unclear to me, but it would mean user's can remain on older ASTs even when <a href="https://patrick.sirref.org/ppxlib/">ppxlib</a> bumps the internal, main AST.</p>
        </section>
        <section>
          <header>
            <h2>Sherlorocq</h2>
          </header>
          <p><a href="https://rocq-prover.org/">Rocq</a><![CDATA[ is a theorem prover (originally called]]> <code>coq</code><![CDATA[) from many of the same folks who brought you OCaml.]]>  I have been interested in theorem provers for a while, more from an engineering perspective and less from a theoretical one. My good friend, <a href="https://patrick.sirref.org/dhsorens/">Derek Sorenson</a>, taught me about Rocq when we <a href="https://github.com/dhsorens/mrdt">encoded <em>mergeable replicated datatypes</em></a>. Later I had a go at encoding <a href="https://github.com/patricoferris/coq-difc"><em>decentralised information flow control</em></a><![CDATA[ (also in]]> <a href="https://github.com/patricoferris/difc-star">Fstar</a><![CDATA[).]]></p>
          <p>During this process, I found it quite challenging to find Rocq code that I could learn from. Compared to using say OCaml's <code>Stdlib</code><![CDATA[, using Rocq's standard library of datatypes and proofs did not come naturally (not helped by the fact that at the time I could not get the LSP to play ball).]]></p>
          <p>This lead me to port <a href="https://patrick.sirref.org/artw/">Arthur Wendling's</a> excellent <a href="https://sherlocode.com/">Sherlocode</a> to do the same thing only for Rocq code. Luckily, it uses <a href="https://swtch.com/~rsc/regexp/regexp4.html">regular expression matching with a trigram index</a> so it is not tied to any particular programming language. <![CDATA[Additionally, it is somewhat opam-centric (not actually that much) which is perfect for Rocq!]]></p>
          <p>Anyway, I've had some interest from the people at Inria to bring the server back to life. Their wish is my command!</p>
          <p><a href="https://sherlorocq.sirref.org/">Sherlorocq</a> is back online!</p>
        </section>
      </div>
    </content>
  </entry>
  <entry>
    <title>Shelter in the Forest</title>
    <published>2025-04-21T00:00:00-00:00</published>
    <updated>2025-04-21T00:00:00-00:00</updated>
    <author>
      <name>https://patrick.sirref.org/Patrick Ferris/</name>
      <uri>https://patrick.sirref.org/Patrick%20Ferris/</uri>
    </author>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/weekly-2025-04-21/" />
    <id>https://patrick.sirref.org/weekly-2025-04-21/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>I spent much of this week working on Shelter and things related to it. Some of that time was also spent on Forester.</p>
        <section>
          <header>
            <h2>Forester</h2>
          </header>
          <p>I added two important quality-of-life features to my frontend to Forester this week.</p>
          <section>
            <header>
              <h3>Bibtex Support</h3>
            </header>
            <p>I had previously mentioned adding support to <a href="https://patrick.sirref.org/forester/">Forester</a> for <a href="https://patrick.sirref.org/weekly-2025-01-20/">Markdown</a>. This week I added support for Bibtex too. From any <code>*.bib</code> file in your forest, <a href="https://patrick.sirref.org/forester/">Forester</a> will now dutifully recognise it as a Bibtex file and convert, as best it can, all the entries into <code>Reference</code> trees.</p>
            <p>I'm becoming quite convinced of this model at the moment. I'm using Forester's <code>Code.t</code> as a target representation. In fact, to ease the process, I really shouldn't spend <em>all my time</em> on my website, I have reused my <code>Yaml.t -&gt; Code.t</code> and <code>Markdown.t -&gt; Code.t</code> functions in the Bibtex parser.</p>
            <p>To see it in action, you could have a look at the <a href="https://patrick.sirref.org/mokhov-build-systems/">Build Systems à la Carte</a> paper which is generated completely from Bibtex.</p>
          </section>
          <section>
            <header>
              <h3>Full Heading Support</h3>
            </header>
            <p>The eagled-eyed viewer may have noticed that the table of contents for this page has <em>more than one level</em>. I finally caved and spent an evening rejigging my <code>Cmarkit.Doc.t -&gt; Tree</code> code which was hacky and broken and is now less hacky and less broken.</p>
            <p>In addition, headings support links and emphasis etc.</p>
          </section>
          <section>
            <header>
              <h3>Lunch with <a href="https://patrick.sirref.org/jonmsterling/">Jon Sterling</a></h3>
            </header>
            <p>I had a delightful lunch with <a href="https://patrick.sirref.org/jonmsterling/">Jon Sterling</a> discussing the future of Forester, the nature of <![CDATA[the Web (old and new) and the success posting weekly updates for our colleagues. Thanks Jon.]]></p>
          </section>
        </section>
        <section>
          <header>
            <h2><a href="https://patrick.sirref.org/shelter/">Shelter</a> Fixes</h2>
          </header>
          <p>I spent a good chunk of my week fixing bugs in <a href="https://patrick.sirref.org/shelter/">Shelter</a> with the aim to perhaps setup a VM somewhere and let people kick the tyres of what we've got so far.</p>
          <p>The first bug is pretty annoying. At the moment, our filsystem backend is ZFS and we make heavy use of snapshots and cloning in order to provide time-travelling capabilities. Unfortunately, ZFS will take a snapshot before <![CDATA[data has fully made it to disk (or whatever is the equivalent point it should reach in ZFS). Commands that generated]]>  lots of disk activity would be snapshotted in a half finished state and this would cause all sorts of problems. Thanks to <a href="https://patrick.sirref.org/mtelvers/">Mark Elvers</a> for the pointer to how OBuilder uses ZFS for the OCaml macOS builders which unmount datasets immediately therefore inducing a <em>flush</em> of sorts. Shelter now follows a similar model with all of the slow downs that create. <a href="https://patrick.sirref.org/anilmadhavapeddy/">Anil</a> and I discussed some amalgamation of overlayfs, tmpfs and ZFS to alleviate some of this but for now that's a premature optimisation.</p>
          <section>
            <header>
              <h3>A small eDSL for <a href="https://patrick.sirref.org/shelter/">Shelter</a></h3>
            </header>
            <p>Whilst testing <a href="https://patrick.sirref.org/shelter/">Shelter</a>, 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.</p>
            <p>This lead me to revisit the <a href="https://patrick.sirref.org/mokhov-build-systems/">Build systems à la Carte</a> paper and rediscover <a href="https://patrick.sirref.org/mokhov-selective-2019/">selective applicative functors</a>.</p>
            <p><![CDATA[I started playing around with a selective applicative interface to Shelter, this would allow you to express your dependencies statically but select them dynamically (as the paper says).]]></p>
            <pre class="hilite">
              <code><span class="ocaml-keyword-other">module</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">D</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">Shl</span><span class="ocaml-source"> </span><span class="ocaml-source"><![CDATA[(]]> </span><span class="ocaml-constant-language-capital-identifier">Identity</span><span class="ocaml-source"><![CDATA[)]]> </span><span class="ocaml-source">
</span>
<span class="ocaml-source">
</span>
<span class="ocaml-keyword">let</span><span class="ocaml-source"> </span><span class="ocaml-entity-name-function-binding">shelterfile</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-keyword">let</span><span class="ocaml-source"> </span><span class="ocaml-keyword">open</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">D</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other">in</span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-keyword">let</span><span class="ocaml-source"> </span><span class="ocaml-entity-name-function-binding">base_image</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source"> </span><span class="ocaml-source">from</span><span class="ocaml-source"> </span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-string-quoted-double">alpine</span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other">in</span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-keyword">let</span><span class="ocaml-source"> </span><span class="ocaml-entity-name-function-binding">is_node_lst</span><span class="ocaml-source"> </span><span class="ocaml-source">img</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">String</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">equal</span><span class="ocaml-source"> </span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-string-quoted-double">v22.15.0</span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-source"> </span><span class="ocaml-source"><![CDATA[(]]> </span><span class="ocaml-source">stdout</span><span class="ocaml-source"> </span><span class="ocaml-source">img</span><span class="ocaml-source"><![CDATA[)]]> </span><span class="ocaml-source"> </span><span class="ocaml-keyword-other">in</span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-keyword">let</span><span class="ocaml-source"> </span><span class="ocaml-entity-name-function-binding">cmds</span><span class="ocaml-source"> </span><span class="ocaml-source">base</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source">
</span>
<span class="ocaml-source">    </span><span class="ocaml-keyword">let</span><span class="ocaml-source"> </span><span class="ocaml-entity-name-function-binding">node_version</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source"> </span><span class="ocaml-source">run</span><span class="ocaml-source"> </span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-string-quoted-double">node --version</span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-source"> </span><span class="ocaml-source">base</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other">in</span><span class="ocaml-source">
</span>
<span class="ocaml-source">    </span><span class="ocaml-constant-language-capital-identifier">Select</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">if'</span><span class="ocaml-source">
</span>
<span class="ocaml-source">      </span><span class="ocaml-source"><![CDATA[(]]> </span><span class="ocaml-constant-language-capital-identifier">Select</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">map</span><span class="ocaml-source"> ~</span><span class="ocaml-source">f</span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source">is_node_lst</span><span class="ocaml-source"> </span><span class="ocaml-source">node_version</span><span class="ocaml-source"><![CDATA[)]]> </span><span class="ocaml-source">
</span>
<span class="ocaml-source">      </span><span class="ocaml-source"><![CDATA[(]]> </span><span class="ocaml-source">run</span><span class="ocaml-source"> </span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-string-quoted-double"><![CDATA[node -e 'console.log('success!')]]> </span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-source"><![CDATA[)]]> </span><span class="ocaml-source">
</span>
<span class="ocaml-source">      </span><span class="ocaml-source"><![CDATA[(]]> </span><span class="ocaml-source">run</span><span class="ocaml-source"> </span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-string-quoted-double"><![CDATA[node -e 'console.log('failure!')]]> </span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-source"><![CDATA[)]]> </span><span class="ocaml-source">
</span>
<span class="ocaml-source">      </span><span class="ocaml-source">base</span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-keyword-other">in</span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-source">with_session</span><span class="ocaml-source"> </span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-string-quoted-double">node</span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-source"> </span><span class="ocaml-source"><![CDATA[(]]> </span><span class="ocaml-source">cmds</span><span class="ocaml-source"> </span><span class="ocaml-source">base_image</span><span class="ocaml-source"><![CDATA[)]]> </span><span class="ocaml-source">
</span>
</code>
            </pre>
            <p>From this, we get a slightly more expressive way to describe images.</p>
          </section>
        </section>
        <section>
          <header>
            <h2><a href="https://patrick.sirref.org/geocaml/">Geocaml</a> TIFF Library</h2>
          </header>
          <p>I was pleasantly surprised to receive a pull request from <a href="https://patrick.sirref.org/mdales/">Michael</a> 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.</p>
          <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 <a href="https://patrick.sirref.org/talex5/">Thomas Leonard</a> the root cause was OCaml's <code>OUnit2</code><![CDATA[ library using process-level parallelism (via]]> <code>Unix.fork</code><![CDATA[), sharing the ring between the parent and the child]]>  lead to the issues.</p>
          <p><a href="https://github.com/ocaml-multicore/eio/issues/801">Read more about that issue on the Eio issue tracker</a>.</p>
        </section>
        <section>
          <header>
            <h2><a href="https://patrick.sirref.org/part-ii-2024/">Part II</a> Students</h2>
          </header>
          <p>As the new term begins, it signals that there are only just over two weeks for the final year undegrads at <a href="https://patrick.sirref.org/ucam/">Cambridge</a> to submit their dissertations.</p>
          <p><![CDATA[The four students that I help supervise have been sending me drafts of their work (and reminder you can]]> <a href="https://patrick.sirref.org/part-ii-2024/">read about their projects</a><![CDATA[)]]>  and I'm very impressed. I'm sure the next two weeks will be stressful, but I'm proud of what they have accomplished over the past academic year.</p>
        </section>
      </div>
    </content>
  </entry>
  <entry>
    <title>Shelter, Hazel and More!</title>
    <published>2025-03-31T00:00:00-00:00</published>
    <updated>2025-03-31T00:00:00-00:00</updated>
    <author>
      <name>https://patrick.sirref.org/Patrick Ferris/</name>
      <uri>https://patrick.sirref.org/Patrick%20Ferris/</uri>
    </author>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/weekly-2025-03-31/" />
    <id>https://patrick.sirref.org/weekly-2025-03-31/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>Last week I focused on <a href="https://patrick.sirref.org/shelter/">Shelter</a> -- 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.</p>
        <section>
          <header>
            <h2>Shelter Prototype</h2>
          </header>
          <p>Shelter is a spin-off from the work <a href="https://patrick.sirref.org/mdales/">Michael</a> and I started with <a href="https://github.com/quantifyearth/shark">Shark</a>. It takes the same ideas but applies them directly to a shell-like interface.</p>
          <p>We're still in the middle of working all of this, but you can read more about it at <a href="https://patrick.sirref.org/shelter/">Shelter</a>.</p>
        </section>
        <section>
          <header>
            <h2>Forester Hacking</h2>
          </header>
          <p>As you can probably tell, my website is still using <a href="https://patrick.sirref.org/forester/">Forester</a>. I rebased my Markdown branch to include the new Atom syndication feature.</p>
          <p>Alongside that I added support for arbitrary HTML injection into Forester via codeblocks in Markdown. This was actually very straightforward thanks to <a href="https://ocaml.org/p/markup">Markup</a> and being able to re-parse Forester syntax in the middle of converting a Markdown document. The HTML for the shell in <a href="https://patrick.sirref.org/shelter/">Shelter</a> uses this feature.</p>
          <p>If you are interested in taking this custom Forester for a spin, there's <a href="https://github.com/patricoferris/ocaml-forester/tree/5-dev-md">a branch on Github</a>. In fact, nearly the only change beyond letting the core engine know about markdown files, is <a href="https://github.com/patricoferris/ocaml-forester/blob/5-dev-md/lib/compiler/Parse_md.ml">adding a new parser frontend</a>.</p>
        </section>
        <section>
          <header>
            <h2>Hazel</h2>
          </header>
          <p>For one of my <a href="https://patrick.sirref.org/part-ii-2024/">Part II</a> 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.</p>
          <p>Consider the following OCaml <code>map</code> function.</p>
          <pre class="hilite">
            <code><span class="ocaml-keyword">let</span><span class="ocaml-source"> </span><span class="ocaml-keyword">rec </span><span class="ocaml-entity-name-function-binding">map</span><span class="ocaml-source"> </span><span class="ocaml-source">f</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other">function</span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-keyword-other">|</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-list"><![CDATA[[]]]> </span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">-&gt;</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-list"><![CDATA[[]]]> </span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-keyword-other">|</span><span class="ocaml-source"> </span><span class="ocaml-source">x</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source"> </span><span class="ocaml-source">xs</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">-&gt;</span><span class="ocaml-source"> </span><span class="ocaml-source"><![CDATA[(]]> </span><span class="ocaml-source">f</span><span class="ocaml-source"> </span><span class="ocaml-source">x</span><span class="ocaml-source"><![CDATA[)]]> </span><span class="ocaml-source"> </span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source"> </span><span class="ocaml-source">map</span><span class="ocaml-source"> </span><span class="ocaml-source">f</span><span class="ocaml-source"> </span><span class="ocaml-source">xs</span><span class="ocaml-source">
</span>
</code>
          </pre>
          <p>The tool, <a href="https://github.com/patricoferris/hazel_of_ocaml"><code>hazel_of_ocaml</code></a> can translate this to Hazel code, including making the polymorphism explicit.</p>
          <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 ?]]></pre>
          <p>You can copy and paste that codeblock into the <a href="https://hazel.org/build/dev/">hazel playground</a><![CDATA[. But do note that it still needs some manual editing to add the type applications in directly (]]> <code>map@&lt;a&gt;@&lt;b&gt;</code><![CDATA[). With the right amount of type-inferencing and scoping I actually think that you could place those type applications in yourself. This could make a nice Part II project I think.]]></p>
        </section>
        <section>
          <header>
            <h2>Ppxlib</h2>
          </header>
          <p>I recently wrote about the painful experience of <a href="https://patrick.sirref.org/ppxlib-5-2/">miragrating ppxlib to the 5.2 OCaml AST</a>. This week, Nathan Rebours and I merged a PR to add the <a href="https://github.com/ocaml-ppx/ppxlib/pull/558">5.3 AST</a>! 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 <code>Pexp_effect</code> parsetree node. I'll write a little more about this in a separate post soon.</p>
        </section>
      </div>
    </content>
  </entry>
  <entry>
    <title>Vpnkit, Void Processes, LSP Servers</title>
    <published>2025-02-17T00:00:00-00:00</published>
    <updated>2025-02-17T00:00:00-00:00</updated>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/weekly-2025-02-17/" />
    <id>https://patrick.sirref.org/weekly-2025-02-17/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>Previous <a href="https://patrick.sirref.org/weeklies/">weeklies</a> used <strong>strong</strong> emphasis to distinguish sections. This comes from <a href="https://patrick.sirref.org/forester/">Forester</a>'s philosophy about atomicity of the content in your <em>forest</em>.</p>
        <p>However, <em>subtrees</em> are supported! I quickly hacked together the ability to use <em>subheadings</em> to indicate <em>subtrees</em>. This is strictly less expressive than the <code><![CDATA[\subtree{}]]></code> of <a href="https://patrick.sirref.org/forester/">Forester</a>'s default syntax as we cannot <em>close</em> heading sections in Markdown.</p>
        <p>This weekly uses subtrees.</p>
        <section>
          <header>
            <h2>Vpnkit</h2>
          </header>
          <p>I spent some time this week trying to upgrade vpnkit to OCaml 5. I was originally working on <a href="https://patrick.sirref.org/vpnkit-er/">a paper idea</a> which might need benchmarks, but <a href="https://patrick.sirref.org/anilmadhavapeddy/">Anil</a> and I decided we could simply point to the port I did and show how it has simplified much of the code.</p>
        </section>
        <section>
          <header>
            <h2>Void Processes</h2>
          </header>
          <p><![CDATA[Work continued on implementing (and fully exploring)]]> <a href="https://patrick.sirref.org/void-process/">void processes</a>. A lot of the groundwork already exists in <a href="https://blog.hillion.co.uk/posts/void-processes/dissertation/jsh77-dissertation.pdf">Jake Hillion's master's thesis</a>.</p>
          <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!</p>
          <p><![CDATA[In addition to the root mount (taken care of with]]> <a href="https://man7.org/linux/man-pages/man2/pivot_root.2.html">pivot_root</a><![CDATA[), we need to be able to add additional mounts into the process' environment. These can now be added. All mount points can be mounted]]> <code>readonly</code> or <code>readwrite</code>.</p>
          <p><![CDATA[Here is the "Hello, World!" example (the]]> <code>/say/hey</code> program has been statically compiled using <code>musl-gcc</code><![CDATA[).]]></p>
          <pre class="hilite">
            <code><span class="ocaml-keyword">let</span><span class="ocaml-source"> </span><span class="ocaml-entity-name-function-binding">status</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-keyword">let</span><span class="ocaml-source"> </span><span class="ocaml-entity-name-function-binding">void</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source">
</span>
<span class="ocaml-source">    </span><span class="ocaml-source">empty</span><span class="ocaml-source"> 
</span>
<span class="ocaml-source">    </span><span class="ocaml-keyword-operator">|&gt;</span><span class="ocaml-source"> </span><span class="ocaml-source">mount</span><span class="ocaml-source"> ~</span><span class="ocaml-source">mode</span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-constant-language-capital-identifier">R</span><span class="ocaml-source"> ~</span><span class="ocaml-source">src</span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source">hey_dir</span><span class="ocaml-source"> ~</span><span class="ocaml-source">tgt</span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-string-quoted-double">say</span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-source">
</span>
<span class="ocaml-source">    </span><span class="ocaml-keyword-operator">|&gt;</span><span class="ocaml-source"> </span><span class="ocaml-source">exec</span><span class="ocaml-source"> </span><span class="ocaml-source"><![CDATA[[]]> </span><span class="ocaml-source"> </span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-string-quoted-double">/say/hey</span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-source"> </span><span class="ocaml-source"><![CDATA[]]]> </span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-keyword-other">in</span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-keyword">let</span><span class="ocaml-source"> </span><span class="ocaml-entity-name-function-binding">t</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">Void</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">spawn</span><span class="ocaml-source"> ~</span><span class="ocaml-source">sw</span><span class="ocaml-source"> </span><span class="ocaml-source">void</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other">in</span><span class="ocaml-source">
</span>
<span class="ocaml-source">  </span><span class="ocaml-constant-language-capital-identifier">Promise</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">await</span><span class="ocaml-source"> </span><span class="ocaml-source"><![CDATA[(]]> </span><span class="ocaml-constant-language-capital-identifier">Void</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">exit_status</span><span class="ocaml-source"> </span><span class="ocaml-source">t</span><span class="ocaml-source"><![CDATA[)]]> </span><span class="ocaml-source">
</span>
</code>
          </pre>
          <p>There really is nothing else in there. Without specifying a <code>root</code> mount, the void process is started with an empty <code>tmpfs</code> root. Next on the list is networking!</p>
        </section>
        <section>
          <header>
            <h2>LSP Servers</h2>
          </header>
          <p>I got a little side-tracked building a library for writing <a href="https://microsoft.github.io/language-server-protocol/">LSP</a> servers in OCaml: <a href="https://patrick.sirref.org/mlsp/">mlsp</a>. 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 <a href="https://marketplace.visualstudio.com/items?itemName=ms-python.python">the official extension</a> which gives you linting, formatting, code navigation etc. All of these features are communicating using the LSP.</p>
          <p>It seems <a href="https://github.com/FurqanSoftware/codemirror-languageserver">Code Mirror</a><![CDATA[ can already proxy over a websocket for LSP support too (we might not even need that as we can compile OCaml directly to JavaScript/Webassembly and have the whole thing running locally!).]]></p>
        </section>
        <section>
          <header>
            <h2>Open-Source &amp; Community</h2>
          </header>
          <p><a href="https://patrick.sirref.org/anilmadhavapeddy/">Anil</a> and I had a great conversation this week about building community especially as it pertains to open-source and OCaml.</p>
          <p>I've been going back over <a href="https://patrick.sirref.org/ostrom-gtc/">Governing the Commons</a>, but have already discovered <a href="https://patrick.sirref.org/franklin-rwt/">The Real World of Technology</a>!</p>
          <p>More thoughts on all of this soon... maybe</p>
        </section>
      </div>
    </content>
  </entry>
  <entry>
    <title>Teaching, teaching, teaching...</title>
    <published>2025-02-10T00:00:00-00:00</published>
    <updated>2025-02-10T00:00:00-00:00</updated>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/weekly-2025-02-10/" />
    <id>https://patrick.sirref.org/weekly-2025-02-10/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p><![CDATA[On paper, I don't have that many students. I teach four undergraduates (first]]>  <![CDATA[year students at Pembroke College)]]> <a href="https://patrick.sirref.org/discrete-maths/">Discrete Maths</a>. I supervise three third year students for their <a href="https://patrick.sirref.org/part-ii-2024/">final year project</a> and another one I co-supervise with <a href="https://patrick.sirref.org/mdales/">Michael Dales</a>. However, I do end up spending at least two full days a week on teaching. Something I really enjoy and take seriously. The time it takes is also quite unpredictable; last week for instance all the third year students <![CDATA[had their mid-project demonstrations (a five-minute presentation in front of]]>  <![CDATA[their peers and a few professor-types). My first year students also found two]]>  slides particularly challenging to understand from their lectures and asked if I could help explain what was going on, so I <a href="https://patrick.sirref.org/dm-note.pdf">produced some materials for that</a>.</p>
        <p>
          <strong>OCaml</strong>
        </p>
        <p>Within the OCaml universe I spent a good bit of time trying to maintain a couple of different packages:</p>
        <ol>
          <li>
            <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 <a href="https://patrick.sirref.org/anilmadhavapeddy/">Anil</a>, 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.</p>
          </li>
          <li>
            <p>Ppxlib: In addition to the <a href="https://github.com/ocaml-ppx/ppxlib/pull/514">5.2 AST bump</a><![CDATA[ (which is nearly ready to be merged), I queued up a]]> <a href="https://github.com/ocaml-ppx/ppxlib/pull/558">5.3 AST bump</a> right behind it. I plan to write up a more detailed post about the challenges of maintaining this part of ppxlib.</p>
          </li>
        </ol>
        <p>
          <strong>Paris</strong>
        </p>
        <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.</p>
        <figure>
  <img src="pissarro.jpeg" width="400" alt="Woman in an Orchard (Spring Sunshine in the Meadow at Eragny)." />
  <figcaption>Woman in an Orchard (Spring Sunshine in the Meadow at Eragny)</figcaption>
</figure>
      </div>
    </content>
  </entry>
  <entry>
    <title>AT Protocol and an IR for Wikis</title>
    <published>2025-01-27T00:00:00-00:00</published>
    <updated>2025-01-27T00:00:00-00:00</updated>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/weekly-2025-01-27/" />
    <id>https://patrick.sirref.org/weekly-2025-01-27/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <strong>AT Protocol</strong>
        </p>
        <p>This week I've been diving into the <a href="https://atproto.com/">AT Protocol</a>.</p>
        <blockquote>
          <p>The Authenticated Transfer Protocol, aka atproto, is a decentralized protocol for large-scale social web applications.</p>
        </blockquote>
        <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 <a href="https://patrick.sirref.org/ipfs/">IPFS</a>. Thankfully, a few years ago, I was working on building out a suite of OCaml libraries for working with <a href="https://patrick.sirref.org/ipfs/">IPFS</a>. For example, <a href="https://github.com/patricoferris/ocaml-cid">ocaml-cid</a>, self-describing content-addressed identifiers.</p>
        <pre class="hilite">
          <code><span class="ocaml-keyword-other">#</span><span class="ocaml-source"> </span><span class="ocaml-keyword">let</span><span class="ocaml-source"> </span><span class="ocaml-entity-name-function-binding">s</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source"> </span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-string-quoted-double">zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA</span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span><span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span><span class="ocaml-source">
</span>
<span class="ocaml-keyword-other">val</span><span class="ocaml-source"> </span><span class="ocaml-source">s</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source"> </span><span class="ocaml-support-type">string</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source"> </span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-string-quoted-double">zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA</span><span class="ocaml-string-quoted-double">"</span><span class="ocaml-source">
</span>
<span class="ocaml-keyword-other">#</span><span class="ocaml-source"> </span><span class="ocaml-keyword">let</span><span class="ocaml-source"> </span><span class="ocaml-entity-name-function-binding">cid</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">Cid</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">of_string</span><span class="ocaml-source"> </span><span class="ocaml-source">s</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">|&gt;</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">Result</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">get_ok</span><span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span><span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span><span class="ocaml-source">
</span>
<span class="ocaml-keyword-other">val</span><span class="ocaml-source"> </span><span class="ocaml-source">cid</span><span class="ocaml-source"> </span><span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">Cid</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">t</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">=</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">&lt;</span><span class="ocaml-source">abstr</span><span class="ocaml-keyword-operator">&gt;</span><span class="ocaml-source">
</span>
<span class="ocaml-keyword-other">#</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">Cid</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">pp_human</span><span class="ocaml-source"> </span><span class="ocaml-constant-language-capital-identifier">Format</span><span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</span><span class="ocaml-source">std_formatter</span><span class="ocaml-source"> </span><span class="ocaml-source">cid</span><span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span><span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</span><span class="ocaml-source">
</span>
<span class="ocaml-source">cidv1</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">-</span><span class="ocaml-source"> </span><span class="ocaml-source">base58btc</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">-</span><span class="ocaml-source"> </span><span class="ocaml-source">raw</span><span class="ocaml-source"> </span><span class="ocaml-keyword-operator">-</span><span class="ocaml-source"> </span><span class="ocaml-source">ident</span><span class="ocaml-source"><![CDATA[(]]> </span><span class="ocaml-source">sha2</span><span class="ocaml-keyword-operator">-</span><span class="ocaml-constant-numeric-decimal-integer">256</span><span class="ocaml-source"><![CDATA[)]]> </span><span class="ocaml-source"> </span><span class="ocaml-source">length</span><span class="ocaml-source"><![CDATA[(]]> </span><span class="ocaml-constant-numeric-decimal-integer">32</span><span class="ocaml-source"><![CDATA[)]]> </span><span class="ocaml-source"> </span><span class="ocaml-source">digest</span><span class="ocaml-source"><![CDATA[(]]> </span><span class="ocaml-source">6e 6f </span><span class="ocaml-source">f7</span><span class="ocaml-source"> </span><span class="ocaml-constant-numeric-decimal-integer">95</span><span class="ocaml-source"> 0a </span><span class="ocaml-constant-numeric-decimal-integer">36</span><span class="ocaml-source"> </span><span class="ocaml-constant-numeric-decimal-integer">18</span><span class="ocaml-source"> 7a  </span><span class="ocaml-constant-numeric-decimal-integer">80</span><span class="ocaml-source"> </span><span class="ocaml-constant-numeric-decimal-integer">16</span><span class="ocaml-source"> </span><span class="ocaml-constant-numeric-decimal-integer">13</span><span class="ocaml-source"> </span><span class="ocaml-constant-numeric-decimal-integer">42</span><span class="ocaml-source"> 6e </span><span class="ocaml-constant-numeric-decimal-integer">85</span><span class="ocaml-source"> 8d </span><span class="ocaml-source">ce</span><span class="ocaml-source">
</span>
<span class="ocaml-source">                                                            </span><span class="ocaml-constant-numeric-decimal-integer">68</span><span class="ocaml-source"> 6c </span><span class="ocaml-source">d7</span><span class="ocaml-source"> </span><span class="ocaml-source">d7</span><span class="ocaml-source"> </span><span class="ocaml-source">e3</span><span class="ocaml-source"> </span><span class="ocaml-source">c0</span><span class="ocaml-source"> </span><span class="ocaml-source">fc</span><span class="ocaml-source"> </span><span class="ocaml-constant-numeric-decimal-integer">42</span><span class="ocaml-source">  </span><span class="ocaml-source">ee</span><span class="ocaml-source"> </span><span class="ocaml-constant-numeric-decimal-integer">03</span><span class="ocaml-source"> </span><span class="ocaml-constant-numeric-decimal-integer">30</span><span class="ocaml-source"> </span><span class="ocaml-constant-numeric-decimal-integer">07</span><span class="ocaml-source"> 2d </span><span class="ocaml-constant-numeric-decimal-integer">24</span><span class="ocaml-source"> 5c </span><span class="ocaml-constant-numeric-decimal-integer">95</span><span class="ocaml-source">
</span>
</code>
        </pre>
        <p>To this end I have built out some more OCaml libraries for working with atproto, including:</p>
        <ul>
          <li>
            <p><a href="https://github.com/patricoferris/ocaml-atproto-data">atproto-data</a>: the atproto data model, similar to JSON-LD.</p>
          </li>
          <li>
            <p><a href="https://github.com/patricoferris/ocaml-did">ocaml-did</a>: an OCaml library for working with decentralized identifiers.</p>
          </li>
          <li>
            <p><a href="https://github.com/patricoferris/ocaml-atproto-lexicon">atproto-lexicon</a>: atproto's schema format, I've been building a quick tool for doing an OCaml translation from these schemas.</p>
          </li>
        </ul>
        <p>I managed to get <a href="https://bsky.app/profile/patrick.sirref.org/post/3lh24rrjngw24">a post published from the OCaml library</a> after fixing it up and porting it to <a href="https://patrick.sirref.org/eio/">Eio</a>.</p>
        <p>
          <strong>An IR for Wikis</strong>
        </p>
        <p>I started working on a proof-of-concept intermediate representation for Wikis -- I imagine it a bit like <a href="https://github.com/stedolan/malfunction">malfunction</a> 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:</p>
        <ul>
          <li>
            <p>Links: External links, cross-wiki backlinks</p>
          </li>
          <li>
            <p>Versioned, temporal feeds</p>
          </li>
          <li>
            <p>Etc.</p>
          </li>
        </ul>
        <p>
          <strong>Other PhD Work</strong>
        </p>
        <p>I met with most of my <a href="https://patrick.sirref.org/part-ii/">Part II</a> students this week, and I'm excited about their work. Progress reports are due this week and next they have a presentation to give.</p>
        <p>In <a href="https://patrick.sirref.org/discrete-maths/">discrete maths</a> this week we did induction. Next up is a big section on sets, functions, bijections etc.</p>
        <p>
          <strong>Misc.</strong>
        </p>
        <p>I was happy to find the <a href="https://www.opentech.fund/fellowships/icfp/">Information Controls Fellowship Program</a>.</p>
        <blockquote>
          <p><![CDATA[The Information Controls Fellowship Program (ICFP) cultivates research, outputs, and creative collaboration on topics related to repressive internet censorship and surveillance.]]></p>
        </blockquote>
      </div>
    </content>
  </entry>
  <entry>
    <title>Forester, ICFP, Wikis</title>
    <published>2025-01-20T00:00:00-00:00</published>
    <updated>2025-01-20T00:00:00-00:00</updated>
    <link rel="alternate" type="text/html" href="https://patrick.sirref.org/weekly-2025-01-20/" />
    <id>https://patrick.sirref.org/weekly-2025-01-20/</id>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <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.</p>
        <p>
          <strong>ICFP Papers</strong>
        </p>
        <p>In conversation with <a href="https://patrick.sirref.org/anilmadhavapeddy/">Anil</a>, we looked at options for submitting a paper to ICFP. I wrote up some notes on some options <a href="https://patrick.sirref.org/icfp25-ideas/">we discussed</a>.</p>
        <p>
          <strong>Forester</strong>
        </p>
        <p>I spent some time this week converting this website to using <a href="https://www.jonmsterling.com/foreign-forester-jms-005P.xml">Forester</a>. 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 <a href="https://github.com/patricoferris/ocaml-forester/tree/markdown">available on Github</a>.</p>
        <p>The markdown frontend integrates very nicely and only a few changes were needed in the core logic of <a href="https://patrick.sirref.org/forester/">Forester</a> itself. Additionally, for any features not directly supported in markdown there is an escape hatch using code blocks such as:</p>
        <pre><![CDATA[```forester
\put\transclude/numbered{false}

\transclude{pxf-1000}
```]]></pre>
        <p>Personally, I'm still getting to grips with the <em>bottom-up</em> approach to building this site, atomically creating notes and reference cards that then are linked in many places.</p>
        <p>I'm excited to see how I can integrate some of the Forester concepts into "Shark".</p>
        <p>
          <strong>OCaml</strong>
        </p>
        <p>In the OCaml world, I spent time on <code>ppxlib</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 <a href="https://patrick.sirref.org/icfp25-ideas/">ICFP 2025</a> too.</p>
        <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.</p>
        <p>I also met with the single, OCaml Outreachy intern working on <a href="https://github.com/ocaml-semver/ocaml-api-watch">ocaml-api-watch</a>.</p>
        <p>
          <strong>Misc.</strong>
        </p>
        <p>I met with most of my <a href="https://patrick.sirref.org/part-ii-2024/">Part II</a> 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 <em>induction</em> part of their <a href="https://patrick.sirref.org/discrete-maths/">Discrete Maths</a> course.</p>
      </div>
    </content>
  </entry>
</feed>
