Recent-ish note for 2025-12-02

What's been going on recently? In order of decreasing share of my time:

I've got a whole (draft) post on Claude and Dune, but let's talk about the other things.

x-ocaml for teaching

Looking at x-ocaml for teaching has been interesting. I've been investigating how it might be used both for oxcaml and for Foundations of Computer Science. The idea I've been playing with recently is to have inline tests for cells, a bit like we do for the ticks that are part of FoCS. The goal is to have something like this:

<x-ocaml id="sort">
(* Implement a function that sorts a list of
   integers in ascending order *)
let rec sort lst =
  lst
</x-ocaml>

<x-ocaml spec-for="sort" run-on="never" hide-source>
val sort : int list -> int list
</x-ocaml>

<x-ocaml test-for="sort" run-on="never" hide-source>
let () = run (fun () ->
	test "empty list" (list int) [] (sort []);
	test "single element" (list int) [1] (sort [1]);
	test "three elements" (list int) [1; 2; 3] (sort [3; 1; 2]);
	test "five elements" (list int)
       [1; 2; 5; 8; 9] (sort [5; 2; 8; 1; 9]);
	test "duplicates" (list int) [1; 1; 1] (sort [1; 1; 1])
)
</x-ocaml>

There are 3 cells here - the implementation, the desired spec, and some tests, only the first of which is actually shown. What I'm aiming at is for there to be instant feedback. After you've finished typing, if Merlin reports no errors, I'm taking the contents of the `spec` cell, and transforming it into this, which is sent to the toplevel:

let _ : int list -> int list = sort

If this returns no errors, I then go on to run the test cell. The idea is that if it doesn't pass the spec test, then there is no point in attempting to run the tests, as they won't even compile.

I've got a prototype implementation on my experiments site.

Merging Sherlodoc indexes

A quite exciting part of the dune work will be the ability to easily create and maintain a local sherlodoc database of all of the dependencies of a project. This will allow fast querying by type or by text of all of the APIs for any library that your project depends upon, and it will be exact, unlike the MCP server that we prototyped as part of the work that Sadiq presented at ICFP this year.

However, while all of the odoc rules are now incremental, the assembly of the sherlodoc database is a one-shot executable that runs over all of the odocl files created by odoc. This can take quite a bit of time, so I put Claude on the task of seeing how feasible it would be to merge two databases together so that we could generate per-package sherlodoc dbs, then merge them together to create the final one, in the hope that this will be faster than running on all of the odocl files every time any one of them is updated. I have a branch with this work in it, and will shortly be able to try this out with the dune rules to see if it makes a difference. The branch is here.

Odoc sidebar

The sidebar we released with odoc 3 is a static piece of HTML. It allows for navigation, but not exploration. This has always bothered me a little - I quite like the way the sidebar works on ocaml.org, where the entire tree is available, and you can expand or collapse individual nodes. So, once again, Claude to the rescue! I gave it a quite minimal prompt, and it made a pretty good job of it. I asked it to ensure that when anything was clicked, it didn't reload the entire page, just the preamble, the main div, title and breadcrumbs, and to update the URL such that the back button worked as expected. The results of this are here