OCaml 5.5.0 released - Ecosystem - OCaml
= 40rem)" rel="stylesheet" data-target="desktop" />
= 40rem)" rel="stylesheet" data-target="chat_desktop" /><br>= 40rem)" rel="stylesheet" data-target="discourse-ai_desktop" /><br>= 40rem)" rel="stylesheet" data-target="discourse-calendar_desktop" /><br>= 40rem)" rel="stylesheet" data-target="poll_desktop" />
OCaml 5.5.0 released
Ecosystem
compiler,<br>announce
octachron
June 19, 2026, 9:35pm
We have the pleasure of celebrating the birthday of Blaise Pascal by announcing the release of OCaml version 5.5.0.
Some of the highlights in OCaml 5.5.0 are:
Module-dependent Functions
Modules can now be used as function arguments in a form of lightweight functors.
For instance, we can define a function for printing a map generated by
the Map.Make functor:
let pp_map (module M: Map.S) pp_key pp_v ppf set =<br>if M.is_empty set then<br>Format.fprintf ppf "ø"<br>else<br>let pp_sep ppf () = Format.fprintf ppf ",@ " in<br>let pp_binding ppf (k,v) =<br>Format.fprintf ppf "@[%a@ =@ %a@]" pp_key k pp_v v<br>in<br>Format.fprintf ppf "@[{@ %a@ }@]"<br>(Format.pp_print_seq ~pp_sep pp_binding) (M.to_seq set)
We can then apply this function on a string map
module String_map = Map.Make(String)
with
let () =<br>let m = String_map.of_list ["Zero", "Zero"; "One", "Un"] in<br>let pp_str = Format.pp_print_string in<br>Format.printf "%a@."<br>(pp_map (module String_map) pp_str pp_str) m
Compared to first-class modules, the type of the function pp_map
type 'a printer = Format.formatter -> 'a -> unit<br>val pp_map: (module M: Map.S) -> M.key printer -> 'a printer -> 'a M.t printer
is dependent over the value of the module S, and thus the function can only
applied over a statically known module:
let f (): (module Map.S) =<br>if Random.bool () then<br>(module Map.Make(Int))<br>else<br>(module Map.Make(Float))<br>let fail = pp_map (f ())
Error: This expression has type<br>(module M : Map.S) -><br>(Format.formatter -> M.key -> unit) -><br>(Format.formatter -> 'a -> unit) -> Format.formatter -> 'a M.t -> unit<br>but an expression was expected of type (module Map.S) -> 'b<br>The module M would escape its scope<br>This function is module-dependent. The dependency is preserved<br>when the function is passed a static module argument (module M : S)<br>or (module M). Its argument here is not static, so the type-checker<br>tried instead to change the function type to be non-dependent.
Relocatable Compiler
A compiler installation can now be moved or copied with no risk
of hard-to-debug errors due to mixing incompatible bytecode runtime interpreters.
In practice, this means that creating a local switch when there is a
global switch with the same compiler version and configuration
available can be done by cloning the global switch rather than
recompiling the whole compiler.
This should considerably reduce the time required to create
new local opam switches out-of-the-box.
Polymorphic Functions as Function Arguments
Higher-rank polymorphic functions can now be defined directly by
using an explicit type annotation in a function argument
let apply_map (map: 'a 'b. ('a -> 'b) -> 'a list -> 'b list) =<br>map string_of_int [1;2;3], map List.singleton ["x"; "y"]<br>let _ = apply_map List.map
Previously defining such a function required going through either a record or an object
with a polymorphic field or methods
type map = { map: 'a 'b. ('a -> 'b) -> 'a list -> 'b list }<br>let apply_map {map} =<br>map string_of_int [1;2;3], map List.singleton ["x"; "y"]
Search and Replace Substring Functions
The String module has been extended with many functions
for searching and replacing substrings inside a string.
let _true = String.includes ~affix:"aba" "abbaba"<br>let sentence = String.replace_all ~sub:"𝄽" ~by:"word" "A 𝄽 is re𝄽ed"
The substring search is using the 2-way string matching algorithm
which has the advantage of requiring constant space memory overhead
independently of the needle size.
Generalised Local Definitions
It is now always possible to define locally a type,
a class, a module type or any kind of item that can be defined
globally:
let mandelbrot n x =<br>let type t = Converge | Escape of int in<br>...<br>match orbit n x with<br>| Converge -> 0<br>| Exit_at n -> colorize n
External Types
When interfacing with foreign function libraries, it is now possible
to define external type
type int_gmp = external "mpz_t"<br>type float_gmp = external "mpf_t"
Compared to an abstract type definition, the external type name
“mpz_t” (resp. mpf_t) makes the type distinguishable from any
non-abstract types or external types with a different name.
In particular, this makes FFI types better behaved when combined with
Generalised Abstract Data Types (GADTs). For instance, The typechecker
is able to prove that
let ok: (int_gmp,[` A] ) Type.eq -> _ = function _ -> .
is a total function because the external type int_gmp is not compatible
with a polymorphic variant type.
Warning: Abstract types in the current module
The astute reader has probably noticed in the definition above that,
in...