https://ocaml.org/feed.xmlThe OCaml Planet2024-03-13T00:00:00-00:00<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2024-03-13-my-experience-at-indiafoss-2023-community-workshop-and-talksMy experience at IndiaFOSS 2023: Community, Workshop, and Talks2024-03-13T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2024.03.12.htmlOCaml Weekly News, 12 Mar 20242024-03-12T12:00:00-00:00Caml Weekly News<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
https://ocamlpro.com/blog/2024_03_07_lean4_when_sound_programs_become_a_choiceLean 4: When Sound Programs become a Choice2024-03-07T10:00:20-00:00
Adrien Champion
<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2024-03-07-a-time-for-change-our-response-to-the-white-house-cybersecurity-press-releaseA Time for Change: Our Response to the White House Cybersecurity Press Release2024-03-07T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2024.03.05.htmlOCaml Weekly News, 05 Mar 20242024-03-05T12:00:00-00:00Caml Weekly Newshttps://frama-c.com/fc-versions/nickel.htmlRelease of Frama-C 28.1 (Nickel)2024-03-01T00:00:00-00:00Frama-C<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2024-02-28-two-major-improvements-in-odoc-introducing-search-engine-integrationTwo Major Improvements in odoc: Introducing Search Engine Integration2024-02-28T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2024.02.27.htmlOCaml Weekly News, 27 Feb 20242024-02-27T12:00:00-00:00Caml Weekly News<p>Hybrid GUID partition table and tar archive</p>
https://blog.robur.coop/articles/gptar.htmlGPTar2024-02-21T10:00:00-00:00Robur Cooperative<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2024-02-21-my-experience-with-tarides-at-icfp-2023My Experience With Tarides at ICFP 2023!2024-02-21T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2024.02.20.htmlOCaml Weekly News, 20 Feb 20242024-02-20T12:00:00-00:00Caml Weekly News<p>Introducing DBCaml, Database toolkit for OCaml</p>
https://priver.dev/blog/dbcaml/dbcaml/Introducing DBCaml, Database toolkit for OCaml2024-02-20T00:01:38-00:00Emil Privér<p>This article talks about how I wrote the connection pool for DBCaml</p>
https://priver.dev/blog/dbcaml/building-a-connnection-pool/Building a Connnection Pool for DBCaml on top of riot2024-02-19T12:00:23-00:00Emil Privérhttps://frama-c.com/fc-plugins/metacsl.htmlMetAcsl v0.6 for Frama-C 28.0 Nickel2024-02-16T00:00:00-00:00Frama-C<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2024-02-14-multicore-testing-tools-dscheck-pt-1Multicore Testing Tools: DSCheck Pt 12024-02-14T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2024.02.13.htmlOCaml Weekly News, 13 Feb 20242024-02-13T12:00:00-00:00Caml Weekly News<p>How we improved the performance of elliptic curves by only modifying the underlying byte array</p>
https://blog.robur.coop/articles/speeding-ec-string.htmlSpeeding elliptic curve cryptography2024-02-13T10:00:00-00:00Robur Cooperative<p>Introduction for OCaml, a blog post for developers that want to dig into OCaml</p>
https://priver.dev/blog/ocaml/ocaml-introduction/OCaml: Introduction2024-02-12T00:01:38-00:00Emil Privér<p>A disgression about Lwt and Miou</p>
https://blog.robur.coop/articles/lwt_pause.htmlCooperation and Lwt.pause2024-02-11T10:00:00-00:00Robur Cooperative<p>A disgression about Lwt and Miou</p>
https://blog.osau.re/articles/lwt_pause.htmlCooperation and Lwt.pause2024-02-11T10:00:00-00:00Romain Calascibetta<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2024-02-07-improving-ocaml-org-to-provide-an-engaging-ux-and-trusted-user-resourcesImproving OCaml.org to Provide an Engaging UX and Trusted User Resources2024-02-07T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2024.02.06.htmlOCaml Weekly News, 06 Feb 20242024-02-06T12:00:00-00:00Caml Weekly News<!-- CommonMark HTML block omitted -->
https://tech.ahrefs.com/profiling-dune-builds-a8de589ec268?source=rss----303662d88bae--ocamlProfiling Dune Builds2024-02-05T22:05:01-00:00Ahrefs<p>Reimplementing Python string escaping in OCaml</p>
https://blog.robur.coop/articles/2024-02-03-python-str-repr.htmlPython's `str.__repr__()`2024-02-03T10:00:00-00:00Robur Cooperative<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2024-01-31-are-your-programs-doing-what-you-think-they-re-doing-introducing-monitoring-tools-for-multicore-ocamlAre Your Programs Doing What You Think They're Doing? Introducing Monitoring Tools for Multicore OCaml2024-01-31T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2024.01.30.htmlOCaml Weekly News, 30 Jan 20242024-01-30T12:00:00-00:00Caml Weekly News<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
http://math.andrej.com/2024/01/30/space-filling-curves-constructively/Space-filling curves, constructively2024-01-29T23:00:00-00:00Andrej Bauer<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2024-01-24-mirageos-designing-a-more-resilient-networking-stack-with-tcpMirageOS: Designing a More Resilient Networking Stack With µTCP2024-01-24T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<p><><> Fetching repository information ><><><><><><><><><><><><><><><><>
[default] Initialised</p>
<p><><> Required setup - please read <><><><><><><><><><><><><><><><><><></p>
<p>In normal operation, opam only alters files within ~/.opam.</p>
<p>However, to best integrate with your system, some environment
variables should be set. If you allow it to, this initialisation
step will update your bash configuration by adding the following
line to ~/.profile:</p>
<pre><code>test -r ~/.opam/opam-init/init.sh &amp;&amp; . ~/.opam/opam-init/init.sh &gt; /dev/null 2&gt; /dev/null || true
</code></pre>
<p>Otherwise, every time you want to access your opam installation,
you will need to run:</p>
<pre><code>eval $(opam env)
</code></pre>
<p>You can always re-run this setup with 'opam init' later.</p>
<p>Do you want opam to modify ~/.profile? [N/y/f]
(default is 'no', use 'f' to choose a different file) y</p>
<p>User configuration:
Updating ~/.profile.
[NOTE] Make sure that ~/.profile is well sourced in your ~/.bashrc.</p>
<p><><> Creating initial switch 'default' (invariant ["ocaml" {>= "4.05.0"}] - initially with ocaml-base-compiler)</p>
<p><><> Installing new switch packages <><><><><><><><><><><><><><><><><>
Switch invariant: ["ocaml" {>= "4.05.0"}]</p>
<p><><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><>
∗ installed base-bigarray.base
∗ installed base-threads.base
∗ installed base-unix.base
∗ installed ocaml-options-vanilla.1
⬇ retrieved ocaml-base-compiler.5.1.0 (https://opam.ocaml.org/cache)
∗ installed ocaml-base-compiler.5.1.0
∗ installed ocaml-config.3
∗ installed ocaml.5.1.0
∗ installed base-domains.base
∗ installed base-nnp.base
Done.
<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
<p>In normal operation, opam only alters files within ~/.opam.</p>
<p>However, to best integrate with your system, some environment
variables should be set. If you allow it to, this initialisation
step will update your bash configuration by adding the following
line to ~/.profile:</p>
<pre><code>test -r ~/.opam/opam-init/init.sh &amp;&amp; . ~/.opam/opam-init/init.sh &gt; /dev/null 2&gt; /dev/null || true
</code></pre>
<p>Otherwise, every time you want to access your opam installation,
you will need to run:</p>
<pre><code>eval $(opam env)
</code></pre>
<p>You can always re-run this setup with 'opam init' later.</p>
<p>Do you want opam to modify ~/.profile? [N/y/f]
(default is 'no', use 'f' to choose a different file) y</p>
<p>User configuration:
Updating ~/.profile.
[NOTE] Make sure that ~/.profile is well sourced in your ~/.bashrc.</p>
<p><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
<p><><> Installing new switch packages <><><><><><><><><><><><><><><><><>
Switch invariant: ["ocaml" {>= "4.05.0"}]</p>
<p><><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><>
∗ installed base-bigarray.base
∗ installed base-threads.base
∗ installed base-unix.base
∗ installed ocaml-options-vanilla.1
⬇ retrieved ocaml-base-compiler.5.1.0 (https://opam.ocaml.org/cache)
∗ installed ocaml-base-compiler.5.1.0
∗ installed ocaml-config.3
∗ installed ocaml.5.1.0
∗ installed base-domains.base
∗ installed base-nnp.base
Done.
<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
<p><><> Installing new switch packages <><><><><><><><><><><><><><><><><>
Switch invariant: ["ocaml" {>= "4.05.0"}]</p>
<p><><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><>
∗ installed base-bigarray.base
∗ installed base-threads.base
∗ installed base-unix.base
∗ installed ocaml-options-vanilla.1
⬇ retrieved ocaml-base-compiler.5.1.0 (https://opam.ocaml.org/cache)
∗ installed ocaml-base-compiler.5.1.0
∗ installed ocaml-config.3
∗ installed ocaml.5.1.0
∗ installed base-domains.base
∗ installed base-nnp.base
Done.
<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
<p><><> Installing new switch packages <><><><><><><><><><><><><><><><><>
Switch invariant: ["ocaml" {>= "4.05.0"}]</p>
<p><><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><>
∗ installed base-bigarray.base
∗ installed base-threads.base
∗ installed base-unix.base
∗ installed ocaml-system.4.14.1
∗ installed ocaml-config.2
∗ installed ocaml.4.14.1
Done.
$ opam switch</p>
<h1>switch compiler description</h1>
<p>→ /home/ocp/my-project ocaml.4.14.1 /home/ocp/my-project
default ocaml.5.1.0 default
my-switch ocaml.4.13.1 my-switch</p>
<p>[NOTE] Current switch has been selected based on the current directory.
The current global system switch is default.
<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
https://ocamlpro.com/blog/2024_01_23_opam_101_the_first_stepsopam 101: the first steps2024-01-23T14:15:10-00:00
Dario Pinto
<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2024.01.23.htmlOCaml Weekly News, 23 Jan 20242024-01-23T12:00:00-00:00Caml Weekly Newshttps://idaranabuk.com/blog/ocaml_communityThe OCaml Community2024-01-21T00:00:00-00:00Idarahttps://idaranabuk.com/blog/everyone_strugglesOutreachy Blog: Everyone Struggles2024-01-21T00:00:00-00:00Idara<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2024-01-17-what-are-data-races-and-do-they-threaten-your-businessWhat are Data Races? And do They Threaten Your Business?2024-01-17T00:00:00-00:00Tarides<p>This post explores the concepts of functional programming, including immutability, pure functions, higher-order functions, recursion, and more. It also delves into the history of functional programming and introduces Lambda Calculus. If you're new to functional programming or want to deepen your understanding, this post is for you.</p>
https://priver.dev/blog/functional-programming/concepts-of-functional-programming/Concepts of Functional Programming2024-01-16T20:01:38-00:00Emil Privér<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2024.01.16.htmlOCaml Weekly News, 16 Jan 20242024-01-16T12:00:00-00:00Caml Weekly News<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2024-01-10-meet-odoc-ocaml-s-documentation-generatorMeet odoc, OCaml's Documentation Generator2024-01-10T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2024.01.09.htmlOCaml Weekly News, 09 Jan 20242024-01-09T12:00:00-00:00Caml Weekly News<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2024.01.02.htmlOCaml Weekly News, 02 Jan 20242024-01-02T12:00:00-00:00Caml Weekly News<p><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->If you've ever had to parse anything, (anything really), I want to show you a glimpse of what it could look like when you parse it binary string pattern matching, like you'd do on Erlang, Elixir, or Gleam.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->In OCaml, we can do this with the <!-- CommonMark raw HTML omitted -->bitstring<!-- CommonMark raw HTML omitted --> package.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->To do this we'll use a small example of something I've had to parse recently: WebSocket Frames.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->A WebSocket frame looks like this:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|I|S|S|S| (4) |A| (7) | (16/64) |
|N|V|V|V| |S| | (if payload len==126/127) |
| |1|2|3| |K| | |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
| Extended payload length continued, if payload len == 127 |
+ - - - - - - - - - - - - - - - +-------------------------------+
| |Masking-key, if MASK set to 1 |
+-------------------------------+-------------------------------+
| Masking-key (continued) | Payload Data |
+-------------------------------- - - - - - - - - - - - - - - - +
: Payload Data continued ... :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Payload Data continued ... |
+---------------------------------------------------------------+</p>
<p><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->pretty ascii art for a websocket frame from <!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->rfc6455<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->This roughly means:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->1st byte includes the <!-- CommonMark raw HTML omitted -->fin<!-- CommonMark raw HTML omitted -->, <!-- CommonMark raw HTML omitted -->rsv1,2,3<!-- CommonMark raw HTML omitted --> and <!-- CommonMark raw HTML omitted -->opcode<!-- CommonMark raw HTML omitted --> headers<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->2nd byte includes a <!-- CommonMark raw HTML omitted -->mask<!-- CommonMark raw HTML omitted --> and a <!-- CommonMark raw HTML omitted -->payload_length<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->3rd-7th byte includes an extended payload (can be shorter too)<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->the byte after that is going to be a masking key<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->and then the rest is the actual data you packed in the WebSocket frame<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->The way you'd parse this with parse combinators looks a lot like the <!-- CommonMark raw HTML omitted -->BNF grammar<!-- CommonMark raw HTML omitted --> used to describe this packet. Let's look at some code, shall we?<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->We'll assume we have a function <!-- CommonMark raw HTML omitted -->Frame.make ~fin ~compressed ~rsv ~opcode ~mask ~payload<!-- CommonMark raw HTML omitted --> that will create a record of type <!-- CommonMark raw HTML omitted -->Frame.t<!-- CommonMark raw HTML omitted -->. That part is the least interesting. The interesting thing is how do we get those values.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Here's how the <!-- CommonMark raw HTML omitted -->websocketaf<!-- CommonMark raw HTML omitted --> parses this frame using :<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->(* this example code taken almost verbatim from the <code>websocketaf</code>
opam package.</p>
<p>I've only amended the last <code>parse</code> function to make it more obvious how
the parsing is becoming a frame. In practice they do something
different after parsing.
*)</p>
<p>(* a Bigstringaf.t (i know, i giggle too) is an efficient type
for a large string that doesn't have to be copied over and over.</p>
<p>If you need something similar in your code, consider using Cstruct.t
*)
type t = Bigstringaf.t</p>
<p>(* this function takes a bigstring and checks if the first bit, which
corresponds to the FIN bit is set *)
let is_fin t =
let bits = Bigstringaf.unsafe_get t 0 |> Char.code in
bits land (1 lsl 8) = 1 lsl 8
;;</p>
<p>(* this function extracts the reserverd bits from the bigstring *)
let rsv t =
let bits = Bigstringaf.unsafe_get t 0 |> Char.code in
(bits lsr 4) land 0b0111
;;</p>
<p>(* this function creates an int representation for an opcode *)
let opcode t =
let bits = Bigstringaf.unsafe_get t 0 |> Char.code in
bits land 0b1111 |> Opcode.unsafe_of_code
;;</p>
<p>(* this function gets the length of the payload.
and yes that comment was already there.
<em>)
let payload_length_of_offset t off =
let bits = Bigstringaf.unsafe_get t (off + 1) |> Char.code in
let length = bits land 0b01111111 in
if length = 126 then Bigstringaf.unsafe_get_int16_be t (off + 2) else
(</em> This is technically unsafe, but if somebody's asking us to read 2^63</p>
<ul>
<li>bytes, then we're already screwd. *)
if length = 127 then Bigstringaf.unsafe_get_int64_be t (off + 2) |> Int64.to_int else
length
;;</li>
</ul>
<p>let payload_length t =
payload_length_of_offset t 0
;;</p>
<p>(* this function checks if the bigstring has a specific mask set *)
let has_mask t =
let bits = Bigstringaf.unsafe_get t 1 |> Char.code in
bits land (1 lsl 7) = 1 lsl 7</p>
<p>(* and this one checks if the mask exists and if so, gets the value *)
let mask t =
if not (has_mask t)
then None
else
Some (
let bits = Bigstringaf.unsafe_get t 1 |> Char.code in
if bits = 254 then Bigstringaf.unsafe_get_int32_be t 4 else
if bits = 255 then Bigstringaf.unsafe_get_int32_be t 10 else
Bigstringaf.unsafe_get_int32_be t 2)
;;</p>
<p>(* this computes the offset of the payload in bits *)
let payload_offset_of_bits bits =
let initial_offset = 2 in
let mask_offset = (bits land (1 lsl 7)) lsr (7 - 2) in
let length_offset =
let length = bits land 0b01111111 in
if length < 126
then 0
else 2 lsl ((length land 0b1) lsl 2)
in
initial_offset + mask_offset + length_offset
;;</p>
<p>let payload_offset t =
let bits = Bigstringaf.unsafe_get t 1 |> Char.code in
payload_offset_of_bits bits
;;</p>
<p>let length_of_offset t off =
let bits = Bigstringaf.unsafe_get t (off + 1) |> Char.code in
let payload_offset = payload_offset_of_bits bits in
let payload_length = payload_length_of_offset t off in
payload_offset + payload_length
;;</p>
<p>let length t =
length_of_offset t 0
;;</p>
<p>let apply_mask mask bs ~off ~len =
for i = off to off + len - 1 do
let j = (i - off) mod 4 in
let c = Bigstringaf.unsafe_get bs i |> Char.code in
let c = c lxor Int32.(logand (shift_right mask (8 * (3 - j))) 0xffl |> to_int) in
Bigstringaf.unsafe_set bs i (Char.unsafe_chr c)
done
;;</p>
<p>let unmask_inplace t =
if has_mask t then begin
let mask = mask_exn t in
let len = payload_length t in
let off = payload_offset t in
apply_mask mask t ~off ~len
end
;;</p>
<p>(* this was confusing to me too *)
let mask_inplace = unmask_inplace</p>
<p>let parse =
let open Angstrom in
Unsafe.peek 2 (fun bs ~off ~len:_ -> length_of_offset bs off)
>>= fun len -> Unsafe.take len Bigstringaf.sub
>>| fun frame ->
let fin = Websocket.Frame.is_fin frame in
let opcode = Websocket.Frame.opcode frame in
unmask_inplace frame;
let len = payload_length t in
let off = payload_offset t in
Frame.make ~fin ~opcode ~payload:(len, off, frame)
;;<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->This process begins by defining from the bottom up all the smallest parts we need to use in our final combinator. Only at the very end do we stitch everything together. It also requires us to keep track of several small numbers in different positions to understand what is being read from where.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->If you wanted to run this parser incrementally, you now need an external loop that would normally read something like this:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->let parse ?(parser = Frame.parse) data =
match parser with
(* check if the parser is currently in a partial state <em>)
| Angstrom.Buffered.Partial continue -> (
(</em> continue by with the next piece of data <em>)
match continue (<code>Bigstring data) with (* if we're done, return our frame *) | Angstrom.Buffered.Done (_unconsumed, frame) -&gt; Ok (</code>frame frame)
(</em> handle any parsing errors *)
| Angstrom.Buffered.Fail (_, _, _) -> Error <code>bad_frame (* otherwise return that we need more data to continue *) | parser -&gt; Ok (</code>more parser))
| Angstrom.Buffered.Done (_unconsumed, frame) -> Ok (<code>frame frame) | Angstrom.Buffered.Fail (_, _, _) -&gt; Error </code>bad_frame</p>
<p>(* helper function to read data and continue parsing until we are done
or until the parser errors *)
let rec read_all_and_parse ?(parser=Frame.parse) () =
let data = read_data () in
match parse ~parser data with
| Ok (<code>more parser) -&gt; read_all_and_parse ~parser () | Ok (</code>frame frame) -> Ok frame
| Error reason -> Error reason
<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Not bad! I kinda like being able to control the parsing incrementally like this. It can make for really efficient code.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->And here's how it can look when pattern matching on binary strings:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->let deserialize ?(max_frame_size = 0) data =
match%bitstring Bitstring.bitstring_of_string data with
| {| fin : 1;
compressed : 1;
rsv : 2;
opcode : 4;
pad1 : 1 : check( pad1 = true );
pad2 : 7 : check( pad2 = 127 );
length : 64;
mask : 32;
payload : Int64.(mul length 8L |> to_int) : string;
rest : -1 : string |}
when max_frame_size = 0 || Int64.(length <= of_int max_frame_size) ->
Some (Frame.make ~fin ~compressed ~rsv ~opcode ~mask ~payload, rest)</p>
<p>| {| fin : 1;
compressed : 1;
rsv : 2;
opcode : 4;
pad1 : 1 : check( pad1 = true );
pad2 : 7 : check( pad2 = 126 );
length : 16 : int;
mask : 32 : int;
payload : (length * 8) : string;
rest : -1 : string |}
when max_frame_size = 0 || length <= max_frame_size ->
Some (Frame.make ~fin ~compressed ~rsv ~opcode ~mask ~payload, rest)</p>
<p>| {| fin : 1;
compressed : 1;
rsv : 2;
opcode : 4;
x : 1 : check( x = true );
length : 7 : int;
mask : 32 : int;
payload : (length * 8) : string;
rest : -1 : string |}
when length <= 125 && (max_frame_size == 0 || length <= max_frame_size) ->
Some (Frame.make ~fin ~compressed ~rsv ~opcode ~mask ~payload, rest)</p>
<p>| {| data : -1 : string |} -> Some (`more data, "")<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->This function also takes in a string as data, but it does a much clearer job of outlining what are the valid cases for frames on each matching branch. <!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Let's break this down.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->A binary pattern match starts with <!-- CommonMark raw HTML omitted -->match%bitstring data with<!-- CommonMark raw HTML omitted --> and includes several cases. Every case is a regular OCaml string with the delimiters <!-- CommonMark raw HTML omitted -->{| ... |}<!-- CommonMark raw HTML omitted --> . The <!-- CommonMark raw HTML omitted -->bitstring<!-- CommonMark raw HTML omitted --> package will translate this string into a series of operations over the string data. This is why this is more declarative.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Okay but what goes inside each pattern? <!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Roughly every binary pattern follows this format: <!-- CommonMark raw HTML omitted -->{| variable : size : type |}<!-- CommonMark raw HTML omitted --> and they are all separated by semicolons.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->For example, let's grab the first branch of the match:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->{| fin : 1;
compressed : 1;
rsv : 2;
opcode : 4;
pad1 : 1 : check( pad1 = true );
pad2 : 7 : check( pad2 = 127 );
length : 64;
mask : 32;
payload : Int64.(mul length 8L |> to_int) : string;
rest : -1 : string |}<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->In here we are saying that:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->the first bit will be captured by the variable <!-- CommonMark raw HTML omitted -->fin<!-- CommonMark raw HTML omitted -->, <!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->the second one by the variable <!-- CommonMark raw HTML omitted -->compressed<!-- CommonMark raw HTML omitted -->, <!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->the next 2 bits by the variable <!-- CommonMark raw HTML omitted -->rsv<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->the next 4 bits by the variable <!-- CommonMark raw HTML omitted -->opcode<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->the next 1 bit by the variable <!-- CommonMark raw HTML omitted -->pad1<!-- CommonMark raw HTML omitted --> , and we will check that the variable <!-- CommonMark raw HTML omitted -->pad1<!-- CommonMark raw HTML omitted --> is true – since it is a single bit, the library maps this to a <!-- CommonMark raw HTML omitted -->bool<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->the next 7 bits by the variable <!-- CommonMark raw HTML omitted -->pad2<!-- CommonMark raw HTML omitted -->, and we will check that it is the number 127<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->the next 64 bits by the variable <!-- CommonMark raw HTML omitted -->length<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->the next 32 bits by the variable <!-- CommonMark raw HTML omitted -->mask<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->and next <!-- CommonMark raw HTML omitted -->length * 8<!-- CommonMark raw HTML omitted --> bits by the variable payload – and we specifically want this to be captured as a string<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->the rest of the bits (<!-- CommonMark raw HTML omitted -->-1<!-- CommonMark raw HTML omitted -->) as a string<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Now compare that to our little diagram and tell me if this, while packed with info, is not easier to double-check that you are in fact parsing the right thing.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|I|S|S|S| (4) |A| (7) | (16/64) |
|N|V|V|V| |S| | (if payload len==126/127) |
| |1|2|3| |K| | |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
| Extended payload length continued, if payload len == 127 |
+ - - - - - - - - - - - - - - - +-------------------------------+
| |Masking-key, if MASK set to 1 |
+-------------------------------+-------------------------------+
| Masking-key (continued) | Payload Data |
+-------------------------------- - - - - - - - - - - - - - - - +
: Payload Data continued ... :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Payload Data continued ... |
+---------------------------------------------------------------+</p>
<p><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->pretty ascii art for a websocket frame from <!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->rfc6455<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->With that explained, we can go back to calling our function.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Since we control the returning values in this function, it is straightforward to fit it into other abstractions that we may be using. For example, we can use it with <!-- CommonMark raw HTML omitted -->Seq.unfold<!-- CommonMark raw HTML omitted --> to generate a sequence of frames:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Seq.unfold deserialize data
(* <code>ok frame </code>ok frame
<code>more rest *)</code></pre><p>And with a little combinator for sequences, we can make it quite pleasant to incrementally parse over streams of data:</p><pre><code class="language-ocaml">(* reduce a value until we explicitly halt or the sequence is finished *) let rec reduce_while init fn t = match t () with | Seq.Nil -&gt; init | Seq.Cons (v, t') -&gt; ( match fn v init with | </code>continue acc -> reduce_while acc fn t'
| `halt acc -> acc)</p>
<p>(* do an incremental read/parse/handle_frame loop *)
let rec parse data =
let next =
Seq.unfold Frame.deserialize data
|> reduce_while <code>ok (fun frame state -&gt; match (state, frame) with | </code>ok, <code>more buf -&gt; </code>halt (<code>more buf) | </code>ok, <code>ok frame -&gt; </code>continue (handle_frame frame)
| <code>ok, </code>error reason -> <code>halt (</code>error reason)
| <code>error reason, _ -&gt; </code>halt (<code>error reason) | </code>more buf, _ -> <code>halt (</code>more buf))
in
match next with
| <code>ok -&gt; Ok () | </code>error reason -> Error reason
| `more buffer ->
let more_data = read_data () in
parse (buffer ^ more_data)
<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Just to clarify, I'm sure you can fit Angstrom into a <!-- CommonMark raw HTML omitted -->Seq.t<!-- CommonMark raw HTML omitted --> as well. So this last <!-- CommonMark raw HTML omitted -->reduce_while<!-- CommonMark raw HTML omitted --> trick isn't a win specifically for binary pattern matching, but having full control over how the parser executes sure helps us build parsers that fit exactly where we need them to.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Conclusion<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->I like binary pattern matching better, it has way less cognitive overhead, it helps me parse instantly what a sequence of bits/bytes would look like, and its recursive descent approach helps me write parsers that fit exactly into the code around them.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->They're not for everything, and some things can be rather painful to parse where you end up using tiny combinators anyway (like "parse all until new line"), but overall I think they're a major improvement in readability and declarativeness over parser combinators.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->If you find this interesting, have a look at <!-- CommonMark raw HTML omitted -->bitstring<!-- CommonMark raw HTML omitted -->. I'll be writing more about this package soon.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->That's all I've got for today folks, it's the last day of the year and I figured we should end it with one last 2023 issue.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->If you liked what I've written you can support me on <!-- CommonMark raw HTML omitted -->Github Sponsors<!-- CommonMark raw HTML omitted --> ✨<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Here's to more Practical OCaml in 2024 🥂 <!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Thanks to <!-- CommonMark raw HTML omitted -->@dillon_mulroy<!-- CommonMark raw HTML omitted --> for reviewing a draft of this post.<!-- CommonMark raw HTML omitted --></p>
https://practicalocaml.com/parsing-with-binary-string-pattern-matching/Parsing with Binary String Pattern Matching2023-12-31T21:01:50-00:00Practical OCaml<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2023-12-29-announcing-the-orchide-project-powering-satellite-innovationAnnouncing the ORCHIDE Project: Powering Satellite Innovation2023-12-29T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.12.26.htmlOCaml Weekly News, 26 Dec 20232023-12-26T12:00:00-00:00Caml Weekly News<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2023-12-20-ocaml-survey-developers-perception-interest-and-perceived-barriersOCaml Survey: Developers' Perception, Interest, and Perceived Barriers2023-12-20T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.12.19.htmlOCaml Weekly News, 19 Dec 20232023-12-19T12:00:00-00:00Caml Weekly News<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2023-12-14-ocaml-memory-safety-and-beyondOCaml: Memory Safety and Beyond2023-12-14T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
https://ocamlpro.com/blog/2023_12_13_learn_ocaml_gateway_to_the_ocaml_worldMaturing Learn-OCaml to version 1.0: Gateway to the OCaml World2023-12-13T16:49:04-00:00
Dario Pinto
<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.12.12.htmlOCaml Weekly News, 12 Dec 20232023-12-12T12:00:00-00:00Caml Weekly Newshttps://oyenugaoluwaseun.hashnode.dev/outreachy-introduce-yourselfOutreachy Blog #1: Introduce Yourself2023-12-12T00:00:00-00:00Oluwaseun<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted -->OCaml 5.1.1<!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted -->module<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->type<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->Root<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->sig<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->include<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->Def<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->val<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->v1<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->:<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->id<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->scheme_version<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->val<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->new_key<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->:<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->id<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->scheme_version<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->-><!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->string<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->-><!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->'<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->a<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->typ<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->-><!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->'<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->a<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->key<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->val<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->new_version<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->:<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->version<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->-><!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->id<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->scheme_version<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->end<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
https://gallium.inria.fr/blog/florian-cw-2023-12-11Florian compiler weekly, 11 December 20232023-12-11T08:00:00-00:00GaGalliumhttps://idaranabuk.com/blog/introductionMy Tech Journey and Outreachy Internship.2023-12-10T00:00:00-00:00Idara<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.12.05.htmlOCaml Weekly News, 05 Dec 20232023-12-05T12:00:00-00:00Caml Weekly News<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2023-12-05-international-disability-day-2023-why-it-mattersInternational Disability Day 2023: Why It Matters2023-12-05T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted -->module<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->UDP1<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->:<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->UNSAFE<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->module<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->UDP2<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->:<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->UNSAFE<!-- CommonMark raw HTML omitted --></p>
<p><!-- CommonMark raw HTML omitted -->module<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->Reliable<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->:<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->UNSAFE<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->-><!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->UNSAFE<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->module<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->CongestionControl<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->:<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->UNSAFE<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->-><!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->UNSAFE<!-- CommonMark raw HTML omitted --></p>
<p><!-- CommonMark raw HTML omitted -->module<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->Encryption<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->:<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->UNSAFE<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->-><!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->sig<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->val<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->send<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->:<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->string<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->-><!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->unit<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->(* ... *)<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->end<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->end<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted -->1.2 Module-level polymorphism<!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted -->module<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->F'<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Y<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->:<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->sig<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->module<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->type<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->S<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->end<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Arg<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->:<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->sig<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->...<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->module<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->X<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->:<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->Y<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->S<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->...<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->end<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->...<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->(* polymorphism is enforced *)<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --></p>
<p><!-- CommonMark raw HTML omitted -->1.3 So it’s just
normal use cases of abstraction ?<!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted -->module<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->Crash<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Y<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->:<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->sig<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->end<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->F<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->struct<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->module<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->type<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->T<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->sig<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->module<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->X<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->Y<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->end<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->end<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --></p>
<p><!-- CommonMark raw HTML omitted -->2.3.2 Loss of applicativity<!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted -->module<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->Test<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->F<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->struct<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->type<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->t<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->end<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted --></p>
<p><!-- CommonMark raw HTML omitted -->(* returns *)<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->module<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->Test<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->:<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->sig<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->module<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->type<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->A<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->module<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->X<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->:<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->A<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->type<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->u<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->X<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->u<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->end<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted -->module<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->Test1<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->F1<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Y<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->module<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->Test2<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->F2<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Y<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted -->Transparent ascription<!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted -->3.3 Our proposal :
<!-- CommonMark raw HTML omitted -->simple<!-- CommonMark raw HTML omitted --> abstract signatures<!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted -->Higher-abstraction ?<!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted -->module<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->ApplyGv<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->[<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->A<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->]<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->[<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->B<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->]<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->F<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->A<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->-><!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->GlobalVars<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->-><!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->B<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->X<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->A<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->F<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->X<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->)(<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Gv<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted --></p>
<p><!-- CommonMark raw HTML omitted -->(* At the call site *)<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->module<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->M1<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->MakeApply<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->[<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->T<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->]<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->X<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->[<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Hashtbl<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->HashedType<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->]<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->F<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->[<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Hashtbl<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->S<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->]<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Hashtbl<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted --></p>
<p><!-- CommonMark raw HTML omitted -->module<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->M2<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->ApplyGv<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->[<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->A<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->]<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->[<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->B<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->]<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->F<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->X<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
http://gallium.inria.fr/blog/rethinking-ocaml-abstract-signaturesRethinking OCaml abstract signatures2023-12-01T08:00:00-00:00GaGalliumhttps://frama-c.com/fc-versions/nickel.htmlRelease of Frama-C 28.0 (Nickel)2023-11-30T00:00:00-00:00Frama-C<!-- CommonMark HTML block omitted -->
<p>(* slightly-higher level binding, that checks the buffer offset is ok *)
let write fd buf ofs len =
if ofs < 0 || len < 0 || ofs > Bytes.length buf - len
then invalid_arg "Unix.write"
else unsafe_write fd buf ofs len<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->caml_unix_write<!-- CommonMark raw HTML omitted --> will in turn call a C function called <!-- CommonMark raw HTML omitted -->write<!-- CommonMark raw HTML omitted --> which comes from <!-- CommonMark raw HTML omitted -->libc<!-- CommonMark raw HTML omitted --> on Unix-like operating systems that follow the POSIX standard, and will call <!-- CommonMark raw HTML omitted -->WriteFile<!-- CommonMark raw HTML omitted --> from the Windows APIs when compiling on Windows.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->write<!-- CommonMark raw HTML omitted --> from libc, and <!-- CommonMark raw HTML omitted -->WriteFile<!-- CommonMark raw HTML omitted --> from the Windows APIS. Those are the syscalls.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->🙈<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->If I've lost you already because you wanted to learn about OCaml and now we're talking about C, then you will understand why I'm frustrated about this whole thing.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->The important thing to know is that when you are using this module, many of the functions you will call there are not OCaml code. They are C code, and they reach into the depths of your operating system to do dangerous, wonderful, weird things.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->On Unix systems, one of those is<!-- CommonMark raw HTML omitted --> signals<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Unix Signals<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Unix has a way of <!-- CommonMark raw HTML omitted -->interrupting<!-- CommonMark raw HTML omitted --> a process with a mechanism called <!-- CommonMark raw HTML omitted -->signals<!-- CommonMark raw HTML omitted -->. A process in turn can tell Unix how it's going to react to those signals, by setting a <!-- CommonMark raw HTML omitted -->signal handler.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->It's essentially a configurable, OS-triggered callback.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Some of these signals are very common. Like when you press <!-- CommonMark raw HTML omitted -->Ctr+C<!-- CommonMark raw HTML omitted --> to exit a long-running program, you're really sending a <!-- CommonMark raw HTML omitted -->SIGINT<!-- CommonMark raw HTML omitted --> signal, also known as an<!-- CommonMark raw HTML omitted --> interrupt signal.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->You can of course override this, and you see many REPLs do it, so that if you accidentally press <!-- CommonMark raw HTML omitted -->Ctrl+C<!-- CommonMark raw HTML omitted --> you get a chance to confirm this and exit or return to the program.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Signals, however, are not a part of the Unix module. If we want to configure them (and their handlers) we need to use the <!-- CommonMark raw HTML omitted -->Sys<!-- CommonMark raw HTML omitted --> module.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->⁉️<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->What is the Sys module?<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --> It's a bag of sort of random stuff, and a few things that probably deserve to be in a module called Sys like what OS you're on. If you ask me, I'd rather we didn't have a Sys/Unix module at all, and just had proper abstractions for File, Socket, OS, Env, Process, etc. But c'est la vie. In the meantime, we have <!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->In particular, we need to use the <!-- CommonMark raw HTML omitted -->Sys.set_signal<!-- CommonMark raw HTML omitted -->. This function lets you set the behavior for a particular signal, which can be one of:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Default – whatever POSIX decides is the default<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Ignore – just do nothing with it<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Set a custom handler – use this handler to do something that fits your program<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Fixing The SIGPIPEs<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->The error we had described before is fixed with a single line of OCaml at the top of our program:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Sys.(set_signal sigpipe Signal_ignore);;<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Mark the SIGPIPE signal to be ignored.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->But the knowledge required to put that line there isn't trivial.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->You need to know that the Unix module is just a wrapper around OS syscalls. And in here you'll want to know exactly which one, which may involve <!-- CommonMark raw HTML omitted -->digging<!-- CommonMark raw HTML omitted --> through some of the OCaml C libraries.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->You need to know where to find the right doc for that syscall (<!-- CommonMark raw HTML omitted -->is it BSD<!-- CommonMark raw HTML omitted --> since macOS inherited a lot from it? That doesn't mention anything about SIGPIPEs, maybe <!-- CommonMark raw HTML omitted -->the Linux syscall manual<!-- CommonMark raw HTML omitted --> is relevant here?<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Linux system manual saving the day<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->And then you have to learn about Signals, how to catch them, and how to use the <!-- CommonMark raw HTML omitted -->Sys<!-- CommonMark raw HTML omitted --> module to do that. Granted this last part is the easiest since it's more actionable, but that second step?! Not as easy a leap to make.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Conclusion<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->This is most definitely not the kind of surprise you want to find when writing a type-safe, high-level functional programming language like OCaml.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Hell, I think <!-- CommonMark raw HTML omitted -->Python does this better<!-- CommonMark raw HTML omitted --> by throwing an <!-- CommonMark raw HTML omitted -->IOError<!-- CommonMark raw HTML omitted --> instead. That would've saved me hours of self-doubt.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->If you really need this level of control, <!-- CommonMark raw HTML omitted -->you may find it useful to mentally frame it as writing <!-- CommonMark raw HTML omitted -->garbage-collected C<!-- CommonMark raw HTML omitted -->, and behave accordingly. And please shield your users from all the gory details.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Otherwise<!-- CommonMark raw HTML omitted -->,<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->stay happy and away from the Unix module<!-- CommonMark raw HTML omitted --> and look for alternatives. Use <!-- CommonMark raw HTML omitted -->Bos<!-- CommonMark raw HTML omitted --> for your OS interactions, stick to a higher-level library for sockets, and if it comes to it, isolate that part of your system.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->I hope this gotcha won't get you the next time you're writing network code, and if you have any stories like this one, I'd be happy to share them on Practical OCaml too.<!-- CommonMark raw HTML omitted --></p>
https://practicalocaml.com/unix-module-considered-harmful/Unix Module Considered Harmful2023-11-29T07:19:43-00:00Practical OCaml<!-- CommonMark HTML block omitted -->
https://signals-threads.simplecast.com/episodes/performance-engineering-on-hard-mode-with-andrew-hunter-fxhCMIkBPerformance Engineering on Hard Mode with Andrew Hunter2023-11-28T22:08:42-00:00Signals and Threads<!-- CommonMark HTML block omitted -->
https://hannes.robur.coop/Posts/TCP-nsRedeveloping TCP from the ground up2023-11-28T21:17:01-00:00hannes<!-- CommonMark HTML block omitted -->
https://hannes.robur.coop/Posts/TCP-nsRedeveloping TCP From the Ground Up2023-11-28T21:17:01-00:00hannes<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.11.28.htmlOCaml Weekly News, 28 Nov 20232023-11-28T12:00:00-00:00Caml Weekly News<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.11.21.htmlOCaml Weekly News, 21 Nov 20232023-11-21T12:00:00-00:00Caml Weekly News<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2023-11-21-how-to-install-ocaml-5-a-video-tutorialHow to Install OCaml 5: A Video Tutorial2023-11-21T00:00:00-00:00Tarides<p>How we resurrected MirageVPN from its bitrot state</p>
https://blog.robur.coop/articles/miragevpn-ncp.htmlMirageVPN updated (AEAD, NCP)2023-11-20T10:00:00-00:00Robur Cooperative<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.11.14.htmlOCaml Weekly News, 14 Nov 20232023-11-14T12:00:00-00:00Caml Weekly News<p>How we implementated tls-crypt-v2 for miragevpn</p>
https://blog.robur.coop/articles/miragevpn.htmlMirageVPN & tls-crypt-v22023-11-14T10:00:00-00:00Robur Cooperative<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2023-11-09-ocaml-hacking-day-in-chennaiOCaml Hacking Day in Chennai!2023-11-09T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.11.07.htmlOCaml Weekly News, 07 Nov 20232023-11-07T12:00:00-00:00Caml Weekly News%20https://frama-c.com/fc-plugins/metacsl.html%20MetAcsl for Frama-C 27.x Cobalt2023-11-07T00:00:00-00:00Frama-C<!-- CommonMark HTML block omitted -->
https://tech.ahrefs.com/building-react-server-components-in-ocaml-81c276713f19?source=rss----303662d88bae--ocamlBuilding React Server Components in OCaml2023-11-02T18:29:55-00:00Ahrefs<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2023-11-01-webassembly-support-for-ocaml-introducing-wasm-of-ocamlWebAssembly Support for OCaml: Introducing Wasm_of_Ocaml2023-11-01T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.10.31.htmlOCaml Weekly News, 31 Oct 20232023-10-31T12:00:00-00:00Caml Weekly News%20https://frama-c.com/fc-versions/nickel.html%20Beta release of Frama-C 28.0~beta (Nickel)2023-10-26T00:00:00-00:00Frama-C<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted -->let<!-- CommonMark raw HTML omitted --> main <!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->let<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->open<!-- CommonMark raw HTML omitted --> Lwt<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->Syntax <!-- CommonMark raw HTML omitted -->in<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->let<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><em><!-- CommonMark raw HTML omitted --> tab <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> Browser<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->tabs <!-- CommonMark raw HTML omitted -->|><!-- CommonMark raw HTML omitted --> Tabs<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->active <!-- CommonMark raw HTML omitted -->in<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->let<!-- CommonMark raw HTML omitted --> model <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->let<!-- CommonMark raw HTML omitted --> name <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> Tab<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->title tab <!-- CommonMark raw HTML omitted -->in<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->let<!-- CommonMark raw HTML omitted --> url <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> Tab<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->url tab <!-- CommonMark raw HTML omitted -->in<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->let<!-- CommonMark raw HTML omitted --> created_at <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> Date<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->now <!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->in<!-- CommonMark raw HTML omitted -->
Model<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->v <!-- CommonMark raw HTML omitted -->~created_at<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->~name<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->~url<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->~notes<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->""<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->in<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->let<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --></em><!-- CommonMark raw HTML omitted --> client <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> Client<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->connect <!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->in<!-- CommonMark raw HTML omitted -->
Ui<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->bind client model</p>
<p><!-- CommonMark raw HTML omitted -->let<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> Document<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->on_content_loaded <!-- CommonMark raw HTML omitted -->@@<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->fun<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->_<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->-><!-- CommonMark raw HTML omitted --> Lwt<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->async main<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted -->let<!-- CommonMark raw HTML omitted --> title t <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> Jv<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->get t <!-- CommonMark raw HTML omitted -->"title"<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->|><!-- CommonMark raw HTML omitted --> Jv<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->to_string
<!-- CommonMark raw HTML omitted -->let<!-- CommonMark raw HTML omitted --> url t <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> Jv<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->get t <!-- CommonMark raw HTML omitted -->"url"<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->|><!-- CommonMark raw HTML omitted --> Jv<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->to_string
<!-- CommonMark raw HTML omitted -->end<!-- CommonMark raw HTML omitted --></p>
<p><!-- CommonMark raw HTML omitted -->module<!-- CommonMark raw HTML omitted --> Browser <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->struct<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->let<!-- CommonMark raw HTML omitted --> v <!-- CommonMark raw HTML omitted -->:<!-- CommonMark raw HTML omitted --> Jv<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->t <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> Jv<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->get Jv<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->global <!-- CommonMark raw HTML omitted -->"browser"<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->let<!-- CommonMark raw HTML omitted --> tabs <!-- CommonMark raw HTML omitted -->:<!-- CommonMark raw HTML omitted --> Tabs<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->t <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> Jv<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->get v <!-- CommonMark raw HTML omitted -->"tabs"<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->end<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted -->let<!-- CommonMark raw HTML omitted --> ui <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> Document<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->lookup_by_id <!-- CommonMark raw HTML omitted -->"ui"<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->in<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->let<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->_<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted -->
elems
<!-- CommonMark raw HTML omitted -->|><!-- CommonMark raw HTML omitted --> List<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->map Brr<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->El<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->to_jv
<!-- CommonMark raw HTML omitted -->|><!-- CommonMark raw HTML omitted --> Array<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->of_list
<!-- CommonMark raw HTML omitted -->|><!-- CommonMark raw HTML omitted --> Jv<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->call <!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted -->Brr<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->El<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->to_jv ui<!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->"replaceChildren"<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->in<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted -->module<!-- CommonMark raw HTML omitted --> Codec <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> Irmin_server<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->Conn<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->Codec<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->Bin
<!-- CommonMark raw HTML omitted -->module<!-- CommonMark raw HTML omitted --> Client <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> Irmin_client_jsoo<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->Make_codec <!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted -->Codec<!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted -->Store<!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted -->let<!-- CommonMark raw HTML omitted --> merge <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> Irmin<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->Merge<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted -->option <!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted -->v t merge_m<!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted -->let<!-- CommonMark raw HTML omitted --> load t model <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->let<!-- CommonMark raw HTML omitted --> key <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> Model<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->key_path model <!-- CommonMark raw HTML omitted -->in<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->(* [Store.find] *)<!-- CommonMark raw HTML omitted -->
find t key</p>
<p><!-- CommonMark raw HTML omitted -->let<!-- CommonMark raw HTML omitted --> save t model <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->let<!-- CommonMark raw HTML omitted --> f tree <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->let<!-- CommonMark raw HTML omitted --> key <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> Model<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->key_path model <!-- CommonMark raw HTML omitted -->in<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->(* [Store.Tree.add] *)<!-- CommonMark raw HTML omitted -->
Tree<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->add tree key model
<!-- CommonMark raw HTML omitted -->in<!-- CommonMark raw HTML omitted -->
update t f <!-- CommonMark raw HTML omitted -->~info<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted -->Info_jsoo<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->v <!-- CommonMark raw HTML omitted -->~author<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->"Update %s"<!-- CommonMark raw HTML omitted --> model<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->url <!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted --></p>
<p><!-- CommonMark raw HTML omitted -->let<!-- CommonMark raw HTML omitted --> delete t model <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->let<!-- CommonMark raw HTML omitted --> f tree <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->let<!-- CommonMark raw HTML omitted --> key <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> Model<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->key_path model <!-- CommonMark raw HTML omitted -->in<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->(* [Store.Tree.remove] *)<!-- CommonMark raw HTML omitted -->
Tree<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->remove tree key
<!-- CommonMark raw HTML omitted -->in<!-- CommonMark raw HTML omitted -->
update t f <!-- CommonMark raw HTML omitted -->~info<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted -->Info_jsoo<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->v <!-- CommonMark raw HTML omitted -->~author<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->"Delete %s"<!-- CommonMark raw HTML omitted --> model<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->url <!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2023-10-25-tutorial-building-a-browser-extension-with-irminTutorial: Building a Browser Extension With Irmin2023-10-25T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.10.24.htmlOCaml Weekly News, 24 Oct 20232023-10-24T12:00:00-00:00Caml Weekly News<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted -->let<!-- CommonMark raw HTML omitted --> clients1 <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->(* Some data source *)<!-- CommonMark raw HTML omitted --></p>
<p><!-- CommonMark raw HTML omitted -->let<!-- CommonMark raw HTML omitted --> clients2 <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->(* Some data source *)<!-- CommonMark raw HTML omitted --></p>
<p><!-- CommonMark raw HTML omitted -->let<!-- CommonMark raw HTML omitted --> record_clients <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted -->
Seq<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->iter
<!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->fun<!-- CommonMark raw HTML omitted --> c <!-- CommonMark raw HTML omitted -->-><!-- CommonMark raw HTML omitted --> Hashtbl<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->add clients <!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted -->Atomic<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->fetch_and_add free_id <!-- CommonMark raw HTML omitted -->1<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted --> c<!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted --></p>
<p><!-- CommonMark raw HTML omitted -->let<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted -->
<!-- CommonMark raw HTML omitted -->let<!-- CommonMark raw HTML omitted --> d <!-- CommonMark raw HTML omitted -->=<!-- CommonMark raw HTML omitted --> Domain<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->spawn <!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->fun<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->(<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->-><!-- CommonMark raw HTML omitted --> record_clients clients1<!-- CommonMark raw HTML omitted -->)<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted -->in<!-- CommonMark raw HTML omitted -->
record_clients clients2<!-- CommonMark raw HTML omitted -->;<!-- CommonMark raw HTML omitted -->
Domain<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted -->join d<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
<p>Previous read of size 8 at 0x7f42b37f57e0 by thread T1 (mutexes: write M90):
#0 camlStdlib__Hashtbl.key_index_1308 stdlib/hashtbl.ml:507 (clients.exe+0x53a625)
#1 camlStdlib__Hashtbl.add_1312 stdlib/hashtbl.ml:511 (clients.exe+0x53a6f8)
#2 camlStdlib__Seq.iter_329 stdlib/seq.ml:76 (clients.exe+0x4c8a87)
#3 camlStdlib__Domain.body_703 stdlib/domain.ml:202 (clients.exe+0x50bf60)
#4 caml_start_program <null> (clients.exe+0x5a0ae7)
#5 caml_callback_exn runtime/callback.c:197 (clients.exe+0x56917b)
#6 caml_callback runtime/callback.c:293 (clients.exe+0x569cb0)
#7 domain_thread_func runtime/domain.c:1100 (clients.exe+0x56d37f)
[...]</p>
<h1>SUMMARY: ThreadSanitizer: data race runtime/memory.c:166 in caml_modify</h1>
<p>[...]
ThreadSanitizer: reported 2 warnings<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2023-10-18-off-to-the-races-using-threadsanitizer-in-ocamlOff to the Races: Using ThreadSanitizer in OCaml2023-10-18T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.10.17.htmlOCaml Weekly News, 17 Oct 20232023-10-17T12:00:00-00:00Caml Weekly News<p>Opam: Package Manager on Steroids?</p>
https://priver.dev/blog/ocaml/opam-pkg-manager-on-steroids/Opam: Package Manager on Steroids?2023-10-12T20:38:24-00:00Emil Privér<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.10.10.htmlOCaml Weekly News, 10 Oct 20232023-10-10T12:00:00-00:00Caml Weekly News<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2023-10-10-prioritising-mental-health-at-taridesPrioritising Mental Health at Tarides2023-10-10T00:00:00-00:00Tarides<p>A description of the Miou design and its rules</p>
https://blog.osau.re/articles/miou_rules.htmlRules of Miou!2023-10-09T10:00:00-00:00Romain Calascibetta<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2023-10-04-porting-obuilder-to-freebsdPorting OBuilder to FreeBSD2023-10-04T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.10.03.htmlOCaml Weekly News, 03 Oct 20232023-10-03T12:00:00-00:00Caml Weekly News<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2023-09-27-tutorial-how-to-port-lwt-applications-to-eioTutorial: How to Port Lwt Applications to Eio2023-09-27T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.09.26.htmlOCaml Weekly News, 26 Sep 20232023-09-26T12:00:00-00:00Caml Weekly News<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
http://gallium.inria.fr/blog/florian-cw-2023-09-26Florian compiler weekly, 26 September 20232023-09-26T08:00:00-00:00GaGallium<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2023-09-20-a-year-of-spaceos-showing-the-world-the-benefits-of-ocamlA Year of SpaceOS: Showing the World the Benefits of OCaml2023-09-20T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.09.19.htmlOCaml Weekly News, 19 Sep 20232023-09-19T12:00:00-00:00Caml Weekly News<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
https://ocamlpro.com/blog/2023_09_18_release_of_alt_ergo_2_5_1The latest release of Alt-Ergo version 2.5.1 is out, with improved SMT-LIB and bitvector support!2023-09-18T13:19:46-00:00
Pierre Villemot
<p><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Internships at Tarides<!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2023-09-15-our-experience-at-tarides-projects-from-our-internships-in-2023Our Experience at Tarides: Projects From Our Internships in 20232023-09-15T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
https://tech.ahrefs.com/beyond-typescript-differences-between-typed-languages-f3e14253?source=rss----303662d88bae--ocamlBeyond TypeScript: Differences Between Typed Languages2023-09-14T14:32:06-00:00Ahrefs<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.09.12.htmlOCaml Weekly News, 12 Sep 20232023-09-12T12:00:00-00:00Caml Weekly News<!-- CommonMark HTML block omitted -->
https://blog.janestreet.com/what-the-interns-have-wrought-2023/What the interns have wrought, 2023 edition2023-09-12T00:00:00-00:00Jane Street Tech Blog<p>A description of the Miou scheduler</p>
https://blog.osau.re/articles/miou.htmlMiou, a simple scheduler for OCaml 52023-09-08T10:00:00-00:00Romain Calascibetta<p><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->ICFP 2023<!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2023-09-08-the-state-of-the-art-in-functional-programming-tarides-at-icfp-2023The State of the Art in Functional Programming: Tarides at ICFP 20232023-09-08T00:00:00-00:00Tarides%20https://frama-c.com/fc-plugins/frama-clang.html%20Release of Frama-Clang 0.0.142023-09-07T00:00:00-00:00Frama-C<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.09.05.htmlOCaml Weekly News, 05 Sep 20232023-09-05T12:00:00-00:00Caml Weekly News<!-- CommonMark HTML block omitted -->
https://blog.janestreet.com/oxidizing-ocaml-parallelism/Oxidizing OCaml: Data Race Freedom2023-09-01T00:00:00-00:00Jane Street Tech Blog<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.08.29.htmlOCaml Weekly News, 29 Aug 20232023-08-29T12:00:00-00:00Caml Weekly News<!-- CommonMark HTML block omitted -->
<p>let one: counter = inc 0
let two: counter+1? = inc one
<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Look ma! I made a counter that counts, but you can't see how much it counts on its type. But it's counting, I promise.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->You can bend backwards to do this with some <!-- CommonMark raw HTML omitted -->type schemes<!-- CommonMark raw HTML omitted --> (which is a fancy word for "how to do something" or "pattern" that you may read around). Like a common way of doing this is to use type-params to keep adding types to something. For example:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->type zero = Zero
type 'a inc = Inc of 'a</p>
<p>(* our <code>inc</code> function wraps whatever in an <code>inc</code> type *)
let inc : 'a -> 'a inc = fun x -> Inc x</p>
<p>let one: zero inc = inc Zero
let two: zero inc inc = inc one
let three: zero inc inc inc = inc two<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->And this sort of thing can be suuuper useful if you want to statically validate something. For example, let's say you have a <!-- CommonMark raw HTML omitted -->fuel<!-- CommonMark raw HTML omitted --> type and you can only accelerate your car if you have <!-- CommonMark raw HTML omitted -->enough fuel<!-- CommonMark raw HTML omitted -->. And <!-- CommonMark raw HTML omitted -->enough fuel<!-- CommonMark raw HTML omitted --> is defined as "one unit of fuel" or in types as "it's wrapped by one <!-- CommonMark raw HTML omitted -->fuel<!-- CommonMark raw HTML omitted --> type".<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->So we can start with a car without fuel, fuel it up, and then consume the fuel. And in the next example, you can see how the type annotation matches the amount of fuel a car has.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->type no_fuel = No_fuel
type 'a fuel = Fuel of 'a</p>
<p>let fuel_up x = (Fuel (Fuel x))</p>
<p>let run (Fuel x) = x</p>
<p>let empty_car = No_fuel
let full_car: no_fuel fuel fuel = empty_car |> fuel_up
let full_car: no_fuel fuel = run full_car
let full_car: no_fuel = run full_car</p>
<p>(* this last one will be a type error! *)
let full_car: no_fuel = run full_car<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->In this example we statically track the amount of fuel by using a <!-- CommonMark raw HTML omitted -->fuel<!-- CommonMark raw HTML omitted --> type that is essentially a counter. When we <!-- CommonMark raw HTML omitted -->fuel up<!-- CommonMark raw HTML omitted --> the counter goes up, when we <!-- CommonMark raw HTML omitted -->run<!-- CommonMark raw HTML omitted --> the counter goes down. We can only call <!-- CommonMark raw HTML omitted -->run<!-- CommonMark raw HTML omitted --> on a car with at least one <!-- CommonMark raw HTML omitted -->fuel<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->This fails because the last <!-- CommonMark raw HTML omitted -->full_car<!-- CommonMark raw HTML omitted --> that worked becomes a car with no fuel, and our <!-- CommonMark raw HTML omitted -->run<!-- CommonMark raw HTML omitted --> function requires a car <!-- CommonMark raw HTML omitted -->with<!-- CommonMark raw HTML omitted --> fuel.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->But alas, this can get super complex quickly because:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->We're not used to this kind of programming in the types (unlike in programming languages like Idris or TypeScript)<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->We don't have good debugging tools for this, and type errors can become strange quickly, especially if we use polymorphic variants, objects, or <!-- CommonMark raw HTML omitted -->GADTs<!-- CommonMark raw HTML omitted -->. <!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Okay, there's more to say about type-state, but this should be enough for now: <!-- CommonMark raw HTML omitted -->type-state lets you rule out certain behaviors by putting in your types, information about the values.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Moving on...<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Type-state state machines<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Alright, we're ready to go. The pattern is pretty straightforward:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->We need a type for our <!-- CommonMark raw HTML omitted -->thing<!-- CommonMark raw HTML omitted -->, which will be a state machine<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->We need a type parameter for the <!-- CommonMark raw HTML omitted -->state<!-- CommonMark raw HTML omitted --> the machine is in<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->We want to save that state as a discrete value in our state machine type<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->type 'state fsm = { state: 'state }<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->That's it. That's the pattern. If it seems small it's because it is, but there's so much power to this pattern! Let's explore with an example.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Requesting Permissions as a Type-state machine<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->We'll build a tiny Permissions module that will help us check if a User has the right permissions to access a resource. There will be 3 states: Requested, Granted, and Denied. We'll always start on Requested, and we can move to Granted or Denied. If we are on Granted we should have access to the resource itself, if we are on Denied we should have access to some reason for why we were denied access.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->So we start with our basics, the pattern:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->type 'state t = { state: 'state };<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Next, we're going to add the 3 states as distinct types:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->type id
type scope</p>
<p>type 'resource granted = { resource : 'resource }
type denied = { reason : string }
type requested = { scopes : scope list }<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Let's put this together with our <!-- CommonMark raw HTML omitted -->t<!-- CommonMark raw HTML omitted --> type. We will need to introduce a new type parameter for the <!-- CommonMark raw HTML omitted -->'resource<!-- CommonMark raw HTML omitted -->, so we know what <!-- CommonMark raw HTML omitted -->'resource<!-- CommonMark raw HTML omitted --> to use when we create our <!-- CommonMark raw HTML omitted -->'resource granted<!-- CommonMark raw HTML omitted --> state. We'll also add some more metadata that is specific to a permission request but is shared across all states.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->type ('state, 'resource) t = {
(* the state of the permission request <em>)
state : 'state;
(</em> other shared metadata *)
resource_id : id;
user_id : id;
}<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->And now we can build our API on top of this, using our <!-- CommonMark raw HTML omitted -->'state<!-- CommonMark raw HTML omitted --> type to guide the user to the functions they can use:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->We want to create a new Permissions Request that will be <!-- CommonMark raw HTML omitted -->requested t<!-- CommonMark raw HTML omitted --> <!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->We want to call a function that returns either a <!-- CommonMark raw HTML omitted -->granted t<!-- CommonMark raw HTML omitted --> with our resource, or a <!-- CommonMark raw HTML omitted -->denied t<!-- CommonMark raw HTML omitted --> with a reason<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->If we get a <!-- CommonMark raw HTML omitted -->denied t<!-- CommonMark raw HTML omitted --> we want to be able to see the reasons<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->If we get a <!-- CommonMark raw HTML omitted -->granted t<!-- CommonMark raw HTML omitted --> we want to be able to <!-- CommonMark raw HTML omitted -->use<!-- CommonMark raw HTML omitted --> the resource.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Let's get to work!<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->We'll start with a constructor function, and a function to transition to our final states:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->let make ~resource_id ~user_id ~scopes =
{ state = { scopes }; resource_id; user_id }</p>
<p>let request_access t =
match run_request t with
| Ok resource -> Ok { t with state = { resource } }
| Error reason -> Error { t with state = { reason } }<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->The basic machinery is done. We create, and the type system will infer correctly that the state should be <!-- CommonMark raw HTML omitted -->requested<!-- CommonMark raw HTML omitted -->, because a <!-- CommonMark raw HTML omitted -->requested<!-- CommonMark raw HTML omitted --> record includes <!-- CommonMark raw HTML omitted -->scopes<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Then, our <!-- CommonMark raw HTML omitted -->request_access<!-- CommonMark raw HTML omitted --> function will return either <!-- CommonMark raw HTML omitted -->(granted, 'resource) t<!-- CommonMark raw HTML omitted --> or a <!-- CommonMark raw HTML omitted -->(denied, 'resource) t<!-- CommonMark raw HTML omitted --> wrapped in a result. We can use any variant for this, even a Future, but a result is already present so we'll go with that here.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Great, the next step is implementing our operations:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->(* extract the reason from a <code>denied</code> state *)
let reason { state = { reason }; _ } = reason</p>
<p>(* do something with the resource in a <code>granted</code> state *)
let with_resource { state = {resource}; _ } fn = fn resource</p>
<p>(* get the resource out of a granted permission <em>)
let get { state = {resource}; _ } fn = resource<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->And done. The types get inferred nicely here as well because the records are all disjoint. Now we can use our little state machine:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->(</em> this would be our resource *)
module Album = struct
type t = string
let print = print_string
end</p>
<p>let _ =
let req: (_, Album.t) Permission_request.t =
Permission_request.make
~resource_id:"spotify:album:5SYItU4P7NIwiI6Swug4GE"
~user_id:"user:2pVEM9qgPvPeMslgnGDDOr"
~scopes:[ "listen"; "star"; "playlist/add"; "share" ]
in</p>
<p>match Permission_request.request_access req with
| Ok res ->
Permission_request.with_resource res Album.print;
let album = Permission_request.get res in
Album.print album;
| Error res ->
print_string (Permission_request.reason res)<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Pretty neat, right?<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->For completeness sake, here's our <!-- CommonMark raw HTML omitted -->Permission_request<!-- CommonMark raw HTML omitted --> module:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->module Permission_request = struct
type id = string
type scope = string
type 'resource granted = { resource : 'resource }
type denied = { reason : string }
type requested = { scopes : scope list }</p>
<p>type ('state, 'resource) t = {
(* the state of the permission request <em>)
state : 'state;
(</em> other shared metadata *)
resource_id : id;
user_id : id;
}</p>
<p>let make ~resource_id ~user_id ~scopes =
{ state = { scopes }; resource_id; user_id }</p>
<p>(* TODO(@you): you can implement here the logic for checking</p>
<ul>
<li>if you actually have permissions for this request :)
*)
let run_request : (requested, 'resource') t -> ('resource, string) result =
fun _t -> Error "unimplemented!"</li>
</ul>
<p>let request_access t =
match run_request t with
| Ok resource -> Ok { t with state = { resource } }
| Error reason -> Error { t with state = { reason } }</p>
<p>let reason { state = { reason }; _ } = reason
let with_resource { state = { resource }; _ } fn = fn resource
let get { state = {resource}; _ } = resource
end<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Conclusions: Type-state is Great<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Type-state is just another tool in your bat-belt to build great APIs with type-safety, and good ergonomics.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->It has a cost, like everything else, but <!-- CommonMark raw HTML omitted -->it enables you to grow your states<!-- CommonMark raw HTML omitted --> and maintain them separately by using submodules, in a very natural way. After all they are different types!<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->I picked up this pattern from Rust libraries that model the state of sockets, database connections, and many other things, by doing exactly the same thing. Of course, having <!-- CommonMark raw HTML omitted -->traits<!-- CommonMark raw HTML omitted --> in Rust means we can extend the methods for a specific type-state, which means narrowing down even further the information you have to process when you go type <!-- CommonMark raw HTML omitted -->req.<!-- CommonMark raw HTML omitted --> and get the autocompletion list.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->But at least in OCaml we can implement the pattern safely and maybe with time our autocompletion will get smarter and do the same filtering for us!<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->That's it. That's type-states for OCaml.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Have you implemented typed state machines in some other ways? Have anything to add or challenge? I'd love to hear it! <!-- CommonMark raw HTML omitted -->Join the x.com thread<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Happy Cameling! 🐫<!-- CommonMark raw HTML omitted --></p>
https://practicalocaml.com/how-to-build-type-safe-state-machines-using-type-state/How to build type-safe State Machines using type-state2023-08-29T10:29:59-00:00Practical OCaml<!-- CommonMark HTML block omitted -->
<p>let get : 'x validation -> 'x =
function
| Pending x -> x
| Valid x -> x
| Invalid (x, _) -> x</p>
<p>let errors : 'x validation -> string option =
function
| Invalid (_, err) -> Some err
| _ -> None</p>
<p>let is_valid : 'x validation -> bool =
function
| Valid _ -> true
| _ -> false<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->You can imagine how we'll have to check every time we want to open up a validation, to see if its pending, valid, or invalid. This means other devs will have to remember to check if the validation passed before using the value.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->I don't know about you but I'm 100% certain I will forget to do that at least once.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->GADTs can help us here to reduce the space of all the possible types that our variant constructors create. <!-- CommonMark raw HTML omitted -->Right now, we can essentially create any <!-- CommonMark raw HTML omitted --><type> validation<!-- CommonMark raw HTML omitted --> by just passing the right value to the constructors. But we could change that, so that you can statically check a value has passed, is pending, or has failed validation. Our new GADT could look like this:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->(* we'll make some abstract types to use for differentiating
the validation states *)
type pending
type failed
type valid</p>
<p>(* our new validation GADT *)
type _ validation =
| Pending: 'thing -> pending validation
| Valid: 'thing -> valid validation
| Failed: 'thing * string -> failed validation<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->This means that our functions can have restricted type signatures and smaller implementations. The compiler now knows that there is only one possible type that matches the <!-- CommonMark raw HTML omitted -->Valid<!-- CommonMark raw HTML omitted --> constructor, so we can't consider the others.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->let make x = Pending x</p>
<p>let get (Valid x) = x</p>
<p>let errors (Fail (<em>, err)) = err<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Great! The downside is that this code doesn't actually type-check. You can't pattern-match and get a value out of <!-- CommonMark raw HTML omitted -->Valid x<!-- CommonMark raw HTML omitted --> because the compiler "forgot" what type that value had. Let me show you what I mean. This function:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->let get (Valid x) = x<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Fails to type with this error:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->File "lib/gadt.ml", line 18, characters 20-21:
18 | let get (Valid x) = x
^
Error: This expression has type $Valid</em>'thing
but an expression was expected of type 'a
The type constructor $Valid_'thing would escape its scope<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->And the type of x in the error is <!-- CommonMark raw HTML omitted -->$Valid_'thing<!-- CommonMark raw HTML omitted -->, which is a weird type. The compiler yells that it would escape its scope. That's how OCaml tells us <!-- CommonMark raw HTML omitted -->"Hey I know there should be a type here but I...erhm...don't know anymore what that type <em>actually</em> was. So, yeah, can't let you use it. Sorry"<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->So how does one get this value out?<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Turns out that while the compiler won't let this type <!-- CommonMark raw HTML omitted -->escape<!-- CommonMark raw HTML omitted -->, if you put many things together inside the same constructor, <!-- CommonMark raw HTML omitted -->it will remember if the type was the same across all of them<!-- CommonMark raw HTML omitted -->. For example, the compiler is completely happy here:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->(* we introduce a function in our Valid arguments *)
type 'validity validation =
| Valid: 'thing * ('thing -> bool) -> valid validation
| ...</p>
<p>let get_that_bool (Valid (x, fn)) = fn x <!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->because it understands that once you pack together a <!-- CommonMark raw HTML omitted -->'thing<!-- CommonMark raw HTML omitted --> and a <!-- CommonMark raw HTML omitted -->'thing -> bool<!-- CommonMark raw HTML omitted -->, then it's the same <!-- CommonMark raw HTML omitted -->'thing<!-- CommonMark raw HTML omitted -->. So this will work for any type. And that's both quite powerful and also super non-obvious at first. Like, what is this useful for? <!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->GADTs can help us hide type information, but still be able to use it later. <!-- CommonMark raw HTML omitted -->In <!-- CommonMark raw HTML omitted -->the last issue of Practical OCaml<!-- CommonMark raw HTML omitted --> we created a <!-- CommonMark raw HTML omitted -->route<!-- CommonMark raw HTML omitted --> type for our web router that uses this pattern to hide the types that different route-handler functions use as inputs, and it lets us put together into a single list, a bunch of routes that have type-safe parameters/body parsing. Pretty cool. <!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Anyways, back to our question, to get our Valid value out, we will need to either:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->let the value <!-- CommonMark raw HTML omitted -->escape<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->or turn it into a type that is known outside the GADT, like include a <!-- CommonMark raw HTML omitted -->'thing -> string<!-- CommonMark raw HTML omitted --> function so we can always just call that function to turn our <!-- CommonMark raw HTML omitted -->'thing<!-- CommonMark raw HTML omitted --> into a string and return a string<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->We want to preserve the type of our value, so we're gonna do the first. Letting our value escape means actually putting <!-- CommonMark raw HTML omitted -->'thing<!-- CommonMark raw HTML omitted --> in the return type of our constructors. Like this:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->type _ validation =
| Valid: 'thing -> (valid * 'thing) validation
| ...<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->That's actually all we need. Now the compiler can infer the signature of our <!-- CommonMark raw HTML omitted -->get<!-- CommonMark raw HTML omitted --> function is <!-- CommonMark raw HTML omitted -->(valid * 'thing) validation -> 'thing<!-- CommonMark raw HTML omitted -->, and it lets us take that <!-- CommonMark raw HTML omitted -->'thing<!-- CommonMark raw HTML omitted --> out. BAM. Done.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->And yet our validation solution still doesn't help us actually validate anything. We don't have a function that goes from pending to valid, or from pending to invalid. Since our <!-- CommonMark raw HTML omitted -->Pending<!-- CommonMark raw HTML omitted --> variant doesn't know what a <!-- CommonMark raw HTML omitted -->'thing<!-- CommonMark raw HTML omitted --> is, it also doesn't know how to validate it. We'll start there:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->(* we added a <code>fn</code> to our Pending constructor *)
type _ validation =
| Pending: 'thing * ('thing -> bool) -> pending validation
| ...</p>
<p>let validate (Pending (x, fn)) =
if fn x
then Valid x
else Invalid (x, "invalid value!")<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->We run the compiler, and see the same issue as before: <!-- CommonMark raw HTML omitted -->Valid x<!-- CommonMark raw HTML omitted --> would have type <!-- CommonMark raw HTML omitted -->$Pending_'thing<!-- CommonMark raw HTML omitted -->, because our Pending variant doesn't really expose it's internal <!-- CommonMark raw HTML omitted -->'thing<!-- CommonMark raw HTML omitted --> type... yadda yadda...we can fix that too by letting <!-- CommonMark raw HTML omitted -->'thing<!-- CommonMark raw HTML omitted --> escape:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->type _ validation =
| Pending: 'thing * ('thing -> bool) -> (pending * 'thing) validation
| ...<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Aaaand now we run into another issue. Oof. <!-- CommonMark raw HTML omitted -->Valid x<!-- CommonMark raw HTML omitted --> and <!-- CommonMark raw HTML omitted -->Invalid (x, "invalid value!")<!-- CommonMark raw HTML omitted --> have different types 🙈 – this is a very common "dead end".<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->For now, we are going to wrap 'em up in a <!-- CommonMark raw HTML omitted -->result<!-- CommonMark raw HTML omitted --> and it will push the problem to future you and me:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->let validate (Pending (x, fn)) =
if fn x
then Ok (Valid x)
else Error (Invalid (x, "invalid value!"))<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->So now we can use our Extremely Type-Safe Validation Lib:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->let _ =
let user_value = make 2113 (fun x -> x > 0) in
match validate user_value with
| Ok value ->
let age = get value in
print_int age;
| Error err ->
let err = errors err in
print_string err;
<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Hopefully implementing this has shown some of the reasons why GADTs while powerful are rather painful to work with. <!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->For completeness's sake here's the full code:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->type valid
type invalid
type pending</p>
<p>type _ validation =
| Pending : 'thing * ('thing -> bool) -> (pending * 'thing) validation
| Valid : 'thing -> (valid * 'thing) validation
| Invalid : 'thing * string -> invalid validation</p>
<p>let make x fn = Pending (x, fn)
let get (Valid x) = x
let errors (Invalid (_, err)) = err</p>
<p>let validate (Pending (x, fn)) =
if fn x then Ok (Valid x) else Error (Invalid (x, "invalid value!"))<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Conclusion: You Don't Need GADTs<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Truth is that unless you are Jane Street and <!-- CommonMark raw HTML omitted -->need to optimize the hell out of your compact arrays<!-- CommonMark raw HTML omitted -->, or <!-- CommonMark raw HTML omitted -->are writing a toy λ-calculus interpreter<!-- CommonMark raw HTML omitted -->, you're probably better off without them.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->GADTs can be super useful if you need to:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->hide type information<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->restrict the kind of types that can be instantiated<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->have more control over the relation between the input and return type of a function<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->But GADTs are not only hard to pronounce, they also come with a host of problems. The ones we've seen, and some more that we haven't that need solutions with wizardly names like <!-- CommonMark raw HTML omitted -->locally abstract types <!-- CommonMark raw HTML omitted -->or <!-- CommonMark raw HTML omitted -->polymorphic recursion.<!-- CommonMark raw HTML omitted --> Learning about this is fun and great, but sometimes can get in the way of shipping without substantially improving the quality of your product or developer experience.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->So stick to simpler types until you run into one of those 3 problems and I promise you you'll be a productive, happy camelid 🚀<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Have you implemented typed state machines in some other ways? Have anything to add or challenge? I'd love to hear it! <!-- CommonMark raw HTML omitted -->Join the x.com thread<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Happy Cameling! 🐫<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Thanks to <!-- CommonMark raw HTML omitted -->@patricoferris<!-- CommonMark raw HTML omitted --> for pointing out that if you do implement the above pattern, but move outside the current module (for ex. have a submodule for your <!-- CommonMark raw HTML omitted -->valid<!-- CommonMark raw HTML omitted -->, <!-- CommonMark raw HTML omitted -->invalid<!-- CommonMark raw HTML omitted -->, <!-- CommonMark raw HTML omitted -->pending<!-- CommonMark raw HTML omitted --> types), you may run into some undecidability problems that make pattern-matching non-exhaustive. Oof, many words. The gist is, if you see a "This pattern is non-exhaustive" error, try adding a private constructor to your type-tags:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->type valid = private | Valid_tag
type invalid = private | Invalid_tag
type pending = private | Pending_tag<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->For a more detailed answer, check out this <!-- CommonMark raw HTML omitted -->OCaml forum post<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --></p>
https://practicalocaml.com/a-quick-guide-to-gadts-and-why-you-aint-gonna-need-them/A quick guide to GADTs and why you ain't gonna need them2023-08-28T13:46:43-00:00Practical OCaml<!-- CommonMark HTML block omitted -->
https://practicalocaml.com/how-i-explore-domain-problems-faster-and-cheaply-in-ocaml/How I explore domain problems cheaply and fast with OCaml: modeling a web router2023-08-24T13:29:21-00:00Practical OCaml<!-- CommonMark HTML block omitted -->
https://practicalocaml.com/hello-world/{ hello = `world; }2023-08-23T00:30:16-00:00Practical OCamlhttps://medium.com/@playersrebirth/building-the-ocaml-gpt-library-650c00b4d72bBuilding the OCaml GPT library2023-08-22T06:32:00-00:00Pizie Dust<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2023-08-17-your-programming-language-and-its-impact-on-the-cybersecurity-of-your-applicationYour Programming Language and its Impact on the Cybersecurity of Your Application2023-08-17T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
https://signals-threads.simplecast.com/episodes/a-poets-guide-to-product-management-with-peter-bogart-johnson-_sAIFzsSA Poet's Guide to Product Management with Peter Bogart-Johnson2023-08-15T13:42:13-00:00Signals and Threads<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.08.15.htmlOCaml Weekly News, 15 Aug 20232023-08-15T12:00:00-00:00Caml Weekly News<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
http://math.andrej.com/2023/08/13/on-indenfinite-truth-values/On indefinite truth values2023-08-12T22:00:00-00:00Andrej Bauer<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Get Busy Waiting<!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2023-08-10-kcas-building-a-lock-free-stm-for-ocaml-2-2Kcas: Building a Lock-Free STM for OCaml (2/2)2023-08-10T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.08.08.htmlOCaml Weekly News, 08 Aug 20232023-08-08T12:00:00-00:00Caml Weekly News<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2023-08-07-kcas-building-a-lock-free-stm-for-ocaml-1-2Kcas: Building a lock-free STM for OCaml (1/2)2023-08-07T00:00:00-00:00Tarideshttps://dev.to/burnleydev/outreachy-mid-point-progress-ea5Outreachy Mid-Point Progress2023-08-04T00:00:00-00:00Abongwa Bonalais<p><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Introduction<!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2023-08-02-obuilder-on-macosOBuilder on macOS2023-08-02T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.08.01.htmlOCaml Weekly News, 01 Aug 20232023-08-01T12:00:00-00:00Caml Weekly News<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2023-07-31-ocaml-in-space-welcome-spaceosOCaml in Space - Welcome SpaceOS!2023-07-31T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
http://math.andrej.com/2023/07/28/variations-on-weihrauch-degrees/Variations on Weihrauch degrees (CiE 2023)2023-07-27T22:00:00-00:00Andrej Bauer<p><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Introduction<!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2023-07-27-reflections-on-the-mirageos-retreat-in-moroccoReflections on the MirageOS Retreat in Morocco2023-07-27T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.07.25.htmlOCaml Weekly News, 25 Jul 20232023-07-25T12:00:00-00:00Caml Weekly Newshttps://medium.com/@aryangodara_19887/udp-client-and-server-in-ocaml-e203116a997cCreating a UDP server and client in OCaml2023-07-20T00:00:00-00:00Aryan Godarahttps://medium.com/@aryangodara_19887/setting-up-opam-and-mirageos-on-macos-ventura-on-apple-silicon-57819069991aSetting up Opam and MirageOS on MacOS Ventura, on Apple Silicon2023-07-20T00:00:00-00:00Aryan Godara<p><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Introduction<!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2023-07-19-sandmark-boosting-multicore-projects-with-performance-benchmarkingSandmark: Boosting Multicore Projects with Performance Benchmarking2023-07-19T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
http://math.andrej.com/2023/07/19/continuity-principles-and-the-klst-theorem/Continuity principles and the KLST theorem2023-07-18T22:00:00-00:00Andrej Bauer<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.07.18.htmlOCaml Weekly News, 18 Jul 20232023-07-18T12:00:00-00:00Caml Weekly Newshttps://frama-c.com/fc-versions/cobalt.htmlRelease of Frama-C 27.1 (Cobalt)2023-07-18T00:00:00-00:00Frama-C<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2023-07-12-ocaml-ci-renovatedOCaml-CI Renovated2023-07-12T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.07.11.htmlOCaml Weekly News, 11 Jul 20232023-07-11T12:00:00-00:00Caml Weekly News<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2023-07-07-making-ocaml-5-succeed-for-developers-and-organisationsMaking OCaml 5 Succeed for Developers and Organisations2023-07-07T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
https://blog.janestreet.com/were-sponsoring-some3/We're sponsoring SoME32023-07-06T00:00:00-00:00Jane Street Tech Blog<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
http://cambium.inria.fr/blog/florian-compiler-weekly-2023-07-05Florian's OCaml compiler weekly, 5 July 20232023-07-05T08:00:00-00:00GaGallium<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2023-07-05-zero-day-attacks-what-are-they-and-can-a-language-like-ocaml-protect-youZero-Day Attacks: What Are They, and Can a Language Like OCaml Protect You?2023-07-05T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.07.04.htmlOCaml Weekly News, 04 Jul 20232023-07-04T12:00:00-00:00Caml Weekly News<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
https://ocamlpro.com/blog/2023_06_30_2022_at_ocamlpro2022 at OCamlPro2023-06-30T13:19:46-00:00
Dario Pinto
<!-- CommonMark HTML block omitted -->
https://tech.ahrefs.com/emelletv-talking-with-louis-roche%CC%81-about-ocaml-and-ahrefs-7767afbfbdb9?source=rss----303662d88bae--ocamlEmelleTV: Talking with Louis Roché about OCaml and Ahrefs2023-06-29T14:32:40-00:00Ahrefs<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<p>General tests of used binaries</p>
<p>1: compiler help and information ok
2: compiler warnings ok
3: compiler outputs (general) ok
4: compiler outputs (file specified) ok
5: compiler outputs (path specified) ok
6: compiler outputs (assembler) ok
7: source file not found ok
8: temporary path invalid ok
9: use of full path for cobc ok
10: C Compiler optimizations ok
11: invalid cobc option ok
12: cobcrun help and information ok
13: cobcrun validation ok
14: cobcrun -M DSO entry argument ok
15: cobcrun -M directory/ default ok
[...]
<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
https://ocamlpro.com/blog/2023_03_18_autofonceAutofonce, GNU Autotests Revisited2023-06-27T13:19:46-00:00
Fabrice Le Fessant
<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.06.27.htmlOCaml Weekly News, 27 Jun 20232023-06-27T12:00:00-00:00Caml Weekly News<!-- CommonMark HTML block omitted -->
https://blog.janestreet.com/oxidizing-ocaml-ownership/Oxidizing OCaml: Rust-Style Ownership2023-06-21T00:00:00-00:00Jane Street Tech Blog<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.06.20.htmlOCaml Weekly News, 20 Jun 20232023-06-20T12:00:00-00:00Caml Weekly News<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted -->A few finished tasks<!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
http://cambium.inria.fr/blog/florian-compiler-weekly-2023-06-20Florian's OCaml compiler weekly, 20 June 20232023-06-20T08:00:00-00:00GaGallium<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2023-06-20-ocaml-receives-the-acm-programming-languages-software-awardOCaml Receives the ACM SIGPLAN Programming Languages Software Award2023-06-20T00:00:00-00:00Tarides%20https://frama-c.com/fc-versions/cobalt.html%20Release of Frama-C 27.0 (Cobalt)2023-06-15T00:00:00-00:00Frama-C<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
http://math.andrej.com/2023/06/15/types-2023-isomorphism-invariance-and-isomorphism-reflection/Isomorphism invariance and isomorphism reflection in type theory (TYPES 2023)2023-06-14T22:00:00-00:00Andrej Bauer<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.06.13.htmlOCaml Weekly News, 13 Jun 20232023-06-13T12:00:00-00:00Caml Weekly Newshttps://medium.com/@aryangodara_19887/first-week-at-outreachy-54f4af71820fFirst week experience at Outreachy2023-06-13T00:00:00-00:00Aryan Godarahttps://dev.to/burnleydev/outreachy-blog-1-introduce-yourself-3794Outreachy Blog #1: Introduce Yourself2023-06-13T00:00:00-00:00Burnleydev1<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted -->My roadmap for 5.2.0<!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
http://cambium.inria.fr/blog/florian-compiler-weekly-2023-06-12Florian's OCaml compiler weekly, 12 June 20232023-06-12T08:00:00-00:00GaGallium<p>Neologisms for the current computing era.</p>
https://erratique.ch/writings/anti-personnel-computingAnti-personnel computing2023-06-11T14:13:42-00:00Daniel Bünzli<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.06.06.htmlOCaml Weekly News, 06 Jun 20232023-06-06T12:00:00-00:00Caml Weekly News<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted -->OCaml 5.1.0 second alpha
release:<!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
http://cambium.inria.fr/blog/florian-compiler-weekly-2023-05-06Florian's OCaml compiler weekly, 5 June 20232023-06-05T08:00:00-00:00GaGallium<p>We are pleased that opam 2.1.5 has hit the road, since it contains a security fix since the local cache is considered trusted, and not all checksums are verified.</p>
<p>Opam uses a download cache since 2.0.0: if a source artifact is needed, first its hash is looked up in the local cache (<code>~/.opam/download-cache/<hash-algorihm>/<hash></code>). Opam supports multiple hash algorithms, a cache lookup goes through all hash algorithms present in the opam file to build, unpack, or install. Before 2.1.5, the hash algorithm that lead to the cache hit was not checked (but all others were).</p>
<p>If a package specifies only a single (non-weak) hash algorithm, this lead to the source artifact taken as is, any error while writing the artifact into the cache, or reading it from the cache, was not detected. Also, in certain setups, if the download cache is shared (writable) across containers (for example in some CI systems), this leads to the possibility of cache poisoning.</p>
<p>Thanks to Raja and Kate, the issue was fixed in <a href="https://github.com/ocaml/opam/pull/5538">PR 5538</a></p>
<p>The timeline of this issue is as follows:</p>
<ul>
<li>Feb 23rd 2023 conducted black-box security audit of opam</li>
<li>Feb 24th 2023 reported to the opam team</li>
<li>Feb 27th 2023 video meeting with the opam team, explaining the issue further</li>
<li>Mar 27th 2023 initial review meeting of the patches developed by the opam team</li>
<li>May 9th 2023 public PR fixing the issue discovered</li>
<li>May 25th 2023 release of opam 2.1.5</li>
</ul>
<p>Why we are interested in the security of opam? We plan to improve the supply chain security for opam, and develop <a href="https://github.com/hannesm/conex">conex</a>. While developing conex, we validate the assumptions conex uses about opam. We did that in February 2023 with opam 2.1.2, and reported the missed assumptions to the opam development team.</p>
<p>As methodology we used a blackbox-testing, i.e. we used the opam binary for installing packages from a custom opam repository. We did not study the source code of opam extensively, neither did we exhaustively check opam: we only tested the assumptions that came to our mind while working on conex.</p>
<p>The collaborative work with the opam development team was great, they were open to our reporting and answered quickly. We have no knowledge of this issue being exploited in the wild - on some systems, the <a href="https://opam.ocaml.org/doc/FAQ.html#What-changes-does-opam-do-to-my-filesystem">opam sandbox</a> avoids writing to the download-cache from within the opam file.</p>
https://ocaml.org/blog/opam/opam-2-1-5-local-cacheSecurity in opam's cache handling (before 2.1.5)2023-05-31T00:00:00-00:00ReynirHannes<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.05.30.htmlOCaml Weekly News, 30 May 20232023-05-30T12:00:00-00:00Caml Weekly News<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
http://cambium.inria.fr/blog/two-variants-of-the-bind-ruleTwo variants of the Bind rule2023-05-30T08:00:00-00:00GaGallium<!-- CommonMark HTML block omitted -->
https://blog.janestreet.com/oxidizing-ocaml-locality/Oxidizing OCaml: Locality2023-05-26T00:00:00-00:00Jane Street Tech Bloghttps://stackoverflow.blog/2023/05/23/for-those-who-just-dont-git-it-ep-573For those who just don’t Git it2023-05-23T21:04:40-00:00Stack Overflow Blog<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.05.23.htmlOCaml Weekly News, 23 May 20232023-05-23T12:00:00-00:00Caml Weekly News<!-- CommonMark HTML block omitted -->
https://signals-threads.simplecast.com/episodes/the-future-of-programming-with-richard-eisenberg-pOktpZ_eThe Future of Programming with Richard Eisenberg2023-05-18T15:15:49-00:00Signals and Threads<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.05.16.htmlOCaml Weekly News, 16 May 20232023-05-16T12:00:00-00:00Caml Weekly Newshttps://www.backendbanter.fm/episodes/001-elegance-in-ocaml-with-tj-devriesElegance in OCaml with TJ DeVries2023-05-16T03:04:13-00:00Backend Banter%20https://frama-c.com/fc-versions/cobalt.html%20Beta release of Frama-C 27.0~beta (Cobalt)2023-05-16T00:00:00-00:00Frama-C<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted -->Specifying Functions: Two
Styles<!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
http://gallium.inria.fr/blog/function-specs-2023-05-12Specifying Functions: Two Styles2023-05-12T08:00:00-00:00GaGallium<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.05.09.htmlOCaml Weekly News, 09 May 20232023-05-09T12:00:00-00:00Caml Weekly News<p>A little overview of this retreat</p>
https://blog.osau.re/articles/mirageos_retreat.htmlThe MirageOS retreat (01/05/2023)2023-05-05T10:00:00-00:00Romain Calascibetta<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2023-05-05-optimising-archive-node-storage-for-tezosOptimising Archive Node Storage for Tezos2023-05-05T00:00:00-00:00Tarides<p><!-- CommonMark raw HTML omitted -->OCaml, all the way down<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Photo by <!-- CommonMark raw HTML omitted -->Lance Grandahl<!-- CommonMark raw HTML omitted --> on <!-- CommonMark raw HTML omitted -->Unsplash<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Some history<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->In 2021, we decided to evaluate <!-- CommonMark raw HTML omitted -->Melange<!-- CommonMark raw HTML omitted --> as an alternative to <!-- CommonMark raw HTML omitted -->ReScript<!-- CommonMark raw HTML omitted --> for compiling Ahrefs’ frontend codebase. We wrote about the reasons that led us there, as well as the limitations we encountered at the time, in <!-- CommonMark raw HTML omitted -->a previous article<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->After this experiment, discussions continued inside the team. Switching to a different compiler, which was in a very early stage, involved quite some risk. But so did the continued use of ReScript, which seemed to be diverging further and further away from OCaml.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Finally, in September 2022 (during <!-- CommonMark raw HTML omitted -->ICFP in Ljubljana<!-- CommonMark raw HTML omitted -->), we decided to bite the bullet and kicked off a project to deepen the integration between <!-- CommonMark raw HTML omitted -->Dune<!-- CommonMark raw HTML omitted --> (OCaml’s most used build system) and Melange. This better integration was the key to solve two of the three limitations we had encountered during our initial exploration of Melange:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Build speed would increase due to less work needed to parse dune files, and more efficient rules planning and execution.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Developer ergonomics would get better, as Melange would become a first-class citizen in Dune, with concepts like Dune <!-- CommonMark raw HTML omitted -->libraries<!-- CommonMark raw HTML omitted --> and other stanzas becoming available to Melange users.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Ahrefs’ leadership backed the project and agreed to financially support the development of this tighter integration. With this support, we set about building a team that included Rudi Grinberg, who maintains Dune as part of its development team, and Antonio Monteiro, who created Melange and is also part of the Dune development team.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Heads down<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->During the following months, we focused on two tasks, iterating over multiple cycles where the progress on one task would inform the next steps to take for the other:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Evolve Dune to add stanzas, fields, and documentation to support Melange projects.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Migrate Ahrefs’ frontend codebase to use the Melange compiler and Dune, adapt third-party libraries and bindings to Melange, and polish the editor integration, build scripts, and other aspects of the development experience.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->We believe that tackling these two tasks in parallel led us to better results, compared to a more waterfall-based approach. As we applied the changes over Ahrefs’ large-ish frontend codebase — it will soon reach 5000 modules — we kept finding and fixing bugs, improving the ergonomics of the Dune and Melange integration, and in general making the solution more robust, real-world ready, and developer-friendly.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Another upside of the way the project was implemented is that we developed it initially in stealth mode, keeping it quite private. By working on it within a tight-knit team, before making a public release, we could make progress faster. We believe that this approach saved future Melange users a lot of churn and burn caused by the multiple changes in Dune stanza options, Melange flags, and other configurations we changed along the way, as we learned more about this integration.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Migration strategies<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Initially, our plan was to progressively migrate Ahrefs’ code to Melange. As the frontend codebase is divided into different tools, each being self-contained, we thought we could introduce Melange to build one tool, then another tool, gradually migrating them one by one.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->However, this approach turned out to be too complex because configuring a development environment that works on both Melange and ReScript is challenging. As developers could be working on multiple tools during the same week, or even within the same day, we realized that it was unfeasible to reconfigure the environment every time a developer switched from a tool built with Melange to a tool built with ReScript.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Therefore, we changed our minds and opted for a one-shot migration. We would ensure that CI, development, and staging environments were working with Melange and Dune. And we would do this on separate branches, while still using ReScript on our main branch CI and development scripts. Once we were confident everything was building and functioning correctly with Melange, we switched all CI and development scripts to use the Melange and Dune commands. We tried to keep the PR that applied this switch as small as possible, with just a few hundreds of lines of changes so that we could switch back to ReScript if needed. In fact, after a first attempt in March, we had to switch back to ReScript due to some issues on the developer experience side, related to build performance and ergonomics, which took a few more weeks to solve.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->In terms of package management and third-party Melange dependencies, we followed a more gradual approach. Dune is quite flexible when it comes to <!-- CommonMark raw HTML omitted -->vendoring<!-- CommonMark raw HTML omitted -->, so in the initial phase, we downloaded Melange libraries with npm, and had Dune include them in the project as if they were local sources. Now we have started migrating some of these libraries so that we can consume them using opam, the OCaml package manager. This will involve first publishing them in our private opam mirror, but the plan is to have them published in the <!-- CommonMark raw HTML omitted -->public opam repository<!-- CommonMark raw HTML omitted --> in the future so that other Melange developers can also use them.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Timings<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->You may be curious about the performance differences between the previous and current approaches. Measuring performance is tricky, but we attempted to measure a few different scenarios with both setups. The results can be seen below.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Keep in mind that Ahrefs frontend setup has specific characteristics, which affect the performance measurements:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Before migration: Dune generated ml files from atd files, then ReScript build tool bsb built all hand-written source files plus the ones generated from atd files.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->After migration: everything is built with Dune and Melange.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->All measurements were taken on a node with 2x AMD EPYC 7742 cpu @3.2 GHz (nproc=256), 1TB RAM, Debian 11 x86_64 GNU/Linux. The build target is always the entire Ahrefs frontend codebase.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Cold build:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Before: real 0m28.232s, user 9m23.883s, sys 13m33.939s<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->After: real 1m14.208s, user 10m33.708s, sys 5m45.644s<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Warm build<!-- CommonMark raw HTML omitted -->, noop (no file is built):<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Before: real 0m14.687s, user 3m17.058s, sys 3m57.903s<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->After: real 0m21.895s, user 0m20.528s, sys 0m1.372s<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Watch mode, modifying an “edge” file<!-- CommonMark raw HTML omitted --> with almost no reverse dependencies:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Before: 1002ms<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->After: 1576ms<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Watch mode, modifying an “inner” file<!-- CommonMark raw HTML omitted --> belonging to a library, with many reverse dependencies:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Before: 7032ms<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->After: 15394ms<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->In general, Melange and Dune are slower than ReScript for cold builds in our setup. However, the differences are smaller for warm builds. For watch mode, the difference gets reduced when modifying edge files.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->There is room for improvement in the way the Melange and Dune rules are arranged so that cold builds can get faster. For example, delaying some <!-- CommonMark raw HTML omitted -->optimizations in Melange<!-- CommonMark raw HTML omitted --> might allow to parallelize more work.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Conclusions<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->The results so far are quite encouraging. These are some of the things that are possible thanks to the deeper integration between Dune and Melange, and its application within the Ahrefs codebase:<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->The same OCaml compiler is used on both frontend and backend codebases.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Access to all the bug fixes, error improvements, and new features that the OCaml compiler team added between versions 4.06 and 4.14 of the compiler.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->A shared developer environment across teams, including editor extensions, OCaml LSP server, etc. No more need to maintain a different set of tooling for backend and frontend.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Removal of hand-written CI checks that were ensuring different tools in the frontend codebase would not access components from other tools. This is now solved by Dune libraries, and the OCaml compiler will complain if logical units try to reach outside their bounds.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Frontend and backend shared dependencies, such as <!-- CommonMark raw HTML omitted -->anuragsoni/routes<!-- CommonMark raw HTML omitted -->, can now be defined in a single place: an opam file.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Faster rebuilds and better watch mode, as Dune now controls all the build artifacts. Previously, Dune and ReScript were sharing responsibilities, which was leading to unnecessary rebuilds of some artifacts. Or alternatively, rebuilds were not starting when required due to the build system not tracking changes in some subsets of the sources.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Easier <!-- CommonMark raw HTML omitted -->PPX<!-- CommonMark raw HTML omitted --> maintenance, as there is no longer a need to publish pre-built versions of these tools.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Melange allows to run all ppxs <!-- CommonMark raw HTML omitted -->from a single executable file<!-- CommonMark raw HTML omitted -->, which has some nice performance benefits.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->All the other advantages of using Dune: virtual libraries, watch mode, leverage integrations with tools like odoc…<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->What’s next?<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->We are excited about this project becoming a reality, and we believe that the deeper integration between OCaml and Melange through Dune, together with Melange’s ergonomic integration with the JavaScript ecosystem through its bindings, can enable projects that were previously impossible to imagine. For example, full-stack React by hydrating components that are rendered <!-- CommonMark raw HTML omitted -->server-side using native OCaml<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Now, we have to make it easier for other people who are willing to try and use Melange and Dune. So our focus is shifting to documenting how Melange works.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->There is a section for Melange in the Dune manual that will be included in the next stable release, and that can be consulted today in the latest branch: <!-- CommonMark raw HTML omitted -->https://dune.readthedocs.io/en/latest/melange.html<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->The next step will be to design and create a site where everyone can read and learn about what is needed to create and maintain a project using Melange and Dune. This site will include a playground, in the spirit of the <!-- CommonMark raw HTML omitted -->ReasonML one<!-- CommonMark raw HTML omitted -->, so that we can share snippets, see the resulting JavaScript compilation output, and iterate on ideas together.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Besides the above, we have plenty of other things we will be working on in the next months. We will share more information about the roadmap as soon as Dune 3.8 and its respective Melange version are published in the main public opam repository, which should happen in the next weeks.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->How to contribute?<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->If you want to be a part of this, or you want to write or port your libraries to Melange, the best way to do so is by reaching out on the <!-- CommonMark raw HTML omitted -->ReasonML Discord<!-- CommonMark raw HTML omitted -->. There is a #melange dedicated channel where one can get help and advice on how to get started.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Otherwise, if you are missing features, find bugs, or run into confusing errors, please open an issue <!-- CommonMark raw HTML omitted -->in the Melange public repo<!-- CommonMark raw HTML omitted -->.<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->We hope you share our excitement about this update. Our journey to integrate our frontend stack more naturally within the incredible language and ecosystem of OCaml will be well-documented. Stay tuned for further updates in the future!<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Ahrefs is now built with Melange<!-- CommonMark raw HTML omitted --> was originally published in <!-- CommonMark raw HTML omitted -->Ahrefs<!-- CommonMark raw HTML omitted --> on Medium, where people are continuing the conversation by highlighting and responding to this story.<!-- CommonMark raw HTML omitted --></p>
https://tech.ahrefs.com/ahrefs-is-now-built-with-melange-b14f5ec56df4?source=rss----303662d88bae--ocamlAhrefs is now built with Melange2023-05-03T19:06:58-00:00Ahrefs<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.05.02.htmlOCaml Weekly News, 02 May 20232023-05-02T12:00:00-00:00cwn<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted -->A tag for quoting inline
code<!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted -->Backward
compatibility and polymorphic variants<!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
http://gallium.inria.fr/blog/florian-compiler-weekly-2023-04-28Florian's OCaml compiler weekly, 28 April 20232023-04-28T08:00:00-00:00GaGallium<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2023-04-28-ocaml-at-minidebconf-tn-2023OCaml at MinidebConf TN 20232023-04-28T00:00:00-00:00Tarideshttp://frama-c.com/%20/events/2023-04-28-cyberhackathon.html%20Cyberhackathon Frama-C + Binsec2023-04-28T00:00:00-00:00Frama-C<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
https://roscidus.com/blog/blog/2023/04/26/lambda-capabilities/Lambda Capabilities2023-04-26T10:00:00-00:00Thomas Leonard<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.04.25.htmlOCaml Weekly News, 25 Apr 20232023-04-25T12:00:00-00:00cwn<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
http://cambium.inria.fr/blog/florian-compiler-weekly-2023-04-24Florian's OCaml compiler weekly, 24 April 20232023-04-24T08:00:00-00:00GaGallium<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.04.18.htmlOCaml Weekly News, 18 Apr 20232023-04-18T12:00:00-00:00cwn<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted -->First alpha release for
OCaml 5.1.0<!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
http://cambium.inria.fr/blog/florian-compiler-weekly-2023-04-17Florian's OCaml compiler weekly, 17 April 20232023-04-17T08:00:00-00:00GaGallium<!-- CommonMark HTML block omitted -->
https://blog.janestreet.com/building-reproducible-python-environments-with-xars/Building reproducible Python environments with XARs2023-04-14T00:00:00-00:00Jane Street Tech Blog<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.04.11.htmlOCaml Weekly News, 11 Apr 20232023-04-11T12:00:00-00:00cwn<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted -->A branch for OCaml 5.1<!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
http://gallium.inria.fr/blog/florian-compiler-weekly-2023-04-11Florian's OCaml compiler weekly, 11 April 20232023-04-11T08:00:00-00:00GaGalliumhttps://engineering.fb.com/2023/04/06/open-source/buck2-open-source-large-scale-build-system/Build faster with Buck2: Our open source build system2023-04-06T00:00:00-00:00Engineering at MetaChris HopmanNeil Mitchellhttps://sancho.dev/blog/server-side-rendering-react-in-ocamlServer-side rendering React in OCaml2023-04-05T00:00:00-00:00David Sancho<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.04.04.htmlOCaml Weekly News, 04 Apr 20232023-04-04T12:00:00-00:00cwn<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
http://gallium.inria.fr/blog/florian-weekly-2023-04-03OCaml compiler weekly, 3 April 20232023-04-03T08:00:00-00:00gallium<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.03.28.htmlOCaml Weekly News, 28 Mar 20232023-03-28T12:00:00-00:00cwn<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted -->Reviewing github pull
requests<!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
<p><!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted -->Better manual reference
in error message<!-- CommonMark raw HTML omitted --><!-- CommonMark raw HTML omitted --></p>
<!-- CommonMark HTML block omitted -->
<!-- CommonMark HTML block omitted -->
http://gallium.inria.fr/blog/florian-compiler-weekly-2023-03-27OCaml compiler weekly, 27 March 20232023-03-27T08:00:00-00:00gallium<!-- CommonMark HTML block omitted -->
https://tarides.com/blog/2023-03-22-compiler-hacking-in-cambridge-is-backCompiler Hacking in Cambridge is Back!2023-03-22T00:00:00-00:00Tarides<!-- CommonMark HTML block omitted -->
https://alan.petitepomme.net/cwn/2023.03.21.htmlOCaml Weekly News, 21 Mar 20232023-03-21T12:00:00-00:00cwn