OCaml Weekly News

Previous Week Up Next Week

Hello

Here is the latest OCaml Weekly News, for the week of May 09 to 16, 2023.

Table of Contents

Rendering React in OCaml

David Sancho announced

Here is server-reason-react, the OCaml implementation of React I have been working on: https://sancho.dev/blog/server-side-rendering-react-in-ocaml

The blog post is targeted for a Frontend/JS dev, but I believe it can be interesting from the OCaml site as well.

server-reason-react is an implementation of react-dom/server and some of React’s internals in OCaml. The purpose is to render HTML markup from the server for a Reason React application natively.

fa3544e3ce933ded735ac9e77c570cff3f1870f5_2_1380x814.jpeg

It supports hydration (renderToString) and full render (renderToStaticMarkup) and most unit tests from ReactDOMServer are migrated as well. Basically, to ensure hydration “hacks” work the same way as react’s DOM (in JavaScript).

It’s obviously fast, talking about req/s: x10 against Node and x6 against Bun on the same codebase. Performance is not the priority, though. I did 0 perf work but is cool. If you want to help making it very fast, let me know!

The priority is to implement streaming and later RSC. Can’t wait to try OCaml multicore with Server components.

All of this is thanks to Melange, and I’m grateful to work with @_anmonteiro and @javierwchavarri.

Ahrefs is Hiring

benmonopoli announced

As always here at Ahrefs we’re on the lookout for OCaml devs.

We are headquartered in Singapore but our team is dotted all over the place so we’re open to remote too.

Check out our posting here

Feel free to reach out for more info.

Louis Roché then added

To try to give some context as the job post on the website is pretty dry

Ahrefs is heavily invested in Melange to compile ocaml to javascript. With it the company is also putting resources to maintain the projects related to reasonml. Some recent posts from @jchavarri and @davesnx:

A bunch of commonly used libraries that you probably have heard about are maintained by ahrefs or with the help of ahrefs

There’s more at https://github.com/ahrefs

When not maintaining we try to contribute. One example is ocaml-lsp

We are also sponsoring projects:

Conferences:

(also the reasonml conferences in the past)

And last but not least the OCaml Software Foundation https://ocaml-sf.org/

tmx: Import 2D game maps with ease

fishyfriend announced

tmx is an OCaml library for reading data files from the 2D game map editor Tiled.

The library aims for broad coverage of Tiled’s TMX file formats. It provides an imperative context for loading TMX data files and a collection of immutable types corresponding to TMX data structures.

tmx emulates the semantics of TMX data structures as they exist in the Tiled desktop application, including proper application of custom property inheritance and object templates. This allows the attributes of game resources in OCaml to match exactly what is observed in the editor.

Check out the project page for more.

Brr 0.0.5, the WebGPU edition

Daniel Bünzli announced

There’s a new release of Brr. Brr is an ISC licenced toolkit for programming browsers with the js_of_ocaml compiler.

The highlight of this release is support for the new WebGPU API that is gradually being rolled out in browsers. You can find it in the Brr_webgpu.Gpu module – the binding is large and has been little tested so far, early adopters may run into glitches. But the 250 lines example to render the usual triangle works.

The release notes have the other changes.

The WebGPU binding work was supported by a grant from the OCaml Software Foundation. A big thank to my donators aswell, I welcome and thank a new private donator.

A bestiary of GADT examples?

Chet Murthy asked

Is there someplace a bestiary of GADT examples ? I’d like to find such a thing in order to more-fully understand the universe of possibilities for using GADTs in programming. I’ve never used ’em, and while, sure, reading about the theory is great, and reading a few example is cool, it would be complementary to have a bottom-up understanding (lots of examples) as well as a top-down one.

Yawar Amin replied

We do seem to have a home-grown ’GADT’-iary: https://discuss.ocaml.org/t/open-source-projects-using-gadts/9640

A couple of new and interesting ones since that thread:

Kiran Gopinathan also replied

I haven’t got round to properly publicising it, but I actually wrote blog post about the internal development process of Petrol, and how I gradually moved from Caqti, to macros, to GADTs which may be useful:

https://gopiandcode.uk/logs/log-ways-of-sql-in-ocaml.html

Armael also replied

Not exactly examples of GADTs “in the wild”, but I’ve found @yallop ’s slides (from the Advanced Functional Programming course at Cambridge) to be interesting for seeing “GADT design patterns”: https://www.cl.cam.ac.uk/teaching/1617/L28/lecture-8-slides.pdf , https://www.cl.cam.ac.uk/teaching/1617/L28/lecture-9a-slides.pdf. (I hope it is OK to link those here!)

Gaëtan Gilbert also replied

We use a lot of GADTs in Coq For instance https://github.com/coq/coq/blob/14946eb0cbce09c1a63d36aac21ccb1161fbd869/plugins/ltac2/tac2ffi.ml#L16-L18 used to have arbitrary-arity functions Slightly simplified:

type ('arg,'result,'f) arity =
  | One : ('arg, 'result, 'arg -> 'result) arity
  | More : ('arg, 'result, 'f) arity -> ('arg, 'result, 'arg -> 'f) arity

type ('arg, 'result) nary = Nary : ('arg, 'result, 'f) arity * 'f -> ('arg, 'result) nary

type value =
  | Closure of (value, value) nary
  | SomeInt of int

let to_nary = function
  | Closure f -> f
  | SomeInt _ -> failwith "can't apply someint"

let rec apply : type f. (value,value,f) arity -> f -> value list -> value =
  fun arity f args -> match args, arity with
  | [], _ -> Closure (Nary (arity, f))
  | [arg], One -> f arg
  | arg :: args, More arity -> apply arity (f arg) args
  | arg :: args, One ->
    let f = f arg in
    let Nary (arity, f) = to_nary f in
    apply arity f args

let apply_val f args =
  let Nary (arity, f) = to_nary f in
  apply arity f args

let addf x y = match x, y with
  | SomeInt x, SomeInt y -> SomeInt (x + y)
  | _ -> failwith "addf got non-ints"

let addval =
  Closure (Nary (More One, addf))

let addval' =
  Closure (Nary (One, fun x -> Closure (Nary (One, fun y -> addf x y))))

let () = assert
  (apply_val addval [SomeInt 1; SomeInt 2] =
   apply_val addval' [SomeInt 1; SomeInt 2])

let () = assert
  (apply_val addval [SomeInt 1; SomeInt 2] =
   SomeInt 3)

Or https://github.com/coq/coq/blob/14946eb0cbce09c1a63d36aac21ccb1161fbd869/engine/evd.ml#L208-L230 a record where some fields are nontrivial if and only if some other field is nontrivial

or around https://github.com/coq/coq/blob/14946eb0cbce09c1a63d36aac21ccb1161fbd869/gramlib/grammar.ml#L201 which replaced some Obj.magic in the camlp5 engine this file is derived from.

I guess you can find more by looking at https://github.com/search?q=repo%3Acoq%2Fcoq+GADT&type=commits

Anton Bachin also replied

'a Lwt.t promise states and several other types in Lwt are internally GADTs. See https://github.com/ocsigen/lwt/blob/cc05e2bda6c34126a3fd8d150ee7cddb3b8a440b/src/core/lwt.ml#L321-L340. This is mainly to use the existential types capability of GADTs.

Calascibetta Romain also replied

You can also check a protocol implementation with GADT here (which proves that a client should never send something to another client): https://github.com/dinosaure/bob/blob/main/lib/state.ml. A detailled article is available here: https://blog.osau.re/articles/gadt_and_state_machine.html

Also, I re-implemented a printf function with a promotion mechanism of certains values (à la C) here: https://github.com/mirage/conan/blob/main/src/fmt.ml. You can also check the implementation of the decision tree which helps us to regognize MIME type, it’s a GADT too: https://github.com/mirage/conan/blob/main/src/tree.ml#L10.

Finally, you can check this typed lambda calculus: https://github.com/mirage/mirage-lambda/blob/a89b265b552f8b63ff725fc942f41a276fabb4f5/src/typedtree.ml#L436 and the transformation from a simple lambda-calculus with a typed one (and where we prove that variables are bounds via the De-Bruijn indice).

EDIT: Ah and probably the most complicated GADT I ever see which has a real application, a zipper on an AST where the path is a GADT.

Emile Trotignon also replied

Menhir generates code with gadts using the method described in this paper

In that case, the specific technique used is ADTs without allocation, of which a more simple example is the following :

type 'a number =
  | Float : float number
  | Int : int number

let show_number : type n. n number -> n -> string =
  fun witness n ->
    match witness with
    | Float -> string_of_float n
    | Int -> string_of_int n

zapashcanon also replied

In owi, to allow the user to define host functions usable from Wasm, we also use GADTs.

Jean Christophe Filliatre also replied

Arthur Wendling (Tarides) has an implementation of Kaplan/Tarjan 99 (Purely Functional, Real-Time Deques with Catenation), which makes a non-trivial use of OCaml’s GADT. See https://github.com/art-w/deque

Open-source tool to make a static blog in OCaml?

deep in this thread, roddy said

My tool finch meets most of these requirements. I think it is much more Hugo/Jekyll-like than YOCaml or Soupault. It should be easy for you to add any features you need, it’s <600 lines of straightforward OCaml.

Two examples of its use are its documentation and my meagre website.

BER MetaOCaml N114, for OCaml 4.14.1

Oleg announced

BER MetaOCaml N114 is a strict superset of OCaml 4.14.1 for ``writing programs that generate programs’’. BER MetaOCaml adds to OCaml the type of code values (denoting ``program code’’, or future-stage computations), and two basic constructs to build them: quoting and splicing. The generated code can be printed, stored in a file – or compiled and linked-back to the running program, thus implementing run-time code optimization. A subset of the generated OCaml code can also be converted to C, via offshoring. (The generated C needs no particular runtime or GC.) A well-typed BER MetaOCaml program generates only well-scoped and well-typed programs: The generated code shall compile without type errors. Staging-annotation–free BER MetaOCaml is identical to OCaml; BER MetaOCaml can link to any OCaml-compiled library (and vice versa).

The main changes in version N114 are

  • smoothing the path for the possible future integration into OCaml;
  • starting and almost finishing the complete solution to the long-standing CSP problem;
  • complete support for offshoring

The problems of syntax are said to command the most discussion. This message is no exception. In MetaOCaml, code to be generated is enclosed in brackets: .<1 + 2>. (which may contain `holes’, to be filled with code: fun h -> .<1 + .~h>. where .~, analogous to unquotation in Lisp, is called escape). Although `.<’ and `.~’ are not valid in OCaml and hence can’t be confused, `>.’ is a a valid OCaml operator (and so are the operators that start with that character sequence, like `>..’ and `>.>.’). In fact, there are some libraries that do define the operator `>.’ and which therefore cannot be used in MetaOCaml code. Version N114 introduces an adaptive lexer, which treats `>.’ identically to ordinary OCaml, until it sees the first `.<’. If one arranges the code such that all occurrences of the operator `>.’ come before the opening bracket, one can use the operator even in the same file as brackets. If one cannot arrange code such way, or must use `>.’ within brackets, one has to use the alternative syntax for brackets and escapes:

        fun h -> [%metaocaml.bracket 1 >. [%metaocaml.escape h]]

although one may prefer

        fun h -> [%metaocaml.bracket 1 >. .~h]

For more explanations, please see https://okmij.org/ftp/ML/MetaOCaml.html particularly about CSP, and https://okmij.org/ftp/meta-programming/tutorial/genc.html about offshoring. See also ChangeLog and NOTES.txt in the BER MetaOCaml distribution.

BER MetaOCaml N114 should be available through OPAM, hopefully soon. In the meanwhile, it is available as a set of patches to the OCaml 4.14.1 distribution.

https://okmij.org/ftp/ML/ber-metaocaml.tar.gz

See the INSTALL document in that archive. You need the source distribution of OCaml 4.14.1.

Building iOS apps with OCaml?

RobertN asked

Is it possible to create iOS apps with OCaml? I know it might take some extra work to use a foreign-function interface to call Objective-C functions to create the UI objects. But I’m wondering if I can cross compile for ARM and send a binary to my iPhone, and eventually the App Store. I’ll be working from macOS (x86).

I’m also interested in macOS apps for the App Store, which probably require cross-compiling to make an ARM+x86 binary of some kind.

Daniel Bünzli replied

Don’t know what the state of that is but at least it has been done at some point.

Nathan Fallet also replied

I’ve already seen people trying to do that. Here is an example.

It’s not from me but it’s an example I got shown when I built my OCaml editor for iOS/iPadOS/macOS.

jbeckford added

Couple more options …

Option 1: I mentioned last week in an unrelated thread that there is an opam package `dkml-base-compiler` that does cross-compilation. It supports most of the Android cross-compile matrix (ex. x86 -> arm32), and the macOS (ex. x86_64 -> arm64). I haven’t updated the official opam package to do iOS cross-compiles b/c most of my open-source time commitment has been for Windows. If you know how to compile the OCaml compiler, please extend that package! The bits will be very similar to the macOS cross-compiler, and I can guide you. See: https://discuss.ocaml.org/t/how-to-compile-ocaml-program-on-linux-for-running-on-freebsd/12110/4?u=jbeckford

Option 2: If you want a more out-of-the-box solution, you can use my commercial DkSDK native development kit. From an OCaml perspective, it is a OCaml-beginner friendly kit that embeds OCaml into other languages and frameworks. Two short-term things are relevant. 1) The docs mentions C a lot, but only because I haven’t finished writing its FFI. It will support OCaml objects <–> Objective-C/Swift objects using Apple’s Foundation library. 2) I inadvertently broke support for Xcode builds, but that will get fixed sooner or later (depending on the interest).

Anyway, ping me privately if Objective-C/Swift dev in Xcode with the Run button automatically building FFI-supported OCaml code sounds like a fit.

Vincent Balat also replied

Be Sport app is written in OCaml (iOS, Android, Web client and server) with Ocsigen (Eliom, Js_of_ocaml, Ocsigen Start…) as an HTML5 app (with Cordova) https://apps.apple.com/fr/app/be-sport/id1104216922

A Minimal Prototype of In-Package Search is on staging.ocaml.org

Sabine Schmaltz announced

We added an experimental, incomplete and basic in-package search to staging.ocaml.org. :camel: The current prototype implementation uses an existing JavaScript library. That turned out to be the quickest / least-effort way to get something up and running while we work behind the scenes on something more refined.

On https://staging.ocaml.org/p/dream/latest (or any other package for which documentation has been successfully built by the documentation pipeline) you should see a search bar that allows you to search identifiers within the package.

The goal from our side is to bring a “minimum useful product” to you quickly. Please let us know if there are any problems or wishes for a “version 1.0.0” of the search.

If no show-stopping issues are uncovered, we’ll go ahead and apply a patch to the live site at ocaml.org by end of the week or early next week. :slight_smile:

Thank you @panglesd, @EmileTrotignon, and @art-w for enabling this! I spent surprisingly little time on the integration into staging.ocaml.org so far, so it’s going to be fun to see where this goes.

Barisere Jonathan asked and Sabine Schmaltz replied

Is it possible to run the docs UI locally, just as Racket does?

It is possible to use odoc locally to render and consume documentation.

However, search has not yet been added to odoc.

This particular prototype of search is only on staging.ocaml.org at the moment.

Sid Kshatriya then added

To suplement to what @sabine mentioned, I would like to recommend odig.

odig is a very easy way to invoke odoc on your local machine. See https://erratique.ch/software/odig

New release of Fix (20230505)

François Pottier announced

Frédéric Bour and I are pleased to announce a new release of Fix.

In short, Fix is a toolkit that helps perform memoization and fixed point computations (including data flow analyses). More generally, it offers a number of basic algorithmic building blocks that can be useful in many circumstances.

In this release, two new modules have been added:

  • Fix.Minimize offers a minimization algorithm for deterministic finite automata (DFAs). It is based on Antti Valmari’s 2012 paper, “Fast brief practical DFA minimization”.
  • Fix.Partition offers a partition refinement data structure, which is used by the minimization algorithm, and could be useful in other algorithms.

There are other minor changes.

The library can be installed as follows:

  opam update
  opam install fix.20230505

Documentation is available online.

QCheck 0.21

Jan Midtgaard announced

I’m happy to announce the release of QCheck 0.21, a property-based testing library in the style of Haskell’s QuickCheck :tada: More information is available in the QCheck Github repository and in the package documentation.

The 0.21 release offers better negative test integration and furthermore fixes a couple of bugs in QCheck.Shrink and in ppx_deriving_qcheck:

  • make Test.check_result, Test.check_cell_exn, and Test.check_exn honor test polarity by raising Test_unexpected_success when a negative test (expected to have a counter example), unexpectedly succeeds.
  • fix issue with ppx_deriving_qcheck deriving a generator with unbound gen for recursive types #269 and a related issue when deriving a generator for a record type
  • fix #241 causing QCheck.Shrink.int* to emit duplicates, also affecting QCheck.Shrink.{char,string}
  • fix a cornercase where Shrink.list_spine would emit duplicates

Old CWN

If you happen to miss a CWN, you can send me a message and I’ll mail it to you, or go take a look at the archive or the RSS feed of the archives.

If you also wish to receive it every week by mail, you may subscribe online.