From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Authentication-Results: plum.tunbury.org; dkim=pass (1024-bit key; unprotected) header.d=inria.fr header.i=@inria.fr header.a=rsa-sha256 header.s=dc header.b=XDNlO2bz; dkim-atps=neutral Received-SPF: Permerror (mailfrom) identity=mailfrom; client-ip=192.134.164.83; helo=mail2-relais-roc.national.inria.fr; envelope-from=caml-list-owner@inria.fr; receiver=tunbury.org Received: from mail2-relais-roc.national.inria.fr (mail2-relais-roc.national.inria.fr [192.134.164.83]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by plum.tunbury.org (Postfix) with ESMTPS id B830F400A0 for ; Tue, 11 Mar 2025 15:00:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=inria.fr; s=dc; h=from:to:date:message-id:mime-version:subject:reply-to: sender:list-id:list-help:list-subscribe:list-unsubscribe: list-post:list-owner:list-archive; bh=0rRdcXE2o+2nNpgtHj5CecIAKJvqAHRBRiShZoRr5uo=; b=XDNlO2bzBaqQ+UiBC9gEiravW7C1WBsLXQoymD9VobHMlNsHHIfWDrGJ dOM0M1ABTXNtSSgabul/RWAT/CyzLOxjPuQ6F/PvuaiSVALtEmPJ0oB0a Btu7Jk5gl4Wafbiq22q9U/6bRwyFuMDSB+RaiyjrTuknwhyKfmZc/RqpU 8=; Authentication-Results: mail2-relais-roc.national.inria.fr; dkim=none (message not signed) header.i=none; spf=TempError smtp.mailfrom=caml-list-owner@inria.fr; spf=None smtp.helo=postmaster@sympa.inria.fr Received-SPF: TempError (mail2-relais-roc.national.inria.fr: domain of caml-list-owner@inria.fr temporarily is not available to assert whether or not 128.93.162.160 is permitted sender) identity=mailfrom; client-ip=128.93.162.160; receiver=mail2-relais-roc.national.inria.fr; envelope-from="caml-list-owner@inria.fr"; x-sender="caml-list-owner@inria.fr"; x-conformance=spf_only; x-record-type="v=spf1"; x-record-text="v=spf1 include:mailout.safebrands.com a:basic-mail.safebrands.com a:basic-mail01.safebrands.com a:basic-mail02.safebrands.com ip4:128.93.142.0/24 ip4:192.134.164.0/24 ip4:128.93.162.160 ip4:128.93.162.3 ip4:128.93.162.88 ip4:89.107.174.7 mx ~all" Received-SPF: None (mail2-relais-roc.national.inria.fr: no sender authenticity information available from domain of postmaster@sympa.inria.fr) identity=helo; client-ip=128.93.162.160; receiver=mail2-relais-roc.national.inria.fr; envelope-from="caml-list-owner@inria.fr"; x-sender="postmaster@sympa.inria.fr"; x-conformance=spf_only X-IronPort-AV: E=Sophos;i="6.14,239,1736809200"; d="scan'208,217";a="212350482" Received: from prod-listesu18.inria.fr (HELO sympa.inria.fr) ([128.93.162.160]) by mail2-relais-roc.national.inria.fr with ESMTP; 11 Mar 2025 16:00:37 +0100 Received: by sympa.inria.fr (Postfix, from userid 20132) id E8B60E0D21; Tue, 11 Mar 2025 16:00:35 +0100 (CET) Received: from mail2-relais-roc.national.inria.fr (mail2-relais-roc.national.inria.fr [192.134.164.83]) by sympa.inria.fr (Postfix) with ESMTPS id 5A7D9E0260 for ; Tue, 11 Mar 2025 16:00:32 +0100 (CET) X-IronPort-AV: E=Sophos;i="6.14,239,1736809200"; d="scan'208,217";a="212350431" Received: from mac-03220211.irisa.fr ([131.254.21.249]) by mail2-relais-roc.national.inria.fr with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 11 Mar 2025 16:00:32 +0100 From: Alan Schmitt To: "lwn" , caml-list@inria.fr Date: Tue, 11 Mar 2025 16:00:31 +0100 Message-ID: MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="=-=-=" Subject: [Caml-list] Attn: Development Editor, Latest OCaml Weekly News Reply-To: Alan Schmitt X-Loop: caml-list@inria.fr X-Sequence: 19278 Errors-To: caml-list-owner@inria.fr Precedence: list Precedence: bulk Sender: caml-list-request@inria.fr X-no-archive: yes List-Id: List-Help: List-Subscribe: List-Unsubscribe: List-Post: List-Owner: List-Archive: Archived-At: --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Hello Here is the latest OCaml Weekly News, for the week of March 04 to 11, 2025. Table of Contents =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80 OCaml projects utilizing Category theory Docker base images and OCaml-CI support for OCaml < 4.08 ocamlmig, a tool to rewrite ocaml code, and complement `[@@deprecated]' Ortac 0.6.0 improve bug reporting Dune Developer Preview Updates ppxlib.0.36.0 I created an OCaml grammar for ANTLR4 (Earley parser compatible) Melange 5.0 Other OCaml News Old CWN OCaml projects utilizing Category theory =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2= =95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95= =90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90= =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2= =95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90 Archive: Deep in this thread, Dmitrii Kovanikov announced =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80 I started writing [a series of articles about Pragmatic Category Theory] in OCaml, and there's a repository with examples: =E2=80=A2 If you're interested in a complete project, I made *CCL: Categorical Configuration Language* which leverages multiple Category Theory concepts: =E2=80=A2 [The Most Elegant Configuration Language by @chshersh] I'm currently working on a [GitHub TUI] project in OCaml but the usage of CT concepts is not that crazy there. For now, I only use Semigroup and Monoids (which some people don't even consider part of CT but just Abstract Algebra). [a series of articles about Pragmatic Category Theory] [The Most Elegant Configuration Language by @chshersh] [GitHub TUI] Docker base images and OCaml-CI support for OCaml < 4.08 =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2= =95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95= =90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90= =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2= =95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95= =90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90= =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90 Archive: Mark Elvers announced =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80 The [opam repository archival] process has set the minimum supported OCaml version to 4.08 _for opam repository_. It logically follows that opam-repo-ci should only test against OCaml >=3D 4.08. The purpose of this post is to get a sense of whether the rest of the OCaml infrastructure should also adopt the same lower bound. The current lower bound is 4.02. Specific examples include OCaml-CI. Individual projects can already opt out of testing on older platforms by adding a lower bound in the opam file. Docker base images are built for all versions of OCaml used in the CI systems. These images are published weekly on Docker Hub. We know that these images are also used by the community, but the pull counter is not broken down by individual tag. Potentially only the latest OCaml versions are being used. Users impacted by packages which have been archived from opam repository can easily restore the packages by adding the archive repository to the opam switch. This only needs to be done once. Users can build their own Docker base images, but they would need to be rebuilt periodically to keep them up to date. Would removing testing on < 4.08 in OCaml CI or removing the Docker base images < 4.08 impact you? [opam repository archival] ocamlmig, a tool to rewrite ocaml code, and complement `[@@deprecated]' =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2= =95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95= =90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90= =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2= =95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95= =90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90= =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2= =95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95= =90=E2=95=90=E2=95=90=E2=95=90=E2=95=90 Archive: v-gb announced =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80 Hi, I released a new version of ocamlmig in opam, whose main change is to avoid reformatting everything in codebases that don't use ocamlformat. Instead, only subexpressions touched by a rewrite are reformatted. It also requalifies identifier in more places to preserve their meaning (e.g. when replacing `string_of_int' by `Int.to_string', there might be an `Int' module in scope that's not `Stdlib.Int'. In such case, ocamlmig would more often replace `string_of_int' by `Stdlib.Int.to_string'). Separately, I've thought about the recent addition of let+ operators in Cmdliner, and how one might migrate from the use of `$' to them. Concretetely, given: =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =E2=94=82 let bistro () (`Dry_run dry_run) (`Package_names pkg_names) ...= =3D the code =E2=94=82 open Cmdliner =E2=94=82 let term =3D Term.(const bistro $ Cli.setup $ Cli.dry_run $ ...) =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80 you'd want to have instead: =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =E2=94=82 open Cmdliner =E2=94=82 let term =3D =E2=94=82 Term.(Syntax.( =E2=94=82 let+ () =3D Cli.setup =E2=94=82 and+ (`Dry_run dry_run) =3D Cli.dry_run =E2=94=82 and+ (`Package_names pkg_names) =3D ... =E2=94=82 ... =E2=94=82 in =E2=94=82 the code)) =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80 ocamlmig can now transform code this way, at the tip of the ocamlmig repo (not the last release). You can see it [in the second commit in this branch] (and further mechanical cleanups in the commits with "=E2=80= =A6" bubbles), but to explain a bit: =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =E2=94=82 let bistro () (`Dry_run dry_run) (`Package_names pkg_names) ...= =3D the code =E2=94=82 open Cmdliner =E2=94=82 let term =3D Term.(const bistro $ Cli.setup $ Cli.dry_run $ ...) =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80 is first turned into: =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =E2=94=82 open Cmdliner =E2=94=82 let term =3D Term.(const (fun () (`Dry_run dry_run) (`Package_n= ames pkg_names) ... -> the code) =E2=94=82 $ Cli.setup $ Cli.dry_run $ ...) =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80 which is then turned into the final code: =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =E2=94=82 open Cmdliner =E2=94=82 let term =3D =E2=94=82 Term.(Syntax.( =E2=94=82 let+ () =3D Cli.setup =E2=94=82 and+ (`Dry_run dry_run) =3D Cli.dry_run =E2=94=82 and+ (`Package_names pkg_names) =3D ... =E2=94=82 ... =E2=94=82 in =E2=94=82 the code)) =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80 The first step is done using `ocamlmig replace -w -e 'const [%move_def __f] /// const __f''. In short, what this does is anytime it sees `const some-identifier', it tries to inline the definition of the identifier. In details, the left side of the `///' specifies the code to search for, and the right side what to replace it with. `const ...' searches for literally `const' applied to one argument. `[%move_def __f]' is trickier: it matches identifiers that are let-bound somewhere in the current file, removes said let binding, and recursively matches the right hand side of the binding against `__f'. Variables that start with two underscores name a term for use in the replacement expression. The second step is done with: =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =E2=94=82 ocamlmig replace -w \ =E2=94=82 -e 'const (fun __p1 __p2 __p3 -> __body) $ __e1 $ __e2 $ __e3 =E2=94=82 /// let open Syntax in let+ __p1 =3D __e1 and+ __p2 =3D _= _e2 and+ __p3 =3D __e3 in __body' =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80 This is longer, but given the previous explanation, it's hopefully fairly clear what this does. The only twist is that ocamlmig generalizes this search/replace for three elements into an n-ary version (implicitly, although perhaps it should be explicit). And that's it. So this is the full command that I used: =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =E2=94=82 ocamlmig replace -w \ =E2=94=82 -e 'const [%move_def __f] /// const __f' \ =E2=94=82 -e 'const (fun __p1 __p2 __p3 -> __body) $ __e1 $ __e2 $ __e3 =E2=94=82 /// let open Syntax in let+ __p1 =3D __e1 and+ __p2 =3D _= _e2 and+ __p3 =3D __e3 in __body' =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80 which seems pretty reasonable considering the rewrite is somewhat sophisticated. In general, mechanizing a change can reduce the chance of accidentally modifying something, but in this specific case, ocamlmig also detects shadowing when moving code with `[%move_def]'. Shadowing would likely cause type errors or tests errors, but if it didn't, it'd be quite hard to catch during code review. Finally, if you want to try this out on your code, I'll note that `ocamlmig replace' is in flux, and that while the commands above work, obvious variations of them may not. [in the second commit in this branch] Ortac 0.6.0 improve bug reporting =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2= =95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95= =90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90= =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90 Archive: Nicolas Osborne announced =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80 Hi everyone! We - at Tarides - are very pleased to announce the release of the Ortac-0.6.0 packages for specification-driven testing! Ortac/QCheck-STM is a test generator based on the [QCheck-STM] model-based testing framework and the [Gospel] specification language for OCaml. In addition to generating QCheck-STM tests based on the Gospel specifications, `Ortac/QCheck-STM' computes and display a bug report in case of test failure. This report contains the piece of Gospel specification that has been violated, a runnable scenario to reproduce the bug and the expected returned value (if there is enough information in the specification to compute it). This release improves the reporting in two ways. First, the way we need to formulate the description of the expected returned value has been made more flexible (and fixed). The main limitation was about functions returning a boolean. Because of the coercion mechanism, Gospel often transforms equalities involving a boolean into a double implication. For example: `b =3D Sequence.mem t.contents a' is transformed into `b =3D true <-> Sequence.mem t.contents a'. (For the curious, this is because `Sequence.mem' returns a `prop', not a `bool', and we don't have equality on `prop'). `Ortac/QCheck-STM' now explores more patterns, including the double implication one, to try to find a suitable description of the returned value to use in the bug report. Secondly, and more importantly, the Gospel specification language supports partial functions (`Sequence.hd' is *not* defined on the empty sequence for example). When we translate calls to such function to OCaml, we raise an exception when the call is out of the function's domain. Now, that exception was captured by QCheck at runtime, making the test a failure as expected. But the Ortac runtime was then stopped before being able to build and send the bug report to QCheck for display to the user. That was sad, so I've fixed it. We can now make use of Gospel partial functions when writing specifications and enjoy the bug report computed by `Ortac/QCheck-STM'! You can install Ortac/QCheck-STM via opam (we also advise installing and using Ortac/Dune): =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =E2=94=82 $ opam install ortac-qcheck-stm ortac-dune =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80 You'll find more information in [Ortac/QCheck-STM documentation] and in The [Ortac/Dune readme]. If you have any questions, please don't hesitate to ping me :-) Next release should be about making Ortac/QCheck-STM generate tests of a library in a parallel context (this is, after all, one of the *raison d'=C3=AAtre* of the fantastic QCheck-STM test framework!). Happy testing! [QCheck-STM] [Gospel] [Ortac/QCheck-STM documentation] [Ortac/Dune readme] Dune Developer Preview Updates =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2= =95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95= =90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90= =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90 Archive: Leandro Ostera announced =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80 Hello everyone! :waving_hand: Hope you had a great end of 2024 and your 2025 is starting well too :D We've been hard at work at Tarides to improve the Dune Developer Preview, and we'd love to learn more about what your adoption hurdles have been, so here's a very short form you can fill to let us know what's up. Happy hacking! :two_hump_camel: ppxlib.0.36.0 =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2= =95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90 Archive: Patrick Ferris announced =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80 The ppxlib team is happy to announce the release of `ppxlib.0.36.0'! A full account of the changes can be found [on the 0.36.0 release]. [on the 0.36.0 release] OCaml 5.2 Internal AST =E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2= =95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95= =8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C The main change in this release is that the internal AST used in ppxlib is now the same as OCaml 5.2's AST. Previously it was 4.14.0. The internal AST dictates what features your ppx can and cannot generate. To avoid confusion, this does _not_ mean ppxlib only supports OCaml 5.2 and greater. Ppxlib still supports compilers starting at 4.08.0. *The bump to 5.2 has caused a lot of reverse dependencies to break* as the 5.2 AST represents functions differently ([see the Syntactic Function Arity RFC]). Many patches have already been sent to users of ppxlib in the past few months, but quite a few still remain. :warning: Ppx authors are advised to read [the wiki entry for upgrading to ppxlib.0.36.0]. :warning: Please do not hesitate to reach out if you need any help upgrading to `ppxlib.0.36.0'. [see the Syntactic Function Arity RFC] [the wiki entry for upgrading to ppxlib.0.36.0] Other Changes =E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2= =95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C =E2=80=A2 Change `Location.none' to match the compiler's `Location.none' = as of OCaml 4.08. =E2=80=A2 New ways to create context free rules using floating expansions= =E2=80=93 see [#560] for the details. =E2=80=A2 Add a `-raise-embedded-errors' flag to the driver. Setting this= flag raises the first `ocaml.error' embedded in the final AST. =E2=80=A2 Export `Ast_pattern.fail' making it easier to write new pattern-matchers. =E2=80=A2 Improvements to `Ast_traverse.sexp_of' to be more concise. Do read the changes entry/release for all of the acknowledgments =E2=80=93 thank you to everyone who contributed to this release of ppxlib! A special thanks from me to @NathanReb who has been a massive help getting this work over the line. Thank you to Tarides and Jane Street for funding my time on this release of ppxlib. [#560] I created an OCaml grammar for ANTLR4 (Earley parser compatible) =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2= =95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95= =90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90= =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2= =95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95= =90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90= =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2= =95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90 Archive: ao wang announced =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80 Hi everyone, I=E2=80=99ve created an ANTLR4 grammar for OCaml that supports Earley par= sing. Feel free to use it, and any feedback or contributions are welcome! GitHub Repository: Melange 5.0 =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2= =95=90=E2=95=90=E2=95=90 Archive: Antonio Nuno Monteiro announced =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80 Dear OCaml users, I'm proud to announce the release of Melange 5.0 Melange is a backend for the OCaml compiler that emits JavaScript. This release features improvements across a few areas, mostly targeting OCaml 5.3 support and JavaScript expressivity: =E2=80=A2 OCaml version support: we=E2=80=99re releasing Melange 5 with f= ull support across a few OCaml versions: 4.14, 5.1, 5.2 and the recently released 5.3 =E2=80=A3 Melange uses a versioning scheme similar to Merlin=E2=80=99s:= releases are suffixed with the OCaml version they support, e.g. 5.0.1-414, 5.0.1-53, etc. =E2=80=A2 We're introducing build system-aware, type-safe support for JavaScript's [dynamic import], allowing to code split Melange-generated JavaScript bundles without sacrificing type-safety. =E2=80=A2 Melange can now express [discriminated unions], a JavaScript pa= ttern that The [release announcement] blog post covers the changes in a lot more detail. Please give it a read. I'm excited to count on the support of our financial sponsors [Ahrefs] and the [OCaml Software Foundation], without which this release would not have been possible. [dynamic import] [discriminated unions] [release announcement] [Ahrefs] [OCaml Software Foundation] Other OCaml News =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2= =95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90 >From the ocaml.org blog =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80 Here are links from many OCaml blogs aggregated at [the ocaml.org blog]. =E2=80=A2 [OpenAI and structured outputs from OCaml] =E2=80=A2 [Feature Parity Series: Statmemprof Returns!] =E2=80=A2 [Announcing Melange 5] =E2=80=A2 [Learning OCaml: Functions without Parameters] [the ocaml.org blog] [OpenAI and structured outputs from OCaml] [Feature Parity Series: Statmemprof Returns!] [Announcing Melange 5] [Learning OCaml: Functions without Parameters] Old CWN =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90 If you happen to miss a CWN, you can [send me a message] and I'll mail it to you, or go take a look at [the archive] or the [RSS feed of the archives]. If you also wish to receive it every week by mail, you may subscribe to the [caml-list]. [Alan Schmitt] [send me a message] [the archive] [RSS feed of the archives] [caml-list] [Alan Schmitt] --=-=-= Content-Type: text/html; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable OCaml Weekly News

OCaml Weekly News

Previous Week<= /a> Up Next Week

Hello

Here is the latest OCaml Weekly News, for the week of March 04 to 11, 2025.

OCaml projects utilizing Category theory

Deep in this thread, Dmitrii Kovanikov announced

I started writing a series of articles about Pragmatic Categor= y Theory in OCaml, and there's a repository with examples:

If you're interested in a complete project, I made CCL: Categorical Conf= iguration Language which leverages multiple Category Theory concepts:

I'm currently working on a GitHub TUI project in OCaml but the usage of CT concepts is not that= crazy there. For now, I only use Semigroup and Monoids (which some people = don't even consider part of CT but just Abstract Algebra).

Docker base images and OCaml-CI support for OCaml < 4.08

Mark Elvers announced

The opam repository archival process = has set the minimum supported OCaml version to 4.08 for opam repository. It logically follows that opam-repo-ci shou= ld only test against OCaml >=3D 4.08.

The purpose of this post is to get a sense of whether the rest of the OCaml= infrastructure should also adopt the same lower bound. The current lower = bound is 4.02.

Specific examples include OCaml-CI. Individual projects can already opt ou= t of testing on older platforms by adding a lower bound in the opam file.

Docker base images are built for all versions of OCaml used in the CI syste= ms. These images are published weekly on Docker Hub. We know that these im= ages are also used by the community, but the pull counter is not broken dow= n by individual tag. Potentially only the latest OCaml versions are being = used.

Users impacted by packages which have been archived from opam repository ca= n easily restore the packages by adding the archive repository to the opam = switch. This only needs to be done once. Users can build their own Docker= base images, but they would need to be rebuilt periodically to keep them u= p to date.

Would removing testing on < 4.08 in OCaml CI or removing the Docker base= images < 4.08 impact you?

ocamlmig, a tool to rewrite ocaml code, and complement [= @@deprecated]

v-gb announced

Hi,

I released a new version of ocamlmig in opam, whose main change is to avoid= reformatting everything in codebases that don't use ocamlformat. Instead, = only subexpressions touched by a rewrite are reformatted. It also requalifies identifier in more places to preserve their meaning (e.= g. when replacing string_of_int by Int.to_string,= there might be an Int module in scope that's not Stdlib= .Int. In such case, ocamlmig would more often replace string_o= f_int by Stdlib.Int.to_string).

Separately, I've thought about the recent addition of let+ operators in Cmd= liner, and how one might migrate from the use of $ to them. Co= ncretetely, given:

let bistro () (`Dry_run dry_run) (`Package_names pkg_names) ... =3D the code
open Cmdliner
let term =3D Term.<=
/span>(const bistro $ Cli.setup $=
 Cli.dry_run $ ...)

you'd want to have instead:

open Cmdliner
let term =3D
  Term.(Syntax.(
    let+ () =3D <=
span style=3D"color: #444fcf;">Cli.setup
    and+ (`Dry_run dry_run) =3D and+ (`Package_names <=
span style=3D"color: #007a9f;">pkg_names) =3D ...
    ...
    in
    the code))

ocamlmig can now transform code this way, at the tip of the ocamlmig repo (= not the last release). You can see it in the second commit in this branch (an= d further mechanical cleanups in the commits with "…" bubbles), but = to explain a bit:

let bistro () (`Dry_run dry_run) (`Package_names pkg_names) ... =3D the code
open Cmdliner
let term =3D Term.<=
/span>(const bistro $ Cli.setup $=
 Cli.dry_run $ ...)

is first turned into:

open Cmdliner
let term =3D Term.<=
/span>(const (fun=
 () (`Dry_run dry_run) (`Package_names pkg_names) ... -> the code)
                 $ Cli.setup $ Cli.dry_run $ ...)

which is then turned into the final code:

open Cmdliner
let term =3D
  Term.(Syntax.(
    let+ () =3D <=
span style=3D"color: #444fcf;">Cli.setup
    and+ (`Dry_run dry_run) =3D and+ (`Package_names <=
span style=3D"color: #007a9f;">pkg_names) =3D ...
    ...
    in
    the code))

The first step is done using ocamlmig replace -w -e 'const [%move_def= __f] /// const __f'. In short, what this does is anytime it sees const some-identifier, it tries to inline the definition of the = identifier. In details, the left side of the /// specifies the= code to search for, and the right side what to replace it with. cons= t ... searches for literally const applied to one argum= ent. [%move_def __f] is trickier: it matches identifiers that = are let-bound somewhere in the current file, removes said let binding, and = recursively matches the right hand side of the binding against __f. Variables that start with two underscores name a term for use in the = replacement expression.

The second step is done with:

ocamlmig replace -w \
  -e 'const (fun __p1 __p2 __p3 -> __bod=
y) $ __e1 $ __e2 $ __e3
      /// let open Syntax in let+ __p1 =3D =
__e1 and+ __p2 =3D __e2 and+ __p3 =3D __e3 in __body'

This is longer, but given the previous explanation, it's hopefully fairly c= lear what this does. The only twist is that ocamlmig generalizes this searc= h/replace for three elements into an n-ary version (implicitly, although pe= rhaps it should be explicit).

And that's it. So this is the full command that I used:

ocamlmig replace -w \
  -e 'const [%move_def __f] /// const __f'<=
/span> \
  -e 'const (fun __p1 __p2 __p3 -> __bod=
y) $ __e1 $ __e2 $ __e3
      /// let open Syntax in let+ __p1 =3D =
__e1 and+ __p2 =3D __e2 and+ __p3 =3D __e3 in __body'

which seems pretty reasonable considering the rewrite is somewhat sophistic= ated.

In general, mechanizing a change can reduce the chance of accidentally modi= fying something, but in this specific case, ocamlmig also detects shadowing= when moving code with [%move_def]. Shadowing would likely cau= se type errors or tests errors, but if it didn't, it'd be quite hard to cat= ch during code review.

Finally, if you want to try this out on your code, I'll note that oca= mlmig replace is in flux, and that while the commands above work, ob= vious variations of them may not.

Ortac 0.6.0 improve bug reporting

Nicolas Osborne announced

Hi everyone!

We - at Tarides - are very pleased to announce the release of the Ortac-0.6= .0 packages for specification-driven testing!

Ortac/QCheck-STM is a test generator based on the QCheck-STM model-based testing fra= mework and the Gospel specification language for OCaml.

In addition to generating QCheck-STM tests based on the Gospel specificatio= ns, Ortac/QCheck-STM computes and display a bug report in case= of test failure.

This report contains the piece of Gospel specification that has been violat= ed, a runnable scenario to reproduce the bug and the expected returned valu= e (if there is enough information in the specification to compute it).

This release improves the reporting in two ways.

First, the way we need to formulate the description of the expected returne= d value has been made more flexible (and fixed). The main limitation was ab= out functions returning a boolean. Because of the coercion mechanism, Gospe= l often transforms equalities involving a boolean into a double implication= . For example: b =3D Sequence.mem t.contents a is transformed = into b =3D true <-> Sequence.mem t.contents a. (For the = curious, this is because Sequence.mem returns a prop, not a bool, and we don't have equality on prop). Ortac/QCheck-STM now explores more patterns, including th= e double implication one, to try to find a suitable description of the retu= rned value to use in the bug report.

Secondly, and more importantly, the Gospel specification language supports = partial functions (Sequence.hd is not defined on the em= pty sequence for example). When we translate calls to such function to OCam= l, we raise an exception when the call is out of the function's domain. Now= , that exception was captured by QCheck at runtime, making the test a failu= re as expected. But the Ortac runtime was then stopped before being able to= build and send the bug report to QCheck for display to the user. That was = sad, so I've fixed it. We can now make use of Gospel partial functions when= writing specifications and enjoy the bug report computed by Ortac/QC= heck-STM!

You can install Ortac/QCheck-STM via opam (we also advise installing and us= ing Ortac/Dune):

$ opam install ortac-qcheck-stm ortac-dune

You'll find more information in Ortac/QCheck-STM documentation and in= The Ortac/Dune readme.

If you have any questions, please don't hesitate to ping me :-)

Next release should be about making Ortac/QCheck-STM generate tests of a li= brary in a parallel context (this is, after all, one of the raison d'=C3= =AAtre of the fantastic QCheck-STM test framework!).

Happy testing!

Dune Developer Preview Updates

Leandro Ostera announced

Hello everyone! :waving_hand: Hope you had a great end of 2024 and your 202= 5 is starting well too :D=20

We've been hard at work at Tarides to improve the Dune Developer Preview, a= nd we'd love to learn more about what your adoption hurdles have been, so h= ere's a very short form you can fill to let us know what's up.

Happy hacking! :two_hump_camel:=20

https://forms.gle/piaw12XBY= UeaCmg56

ppxlib.0.36.0

Patrick Ferris announced

The ppxlib team is happy to announce the release of ppxlib.0.36.0!=20

A full account of the changes can be found on the 0.36.0 release.

OCaml 5.2 Internal AST

The main change in this release is that the internal AST used in ppxlib is = now the same as OCaml 5.2's AST. Previously it was 4.14.0. The internal AST= dictates what features your ppx can and cannot generate. To avoid confusio= n, this does not mean ppxlib only supports= OCaml 5.2 and greater. Ppxlib still supports compilers starting at 4.08.0.

The bump to 5.2 has caused a lot of reverse dependencies to break as= the 5.2 AST represents functions differently (see the Syntactic Function Arity RFC). Many patch= es have already been sent to users of ppxlib in the past few months, but qu= ite a few still remain.=20

:warning: Ppx authors are advised to read the wiki entry for upgrading= to ppxlib.0.36.0. :warning:=20

Please do not hesitate to reach out if you need any help upgrading to ppxlib.0.36.0.

Other Changes

  • Change Location.none to match the compiler's Locatio= n.none as of OCaml 4.08.
  • New ways to create context free rules using floating expansions –= ; see #560 for= the details.
  • Add a -raise-embedded-errors flag to the driver. Setting t= his flag raises the first ocaml.error embedded in the final AS= T.
  • Export Ast_pattern.fail making it easier to write new patt= ern-matchers.
  • Improvements to Ast_traverse.sexp_of to be more concise.

Do read the changes entry/release for all of the acknowledgments – t= hank you to everyone who contributed to this release of ppxlib! A special t= hanks from me to @NathanReb who has been a massive help getting this work o= ver the line.

Thank you to Tarides and Jane Street for funding my time on this release of= ppxlib.

I created an OCaml grammar for ANTLR4 (Earley parser compatibl= e)

ao wang announced

Hi everyone,

I=E2=80=99ve created an ANTLR4 grammar for OCaml that supports Earley parsi= ng.=20=20 Feel free to use it, and any feedback or contributions are welcome!

GitHub Repository: https://github.com/WangAo0311/Antlr4-ocaml-earley-parser-grammar

Melange 5.0

Antonio Nuno Monteiro announced

Dear OCaml users,

I'm proud to announce the release of Melange 5.0

Melange is a backend for the OCaml compiler that emits JavaScript. This rel= ease features improvements across a few areas, mostly targeting OCaml 5.3 s= upport and JavaScript expressivity:

  • OCaml version support: we=E2=80=99re releasing Melange 5 with full supp= ort across a few OCaml versions: 4.14, 5.1, 5.2 and the recently released 5= .3
    • Melange uses a versioning scheme similar to Merlin=E2=80=99s: releases = are suffixed with the OCaml version they support, e.g. 5.0.1-414, 5.0.1-53,= etc.
  • We're introducing build system-aware, type-safe support for JavaScript'= s dynamic import, allowing to code split Melange-ge= nerated JavaScript bundles without sacrificing type-safety.
  • Melange can now express discrimina= ted unions, a JavaScript pattern that

The release = announcement blog post covers the changes in a lot more detail. Please = give it a read.

I'm excited to count on the support of our financial sponsors Ahrefs and the OCaml Software Foundation, without which this release would not have b= een possible.

Old CWN

If you happen to miss a CWN, you can send me a message and I'll mail it to you, or go take a loo= k at the archive or the <= a href=3D"https://alan.petitepomme.net/cwn/cwn.rss">RSS feed of the archive= s.

If you also wish to receive it every week by mail, you may subscribe to the= caml-list.

--=-=-=--