Nos activités commerciales ont déménagé : retrouvez-nous désormais sur titagone.com.

A tour of the OCaml Workshop 2026

Date: 2026-09-14
Catégorie: OCaml



This year, for the first time, the Functional Programming Workshops were held in Paris, on Inria's, the French National Computer Science Research Institute, campus along with a watch party for the ICFP conference at Indianapolis.

As each year we attended the OCaml Workshop to see the latest advances of our favourite state-of-the-art language, and as usual it was a blast! People from various companies and labs came to present their latest work in the OCaml ecosystem: Cambridge University, Inria, LexiFi, Meta, Robur, Sorbonne University and Tarides. Here's a quick summary of the day's talks.

A new workflow to build unikernels in OCaml

Romain Calabiscetta

Romain presented a brand new way to build Solo5 unikernels in OCaml. It’s based on two new OCaml components: unic and mfetch.

This lets you build unikernels without vendoring and recompiling entire dependency tree, as was the case with the usual opam-monorepo and mirage approach. With Solo5, in most cases one actually only needs to recompile C files with the Solo5 toolchain (and any package that depends on them). unic helps you identify those packages and mfetch sets them up in a dune vendored_dir so they can be rebuilt with the right toolchain for your unikernel. The rest of your dependencies, the pure OCaml ones, can just be installed via opam. No need for dune ports of your entire dependency tree anymore.

unic and mfetch in action, from Romain's slides

On the picture above, you can see how they are used to vendor the right set of dependencies when building a Solo5 unikernel in the Makefile of Romain's immuable project. You can also take a look at the slides (and at Romain's wonderful drawings).

Compiling FFI-heavy OCaml to WebAssembly: An Experience Report on MOPSA

Reda Boudrouss

Reda reported on how they compiled MOPSA, a static analysis platform which depends quite heavily on C/C++ libraries (APRON, GMP, MPFR, LLVM/Clang), to WebAssembly.

They took a completely different approach to the usual "OCaml in the browser": no js_of_ocaml or wasm_of_ocaml. They instead compiled the OCaml bytecode runtime itself, along with all C/C++ dependencies, using Emscripten. MOPSA is then compiled to bytecode and interpreted by the wasm-compiled OCaml runtime.

This approach saved them from rewriting thousands of lines of stubs in JavaScript or WebAssembly.

This wasn't a walk in the park though: they had to fix some nasty 32-bit bugs to get it to work, and some features don't behave properly because WASM offers no control over the floating-point rounding mode. But it's there!

The result is a not-so-slow web version of MOPSA: 10x slower than native, but much faster than their existing pure js_of_ocaml version!

This approach can easily be reused to compile any other project with a completely different set of C dependencies.

Javascript vs Wasm comparison, from Reda's slides

You can read the full article here if you'd like to know more, or browse the slides.

Security-team address

Edwin Török

Edwin gave us an overview of what the OCaml Security Team did this year. They are the main point of contact for all security issues in the OCaml world, especially for the compiler and the ecosystem tools. They published 17 advisories in 2026, across 11 packages; 3 of them were on the OCaml runtime itself (Marshal buffer over-read, Bigarray.reshape integer overflow, and command injection on Windows via filename). They are all listed in the security advisories database. A mailing list is also available if you want to stay up to date with security advisories. They also released opam-audit, a tool that audits your current switch against known CVEs. As it is an opam plugin, you install it once and it is then available on all your switches. The Security Team holds regular public meetings: the next one is on Tuesday, September 15th (slides).

A Capability Type System for OCaml

Yoann Padioleau

Yoann presented their Caps library, inspired by eio's capabilities, which provides fine-grained control over effectful or "dangerous" resources such as IO, network and system calls, using only existing OCaml language features.

The principle is that one forbids the use of effectful or dangerous functions from the standard library or from external libraries in their code, for instance via Semgrep rules, warnings or any linting system.

Any function that needs to access those resources must then be granted access explicitly:

val f : < Cap.stdout; Cap.fork; Cap.network; .. > -> int -> int

If you're unfamiliar with this syntax, the first argument's type is an object type. Just from the function's signature we know exactly which resources it can access.

Caps provides the abstract types for each resource, wrappers around the standard library and Unix functions such as:

val fork : < Cap.fork; .. > -> unit -> int

and an entry point:

val main : (all_caps -> 'a) -> 'a

which can only be called once in a program and is the only way to access capabilities. One then downcasts the all_caps object to pass it around, and the typechecker will ensure no one accesses undeclared resources.

Yoann's slides are available here if you want to learn more, or you can even watch the talk.

Runtime Types at LexiFi: Experience Report

Nicolas Ojeda Bär

Nicolas presented LexiFi's compiler extension for runtime types, an extension that grants access to type-directed programming in your OCaml codebase.

They define a type for the type witness of a type 'a:

type 'a ttype

Their patched compiler interprets [%t: <type-expr>] and generates a <type-expr> ttype type witness. This cannot be done by a simple PPX, because PPXs don't have access to type information; instead, it is done during or after type checking.

They also have a GADT xtype that describes a type's shape:

type 'a xtype =
  | Unit : unit xtype
  | Bool : bool xtype
  | Char : char xtype
  | Int : int xtype
  | Float : float xtype
  | String : string xtype
  | Option : 'b ttype -> 'b option xtype
  | List : 'b ttype -> 'b list xtype
  ...

and it can be obtained from a type witness with:

val xtype_of_ttype : 'a ttype -> 'a xtype

With that, they can easily generate generic printers, equality functions, JSON de/serializers, etc.:

val print : t:'a ttype -> 'a -> string

Such generic functions always take the type witness as an extra ~t labeled argument. When this argument is omitted at a call site, their compiler extension automatically adds it, with the type witness for the inferred type of the argument, whenever possible.

This also comes with type properties [@t <property-name> = <string>] which are embedded in the type witness so that generic functions can eventually interpret them. This makes it possible to customize the behaviour of a generic function for specific types, e.g. to mark that a record field should use a different name when serialized to JSON.

Compared to the PPX [@@deriving ...] approach, this might offer lower performance, as the functions aren't specialized for a specific type, but it comes with much better ease of use and flexibility: once one has the type witness for a type, they can pass it to any number of functions.

You can read more about LexiFi's runtime types here.

PPXs That Reach Their Destinations

Gabriel Radanne

Gabriel presented their proposal for exposing a low-level API allowing PPXs to transform functions into destination passing style (DPS for short).

OCaml 4.14 introduced the [@tail_mod_cons] transformation, which allows one to mark a function so the compiler can turn a natural-looking recursive function into a tail-recursive one, provided the recursive call is in tail position modulo a constructor application. For instance, the following map implementation for lists:

let[@tail_mod_cons] rec map f l =
  match l with
  | [] -> []
  | x :: xs ->
    let y = f x in
    y :: map f xs

is, roughly speaking, transformed into something that could be written as the following pseudocode:

let rec map_dps f l dst idx =
  match l with
  | [] -> dst.idx <- []
  | x :: xs ->
    let y = f x in
    let dst' = y ::{mutable} Hole in
    dst.idx <- dst';
    map_dps f xs dst' 1

Destinations can be seen as OCaml values with holes (write-once pointers) that can be filled later.

The proposal is to expose the following in the Obj module:

type 'a dest
val set_dest : 'a dest -> 'a -> unit

and a compiler-interpreted extension [%ocaml.value_with_holes ...] that would be replaced by the value, with holes, and a tuple made of all the destinations one needs to fill them:

type t = Foo of int * float array * string

let holed : t * (float Obj.dest * string Obj.dest) =
  [%ocaml.value_with_holes Foo (21, [| [%hole] |], [%hole])]

This is not meant to be used directly, but rather through PPXs that would transform functions in contexts where the current compiler transformation cannot be applied.

You can read the full proposal here, and see how Gabriel and their team apply this to transform tail calls modulo Async/Await here.

Slipshow: chill coding with OCaml

Paul-Elliot Anglès d'Auriac

Paul-Elliot presented new features of his Slipshow project. Slipshow is a tool to craft slideless presentations: your presentation is a continuously rolling slip, into which you can integrate handwriting and animations. A console command gives you full control over your animations, hand-made or imported. You can even switch between WYSIWYG and WYGIWYS editors!

Slipshow is written 100% in OCaml, and the compiler's guarantees strengthened it, from safety to speed, making the developer experience much smoother than with the original JavaScript prototype. Paul-Elliot summed it up by saying that it's OCaml's exceptional design, editor tooling and robust ecosystem that made working on this project so chill: guided by the compiler, without fear of introducing bugs.

Slipshow overview, from Paul-Elliot's slides

If you want to see it in action, take a look at Paul-Elliot's slides.

When Type Checking Goes Wrong, but Keeps Going

Xavier Van De Woestyne

Merlin is a well-known (multi-)editor helper for OCaml. Where the compiler stops at the first error, merlin displays all of them, even when the code block is unfinished; Xavier presented the recovery system that makes this possible. For this, merlin uses a patched version of the type checker. That system worked for a while, but the maintenance burden of updating it with every compiler release is not sustainable.

With the help of the compiler team, they finally upstreamed this typing recovery feature into the compiler itself. The next OCaml 5.6.0 release will offer a new flag -typing-recovery that can be used by merlin to show all the errors found.

Because the recovery mechanism works on incomplete or incorrect code, the errors that follow the first one might be inaccurate; this mode is therefore not recommended for regular users, who should rely on the regular compiler type error reporting.

This will greatly ease support for new compilers in merlin, though there are still some patches to apply, such as their parsing recovery mechanism.

You can find Xavier's slides here.

JSON parsing in OxCaml: fast, but not too fast

Artem Pianykh

Artem presented their SIMD JSON parser implementation, written in OxCaml.

They used OxCaml (Jane Street's current fork of OCaml, which uses the flambda2 optimisation backend, developed here at OCamlPro) to provide a lightning fast JSON parsing library, inspired by C++'s simdjson.

Thanks to OxCaml features such as stack allocation, unboxed types and — of course — SIMD instruction support, plus a bit of elbow grease, they managed to write a parser up to 9 times faster than Yojson.

The library exposes two parsing interfaces: one that produces the usual Json.t variant type, and a lower-level but much faster one.

It is still roughly 3 times slower than simdjson, but there's room for improvement. Artem mentioned that unboxed variants could drastically improve the Json.t parser, among other things.

If you'd like to know more, you can read Artem's detailed article or jump straight to the code.

A new implementation of Short-paths

Ulysse Gérard, Paul-Elliot Anglès d'Auriac

Ulysse presented a new design to select short paths for printing type error messages.

Type short-paths are very useful to make types easier to read and understand at first glance. Instead of displaying Int.t, the compiler shows int; and if you defined type foo = string * int * float, foo is selected by the compiler. However, it is also very opinionated, as we saw clearly in the survey/poll conducted live during the presentation. In more specific cases, such as defining foo in a module Bar, some prefer to keep foo when including that module, while others prefer Bar.foo to keep the information about the origin.

Currently there are 2 ways to compute short paths: one implemented in the compiler to display error messages with the -short-paths option, and the other in Merlin. The compiler determines short paths with a lazy breadth-first search in the environment until it finds an adequate candidate. It is quite costly, but this is not an issue for the compiler, which shows 1 error at a time. Merlin's method is a complex engine that explores the possible branches more deeply when looking for a short path and, to gain performance, cuts some of them when needed. It results in a much faster and more accurate short-path selection.

Merlin's short-path detection has a quite high maintenance burden. The idea of Merlin's team is to have a new short-path mechanism in the compiler itself, one that would remain maintainable and perform well enough to display all type error messages. That new process takes advantage of the compiler to gather information at typing time and build the set of paths used in the source; that set is reused later, so printing doesn't slow down compilation. From it, a domain of discourse is built at printing time, following a given set of inclusion rules: for example, if a module is opened, all its types are included, and if a module is renamed, all the types defined by the original and by the substitution are added to the domain of discourse. To select the shortest path, they build a priority list sorted by cost (by length, with a malus for the presence of double underscores), then they canonicalise the first-level path of that list; if the shortest canonicalised path is valid in the current environment, it is selected. Otherwise, it loops back to the canonicalisation step.

The proposed short-path algorithm, from Ulysses's slides

They tested that algorithm on OxCaml, and their prototype showed much better accuracy in short-path selection (with respect to their requirements) than both the compiler and Merlin, but it remains slower than Merlin. There is some ongoing work to gain performance.

You can find their slides here.

Towards a Benchmarking Service for OCaml

Luis Eduardo de Souza Amorim, Tim McGilchrist

Tim presented their new benchmarking framework for OCaml compilers. It consists of a series of tools to run, orchestrate and visualize several types of benchmarks on your computer.

Historically, Sandmark was used to benchmark OCaml compilers, but it is more focused on GC performance over a multitude of small code pieces. In addition to Sandmark's micro-benchmarks, other macro-benchmarks were added. The idea is to test real-world applications, configured to have relevant data, inspired by Java's Da Capo benchmark suite. They selected a dozen OCaml ecosystem tools and wrote scripts to run them on edge cases that highlight performance data. You can add your own tool to the benchmarks if you want to track regressions. The projects are built and run in isolation, with perf and olly wrapping them to collect system and OCaml runtime data respectively. You can see the results of the macro-benchmarks for the OCaml 5.4.1 compiler, comparing the stable release with a flambda-enabled build.

macro-benchmarks for OCaml 5.4.1 with flambda enabled relative to unmodified baseline

To round out this work, they want to offer these benchmarking tools as a service, triggered by a PR in CI, by regular jobs for OCaml releases and compiler options, etc.

We'd love to see Alt-Ergo added to the benchmarks, along with the possibility of running them for OxCaml with different flambda2 configurations!

You can take a look at Tim's extended slides.

First Class Docs in OCaml

Jon Ludlam

Jon proposed a reflection on how to handle the documentation of a project together with that of its dependencies.

odoc is the main tool to generate documentation in OCaml ecosystem. It is used by external tools to build cross package documentation, from odig that generates a full opam switch documentation to ocaml-docs-ci that generates the online documentation for ocaml.org opam repository packages. It is also used by dune with 2 targets, @doc that generates only the package documentation, and @doc-new that generates also the documentation for package dependencies.

Documenation tools comparison, from Jon's slides

dune @doc and odig still use odoc CLI in version 1, missing new features introduced in newer versions. Looking at how odoc is used in ocaml-docs-ci and dune @doc-new, the main difficulty is to build dependencies documentation. As odoc uses .cmt and .cmti artefacts and reimplements its own module system (in order to retrieve documentation information dropped by the compiler), it needs to be able to link each .odoc to an already present .odoc file of each dependency. Jon propose to consider odoc no longer as an optional package for documentation but a default package installed in each switch. There is already an opam plugin, odd that wraps each package install with documentation generation, allowing easy packages cross-reference. It provides switch-wide documentation search for direct users or editor completion.

This still has quite an impact on switch size and build times (~5% at the moment) but there is ongoing work to reduce the overhead.

If you want to learn more, you can watch Jon's talk, or browse his slides.

In the end

We'd like to thank the organizers and INRIA for hosting this event here in Paris. It was a great occasion to hear the latest updates from the vibrant OCaml community in the French capital, and to meet and discuss with its members in person. We'd love to see this turn into a yearly recurring event, at least when ICFP's hosted in distant lands.



Au sujet d'OCamlPro :

OCamlPro développe des applications à haute valeur ajoutée depuis plus de 10 ans, en utilisant les langages les plus avancés, tels que OCaml, Rust, et WebAssembly (Wasm) visant aussi bien rapidité de développement que robustesse, et en ciblant les domaines les plus exigeants (méthodes formelles, cybersécurité, systèmes distribués/blockchain, conception de DSLs). Fort de plus de 20 ingénieurs R&D, avec une expertise unique sur les langages de programmation, aussi bien théorique (plus de 80% de nos ingénieurs ont une thèse en informatique) que pratique (participation active au développement de plusieurs compilateurs open-source, prototypage de la blockchain Tezos, etc.), diversifiée (OCaml, Rust, Cobol, Python, Scilab, C/C++, etc.) et appliquée à de multiples domaines. Nous dispensons également des [formations sur mesure certifiées Qualiopi sur OCaml, Rust, et les méthodes formelles] (https://training.ocamlpro.com/) Pour nous contacter : contact@ocamlpro.com.