Hello

Here is the latest OCaml Weekly News, for the week of August 23 to 30,
2022.

Table of Contents
─────────────────

What’s your development workflow?
Mirage retreat October 3rd - 9th
Experience report: making a JavaScript library from an OCaml library with 
js_of_ocaml
Will I ever understand Format? or How to print a list vertically with 
indentation
GNU Guile 1.0.0 - Bindings to GNU Guile for OCaml
Update on Eio (effects-based direct-style IO for OCaml 5)
OCaml at First Glance
GADTs for typed option getter/setter
shuttle v0.3.1 released
coinductive data types
Old CWN


What’s your development workflow?
═════════════════════════════════

  Archive:
  <https://discuss.ocaml.org/t/whats-your-development-workflow/10358/1>


Bozhidar Batsov asked
─────────────────────

  I’ve started learning OCaml recently and one issue that I struggle
  with is finding a workflow that gives me quick feedback about changes
  I’ve made (I’m looking to reduce compile/run cycles). To give you some
  context - most of the time I’m programming in Lisps and Ruby, where
  it’s relatively easy to modify a running application. With all Lists
  my workflow is:

  • I make some change (e.g. I update some function)
  • I compile the changed bit of code (e.g. a function)
  • I immediately run this with the help of the REPL
  • Based on the results I got I go to the beginning or move on to the
    next things that needs doing

  That’s known as [interactive programming] in some circles and I
  totally love it. With Ruby I can’t do the same, but at least with web
  apps there’s some degree of code reloading that allows you modify a
  running app.

  With OCaml, however, I’m not sure how to get the quick feedback, as it
  seems I need to constantly compile and run stuff. I’m trying to work
  like with Lisps - I keep a toplevel open alongside my source code and
  occasionally send some code there, but the toplevel is limited in many
  way (you’re just dumping text there at the global level). `dune utop`
  helps to some extent, but it can’t reload changes. I’ve heard that
  some people were saying they didn’t even use a toplevel, so I’m
  wondering if I’m missing something. I’d be curious to hear any tips
  and tricks from your OCaml workflows.


[interactive programming]
<https://docs.cider.mx/cider/usage/interactive_programming.html>


Jack Feser suggested
────────────────────

  Have a look at expectation testing with [ppx_expect]. That’s what I
  use to get this kind of quick feedback (and you can keep the results
  as a test).

  Instead of sending code to a REPL, you write your test in an expect
  block and run `dune runtest'. Anything you print out in the expect
  gets captured, and dune shows you the output as a diff.

  That said, I’ve never had good luck with REPLs, so I might be missing
  something about that workflow.


[ppx_expect] <https://github.com/janestreet/ppx_expect>


Later in the thread, Simon Cruanes said
───────────────────────────────────────

  Any test can be exploratory if they’re expect tests, imho
  :slightly_smiling_face: . The core requirement is to have printers for
  your types (e.g. `ppx_deriving.show'), so you can just create values
  and use
  ┌────
  │ Format.printf "my thing is now %a@." pp_thing my_thing;;
  └────

  and see the output in dune. There’s a few annoyances (e.g. when it
  crashes you need a bit of elbow grease to get the backtrace) but for
  the most part it’s a nice workflow. I don’t apply it to everything,
  though.


Kiran Gopinathan said
─────────────────────

  W.r.t to development cycle in OCaml, I find myself working in 3
  distinct ways depending on at which point of a project I am at:

  • *small experiments* - sometimes I need a particular function that
     isn’t provided by the stdlib, or some other bespoke well-defined
     function. In these cases, I write the function directly in the
     source code - using merlin’s typing information etc. to develop as
     usual. Once I’ve done that, just to check the behaviour is as I
     would expect, I copy over the definition to utop - if the function
     depends on any larger state from my project, I write a dummy module
     to mock these parts.
  • *exploring a stateful system* - sometimes, I’m interacting with some
     kind of stateful existing system that can be hard to run in utop
     (for example, it might be a pain to get the library working in
     bytecode) - e.g. gtk. In these cases, I setup a small executable
     module that performs the minimum required to setup the initial
     state, and do my iterative experiments by recompiling after each
     change. Because the module is small, and the OCaml compiler/dune is
     fast, this leads to a quick iterative editing experience.
  • *working on a well-known codebase* - in all other cases, I’m working
     on a codebase that I either know fairly well, or has sufficient
     documentation and typing-discipline to make it easy to understand
     what’s going on. In these cases, I can rely on the types and
     documentation to make changes/add new functions, and if needed, use
     tests to document expected behaviours.

  As I’m speaking to an Emacs celebrity @bbatsov (thank you for your
  great packages!), I’d be remiss if I didn’t mention my own little
  experiment in this direction - `interactive-utop-mode':

  
<https://global.discourse-cdn.com/standard11/uploads/ocaml/original/2X/5/53856f555462c98314f99209cb3a145a02181428.webp>

  <https://gitlab.com/-/snippets/2170216>

  It’s not quite the same level of interactivity as lisp, granted, but
  with judicious use of forking, you can emulate a slightly more
  interactive repl experience.

  Disclaimer: I don’t actually use this that much myself, it’s just more
  of a proof of concept to show how it works.


Yaron Minsky said
─────────────────

  Big +1 to expect tests for interactive programming. I wrote a bit
  about this in an old blog post:

  <https://blog.janestreet.com/repeatable-exploratory-programming/>

  As to how to make things yet better:

        On the ppx_expect, this could mean dropping dependencies.

  At present, I think ppx_expect itself depends only on a couple other
  ppx’s, and Base and Stdio, so I think it’s already reasonably light,
  and the libraries in question are all portable.

  From my perspective, a more important direction is to improve the
  editor integration. Our internal expect test workflow is delightful,
  and quite a bit better than what’s available publicly. When an error
  pops up from the build, you hit a key to see the diff, hit another key
  to accept the diff if you want to. It would be great if we could get
  something similar to that in vscode.

  Indeed, I posted an issue about this here:

  <https://github.com/ocamllabs/vscode-ocaml-platform/issues/226>


Mirage retreat October 3rd - 9th
════════════════════════════════

  Archive:
  <https://discuss.ocaml.org/t/mirage-retreat-october-3rd-9th/10363/1>


Hannes Mehnert announced
────────────────────────

  Dear (aspiring) [MirageOS] hacker,

  it is my please to announce that there will be the 11th MirageOS
  retreat in early October in Mirleft, southern Morocco – yes, this time
  at the seaside. Please find more details, including writeups of
  earlier retreats at <http://retreat.mirage.io>

  Everyone is welcome, be kind to each other. There won’t be much
  Internet connectivity – but there’s plenty of beach, discussions,
  impromptu talks, and a local network mainly constructed by MirageOS
  unikernels.

  If you have questions, don’t hesitate to ask them here in this thread,
  or contact me directly via eMail “my first name” at mehnert.org.


[MirageOS] <https://mirage.io>


Experience report: making a JavaScript library from an OCaml library with 
js_of_ocaml
═════════════════════════════════════════════════════════════════════════════════════

  Archive:
  
<https://discuss.ocaml.org/t/experience-report-making-a-javascript-library-from-an-ocaml-library-with-js-of-ocaml/10380/1>


John Whitington announced
─────────────────────────

  I have recently compiled our whole codebase with `js_of_ocaml',
  producing a PDF processing library with can be used from JavaScript
  programs on the server, or within the browser.

  I started with no knowledge of JavaScript or its ecosystem, and the
  `js_of_ocaml' examples don’t touch on this particular use case, so I
  thought it would be useful to write up a quick experience report. I’m
  still pretty naive on the topic, so do take it with a pinch of salt.
  Corrections welcome.

  Perhaps you could make your favourite OCaml library accessible from
  JavaScript?

  Source code: [Coherentpdf.js].


[Coherentpdf.js] <https://github.com/coherentgraphics/coherentpdf.js>

Existing Code
╌╌╌╌╌╌╌╌╌╌╌╌╌

  For this project, I used the OCaml source code from the PDF library
  CamlPDF, the command line PDF tools CPDF, and the C interface to CPDF,
  CPDFLIB. CPDFLIB is an API allowing access to the PDF library from C
  via the OCaml FFI (and, therefore, from .NET, Java, Python etc).

  [CamlPDF source] | [CPDF source] | [Cpdflib source]

  This code is almost all OCaml, with a small amount of C code for
  cryptography and compression.

  We will be recompiling all this code with `js_of_ocaml', to yield a
  JavaScript library which can access all the functions in CPDFLIB.
  Since CPDFLIB is a flat API with no direct access to OCaml data
  structures, this should be easy to access from JavaScript. Building a
  JavaScript library which had to directly manipulate OCaml data
  structures would be more difficult.


[CamlPDF source] <https://github.com/johnwhitington/camlpdf>

[CPDF source] <https://github.com/johnwhitington/cpdf-source>

[Cpdflib source] <https://github.com/johnwhitington/cpdflib-source>


Compilation procedure
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌

  Our build procedure will be simple. Copy all the OCaml and C source
  files from the CamlPDF, CPDF and CPDFLIB into our build directory and
  then:

  • compile and link a bytecode executable with ocamlc using a makefile
  • call `js_of_ocaml' to turn the resulting bytecode file into
    JavaScript

  (dune can also be used for both these steps)

  Why the C files? Because we need them to link the bytecode executable:
  the C code will be thrown away by `js_of_ocaml', but we must get the
  bytecode linked.

  `Js_of_ocaml' informs us that we have missing primitives: the C code
  we will need to replace with JavaScript later, but the thing builds,
  and a couple of megabytes of JavaScript is produced. It doesn’t do
  anything yet, because we have no way of calling into it. But we can
  load it as a module in node even at this stage.

  If we miss out the cpdflib source files, though, and just include
  camlpdf and cpdf, we get the cpdf command line tools, which we can run
  in node as a command line tool, and they work just fine (if we don’t
  use compressed or encrypted files, of course):

  ┌────
  │ $node cpdf.js -pages cpdfjsmanual.pdf
  │ 152
  └────

  Magic! About five or six times slower than the native code version,
  but it works with minimal effort. `Js_of_ocaml' has supplied an
  alternative set of primitives for input and ouput, and an alternative
  runtime, and they replaces OCaml’s transparently.


Replacing C with JavaScript
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌

  Our C code will be thrown away by JavaScript, so we need to provide
  alternatives. `js_of_ocaml' allows us to write them in JavaScript with
  some special comments. It will then plug each in for its corresponding
  OCaml external (C symbol in the linked OCaml bytecode). Here’s the
  replacement for one of CamlZip’s functions, using node’s own zlib
  library:

  ┌────
  │ //Provides: camlpdf_caml_zlib_compress
  │ //Requires: caml_bytes_of_array
  │ //Requires: caml_array_of_bytes
  │ function camlpdf_caml_zlib_compress(s)
  │ {
  │   var s2 = caml_array_of_bytes(s);
  │   var buf = Buffer.from(s2);
  │   var output = zlib.deflateSync(buf);
  │   return caml_bytes_of_array(output);
  │ }
  └────

  In this case, it was not a direct replacement - the API is different.
  So we must modify our OCaml code to be compilable in both OCaml and
  `js_of_ocaml', like this:

  ┌────
  │ (* js_of_ocaml only *)
  │ external camlpdf_caml_zlib_compress : string -> string = 
"camlpdf_caml_zlib_compress"
  │ external camlpdf_caml_zlib_decompress : string -> string = 
"camlpdf_caml_zlib_decompress"
  │ 
  │ let is_js =
  │   Sys.backend_type = Sys.Other "js_of_ocaml"
  │ 
  │ let encode_flate stream =
  │   if is_js then
  │     Pdfio.bytes_of_string (camlpdf_caml_zlib_compress 
(Pdfio.string_of_bytes stream))
  │   else
  │     flate_process (Pdfflate.compress ~level:!flate_level) stream
  └────

  We also need some fake stubs in our C code to make sure it still
  compiles in the non-JavaScript case with these new externals:

  ┌────
  │ // So that the code links ok when using js_of_ocaml
  │ char* camlpdf_caml_zlib_decompress(char *s) { return s; }
  │ char* camlpdf_caml_zlib_compress(char *s) { return s; }
  └────

  This code will never be called, of course: it is simply to make the
  symbol available.


Writing the JavaScript interface
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌

  Now, we use the provided PPX `js_of_ocaml-ppx' to provide a JavaScript
  interface to each function, and export them as functions in our
  JavaScript module:

  ┌────
  │ Js.export_all
  │   (object%js
  │      method fromFile filename userpw =
  │        checkerror (Cpdflib.fromFile (Js.to_string filename) (Js.to_string 
userpw))
  │      ...hundreds more functions...
  │   )
  └────

  Notice `Js.to_string' here. Conversions to and from JavaScript will be
  required for many data types, for example strings, arrays, bigarrays
  and so on. In our case, `Cpdflib.fromFile' returns a simple integer,
  so no conversion is required.


Trying it out
╌╌╌╌╌╌╌╌╌╌╌╌╌

  Now that we have the library working, we can try it out by running a
  JavaScript file with node, or by typing into the node REPL:

  ┌────
  │ //Load coherentpdf.js
  │ const coherentpdf = require('./coherentpdf.js');
  │ 
  │ var pdf = coherentpdf.fromFile('hello.pdf', '');
  │ var merged = coherentpdf.mergeSimple([pdf, pdf, pdf]);
  │ coherentpdf.toFile(merged, 'merged.pdf', false, false);
  │ 
  │ coherentpdf.deletePdf(pdf);
  │ coherentpdf.deletePdf(merged);
  └────


Compiling for the browser
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌

  We can use the [browserify] tool to bundle up our code and its
  external libraries, including the parts of the node standard library
  we use, to make single JavaScript file for use within a web page. This
  nearly doubles the size:

  ┌────
  │ 2192588 coherentpdf.browser.js
  │ 1136687 coherentpdf.js
  └────

  Here is an example of a web page which uses coherentpdf.js to process
  a PDF file entirely in the browser. You can choose a file, and it will
  be processed and a download initiated with the output:

  [https://coherentpdf.com/coherentpdfjs/index.html]

  Of course, we have a problem now: in the browser, there are no files
  to read to or write from - the browser is a sandboxed environment. So
  we must make sure our API also contains functions to read to and write
  from PDF files represented as byte arrays.

  There is an additional issue: JavaScript in the browser does not cope
  well with large chunks of synchronous code like ours: processing a big
  PDF file would lock up the browser (or at least the tab). We must use
  what is called a “web worker” to run it in the background in another
  JavaScript environment, and communicate by message-passing only. See
  the file `cpdfworker.js' for this code.


[browserify] <https://browserify.org>

[https://coherentpdf.com/coherentpdfjs/index.html]
<https://coherentpdf.com/coherentpdfjs/index.html>


Minification
╌╌╌╌╌╌╌╌╌╌╌╌

  The [uglify-js] tool can be used to minify the JavaScript for
  deployment on the web:

  ┌────
  │ 2192588 coherentpdf.browser.js
  │ 1324660 coherentpdf.browser.min.js
  │ 1136687 coherentpdf.js
  │ 849949  coherentpdf.min.js
  └────

  We are now down to 1.3Mb. Many web servers can serve gzip’d content
  too, so that helps further, and we get down to 514Kb actually sent
  over the web.


[uglify-js] <https://www.npmjs.com/package/uglify-js>


Documentation
╌╌╌╌╌╌╌╌╌╌╌╌╌

  Because we built our library from within OCaml, and had it generated
  for us by `js_of_ocaml-ppx', there is no place to put the docstrings.
  So, unfortunately, we must write a separate JavaScript source file
  with empty functions like this:

  ┌────
  │ /** Returns the number of pages in a given PDF, with given user password. It
  │ tries to do this as fast as possible, without loading the whole file.
  │ @arg {string} password user password
  │ @arg {Uint8Array} data PDF file as a byte array
  │ @return {number} number of pages */
  │ function pagesFastMemory(password, data) {}
  └────

  Now we can run any standard JavaScript documentation generator over
  this to produce the HTML documentation.


Publishing the package
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌

  Publishing the package on the npm package system is alarmingly easy -
  a `package.json' file, mostly autogenerated, is added, and then it is
  published from the command line. You can see it here:

  [https://www.npmjs.com/package/coherentpdf]

  Here is the source, including the `package.json': [Coherentpdf.js].


[https://www.npmjs.com/package/coherentpdf]
<https://www.npmjs.com/package/coherentpdf>

[Coherentpdf.js] <https://github.com/coherentgraphics/coherentpdf.js>


Licensing
╌╌╌╌╌╌╌╌╌

  Our command line PDF tools and C/.NET/Java/Python APIs are under a
  commercial license, or alternatively a non-standard “not for
  commercial use” license. This is tiresome, because this non-standard
  license prevents them being included in, for example, linux
  distributions.

  For coherentpdf.js, the license is just for the JavaScript output of
  `js_of_ocaml', not the original OCaml source, so it can be given a
  more standard AGPL license, whilst still being available for purchase,
  and without opening up the commercial OCaml code. The AGPL isn’t
  everyone’s favourite license, of course, but we start there for now.


To do
╌╌╌╌╌

  What doesn’t work yet? Just two things:

  • The default stack available in many browsers is small (and some have
    a smaller stack for web workers), so coherentpdf.js can choke on
    very large PDF files. This is not a problem in node on the server.
    This will have to be fixed by modifications to the OCaml code
    itself.

  • `js_of_ocaml' installs its own top-level error handler, with the
    unfortunate side-effect that any error in the node REPL after the
    module is loaded - even a syntax error - causes the REPL to exit. I
    plan to produce a patch to make this behaviour optional.


Final Remarks
╌╌╌╌╌╌╌╌╌╌╌╌╌

  `js_of_ocaml' is a remarkably solid piece of kit. To be able to
  recompile fifteen years of accumulated code with just a few changes
  was very surprising to me.

  Thanks to the `js_of_ocaml' team and others for answering all my
  questions during this process, and correcting some of my
  misconceptions.

  I’m still very much a JavaScript newbie, and it’s not a language or
  platform I’ve grown to love, but if you want your OCaml code to run in
  the browser, or your OCaml library to be available to millions of
  JavaScript programmers, you might try giving it a go.


Will I ever understand Format? or How to print a list vertically with 
indentation
═════════════════════════════════════════════════════════════════════════════════

  Archive:
  
<https://discuss.ocaml.org/t/will-i-ever-understand-format-or-how-to-print-a-list-vertically-with-indentation/10289/16>


Deep in this thread, Gaga said
──────────────────────────────

  There is also a nice document called “Format Unraveled”, if you want
  to learn more about `Format'. It can be found [here]


[here]
<https://hal.archives-ouvertes.fr/hal-01503081/file/format-unraveled.pdf>


GNU Guile 1.0.0 - Bindings to GNU Guile for OCaml
═════════════════════════════════════════════════

  Archive:
  
<https://discuss.ocaml.org/t/ann-gnu-guile-1-0-0-bindings-to-gnu-guile-for-ocaml/10393/1>


Kiran Gopinathan announced
──────────────────────────

  Hi everyone! I am pleased to announce a brand new package for the
  OCaml ecosystem: Guile-ocaml

        Guile-ocaml is a Free Software library that provides
        high-level OCaml bindings to the FFI interface for GNU
        Guile Scheme. The aim of these bindings are to provide an
        easy way for OCaml developers to extend their OCaml
        applications with GNU Guile scheme scripting capabilities,
        providing simple combinators to translate terms and send
        queries between the two languages.

  You can find the documentation [here] - alongside a fairly
  comprehensive documentation of all the bindings, it provides a step by
  step guide on implementing the classical GNU Guile based turtle
  drawing program, except using OCaml’s graphics module.

  Here’s a sneak preview from that guide of what passing an OCaml
  function to GNU Guile looks like using these bindings:

  ┌────
  │ let move_by n =
  │   if not @@ Guile.Number.is_integer n then
  │     failwith "expected numeric arg";
  │   let n = Guile.Number.int_from_raw n in
  │   let x, y =
  │     let cur_pos = Graphics.current_point () in
  │     move n cur_pos !direction in
  │   if !pen_down then
  │     Graphics.lineto x y;
  │   Graphics.moveto x y;
  │   Guile.eol
  │ 
  │ let () = ignore @@ Guile.Functions.register_fun1 "move-by" move_by
  └────

  Also, I’d like to give extra thanks to opam-repository’s tireless
  maintainers! The package was in limbo for a while because I couldn’t
  work out why conf-guile was failing to build on certain distributions,
  but thankfully @mseri and @kit-ty-kate were able to fix the issue!


[here] <https://gopiandcode.github.io/guile-ocaml/>


Update on Eio (effects-based direct-style IO for OCaml 5)
═════════════════════════════════════════════════════════

  Archive:
  
<https://discuss.ocaml.org/t/update-on-eio-effects-based-direct-style-io-for-ocaml-5/10395/1>


Thomas Leonard announced
────────────────────────

  [Eio] provides an effects-based direct-style IO stack for OCaml 5.0.
  It aims to be easy to use, secure, well documented, and fast. It
  consists of a generic cross-platform API, plus optimised backends for
  different platforms. It can be used instead of (or alongside) Lwt and
  Async.


[Eio] <https://github.com/ocaml-multicore/eio>

Recent changes
╌╌╌╌╌╌╌╌╌╌╌╌╌╌

  There have been several releases since the last announcement here. The
  bigger changes include:

  • [Fiber-local storage] (thanks to Jonathan Coates). This allows e.g.
    a web-server to attach a request ID to the fiber that is handling
    it, and then display this in all log messages generated by that
    request.
  • [Eio.Mutex] and [Eio.Condition] (@Lortex). These are similar to the
    ones in the standard library, but they allow other fibers to run
    while waiting instead of blocking the whole domain.
  • [Eio.Buf_write] is a port of Faraday to Eio, allowing efficient
    output buffering.
  • [Fiber.fork_daemon] allows spawning a fiber that will be cancelled
    automatically when the non-daemon fibers have finished. This is
    useful for e.g. running a thread to collect entropy for a random
    number generator while a program is running, without it preventing
    the program from finishing.
  • [Fiber.{iter,map,filter,fiter_map}] provide concurrent versions of
    the corresponding operations in `List'.
  • [Eio.Path] provides file-system access. New operations include
    `read_dir' (@patricoferris), `unlink', `rmdir' and `rename'.
  • [The networking APIs] now include UDP (@patricoferris) and DNS
    (@bikalgurung), and IPv6 now works (@haesbaert).
  • [Eio_mock] provides a framework for creating mocks for testing,
    along with pre-defined ones for flows and networks.
    `Eio_mock.Backend' is a special backend for tests. It does no real
    IO, but can report if your tests deadlock.
  • The much-requested [Eio_unix.sleep] is now available as a direct
    replacement for `Lwt_unix.sleep'.

  See the [release notes] for full details, and [the tutorial] for an
  introduction.


[Fiber-local storage]
<https://ocaml-multicore.github.io/eio/eio/Eio/Fiber/index.html#fiber-local-variables>

[Eio.Mutex]
<https://ocaml-multicore.github.io/eio/eio/Eio/Mutex/index.html>

[Eio.Condition]
<https://ocaml-multicore.github.io/eio/eio/Eio/Condition/index.html>

[Eio.Buf_write]
<https://ocaml-multicore.github.io/eio/eio/Eio/Buf_write/index.html>

[Fiber.fork_daemon]
<https://ocaml-multicore.github.io/eio/eio/Eio/Fiber/index.html#val-fork_daemon>

[Fiber.{iter,map,filter,fiter_map}]
<https://ocaml-multicore.github.io/eio/eio/Eio/Fiber/index.html#concurrent-list-operations>

[Eio.Path]
<https://ocaml-multicore.github.io/eio/eio/Eio/Path/index.html>

[The networking APIs]
<https://ocaml-multicore.github.io/eio/eio/Eio/Net/index.html>

[Eio_mock]
<https://ocaml-multicore.github.io/eio/eio/Eio_mock/index.html>

[Eio_unix.sleep]
<https://ocaml-multicore.github.io/eio/eio/Eio_unix/index.html#val-sleep>

[release notes] <https://github.com/ocaml-multicore/eio/releases>

[the tutorial] <https://github.com/ocaml-multicore/eio#getting-ocaml-50>


Integration with Lwt and Async
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌

  [Lwt_eio] allows running Lwt and Eio code together in a single domain.
  The 0.2 release adds support for integrating Lwt and Eio cancellation.
  The [porting guide] shows how to update an Lwt application to Eio
  incrementally.

  [Async_eio] allows running Async and Eio code together in a single
  domain. This is experimental and requires some changes to Async
  itself.

  [async-eio-lwt-chimera] shows how Async, Eio and Lwt code can all be
  used together in a single event loop. It runs an Async server that
  handles connections using an Lwt handler that reads a line from the
  request and then handles it by using Eio to read the named file from
  its data directory.


[Lwt_eio] <https://github.com/ocaml-multicore/lwt_eio>

[porting guide]
<https://github.com/ocaml-multicore/lwt_eio#porting-a-lwt-application-to-eio>

[Async_eio] <https://github.com/talex5/async_eio>

[async-eio-lwt-chimera]
<https://github.com/talex5/async-eio-lwt-chimera>


Porting
╌╌╌╌╌╌╌

  It’s useful for people to try porting applications and libraries to
  Eio so we can get feedback on the APIs and prioritise missing
  features. The Lwt and Async porting guides linked above may be
  helpful. Some examples so far include:

  • [ocaml-cohttp] (@bikalgurung)
  • [ocaml-geojson] (@patricoferris)
  • [capnp-rpc] (@talex5)
  • [rawlink] (@haesbaert)
  • [dream] (@talex5)
  • [mirage] (@Lortex)
  • [mirage-crypto] (@BikalGurung)


[ocaml-cohttp]
<https://github.com/mirage/ocaml-cohttp/tree/master/cohttp-eio>

[ocaml-geojson] <https://github.com/geocaml/ocaml-geojson/tree/effects>

[capnp-rpc] <https://github.com/mirage/capnp-rpc/pull/256>

[rawlink] <https://github.com/haesbaert/rawlink>

[dream] <https://github.com/aantron/dream/pull/194>

[mirage] <https://github.com/TheLortex/mirage-monorepo>

[mirage-crypto] <https://github.com/mirage/mirage-crypto/pull/155>


Backends
╌╌╌╌╌╌╌╌

  The recent [uring releases] have brought improved performance and
  several new features to the `eio_linux' backend.

  We are still hoping to persuade a Windows user to try using Eio. The
  Luv backend should mostly work, but there are likely some problems
  with paths, etc. Even better would be if someone writes a dedicated
  `eio_windows' backend.

  To add a backend for a new platform, it is best to start by studying
  [Eio_mock.Backend], which is very simple as it does no IO. To add IO,
  you can copy the pattern in either `eio_linux' (which provides its own
  event loop that asks the OS to sleep) or the one in `eio_luv' (which
  delegates to an event loop provided by another library).


[uring releases]
<https://github.com/ocaml-multicore/ocaml-uring/releases>

[Eio_mock.Backend]
<https://github.com/ocaml-multicore/eio/blob/main/lib_eio/mock/backend.ml>


OCaml at First Glance
═════════════════════

  Archive: <https://discuss.ocaml.org/t/ocaml-at-first-glance/10396/1>


Bozhidar Batsov announced
─────────────────────────

  This morning I spent a bit of time writing down some of [my initial
  observations, experiences and thoughts about OCaml]. Hopefully they’ll
  be useful to other newcomers to the language.

  TLDR; I can’t say that my initial experience with OCaml was
  mind-blowing, but it was definitely pleasant and with time the
  language grows on me. I miss the simplicity and uniformity of Clojure
  (still my favorite programming language by far) and Lisps in general
  or some of Haskell’s goodies (e.g. typeclasses, [Hackage] and `ghci'),
  but I feel OCaml strikes a very good balance between functional
  programming, pragmatism and performance. It’s a `fun' language to work
  with!

  I’d be really curious to hear your own thoughts on the subject and to
  receive feedback about any mistakes I might have made due to not being
  familiar enough with OCaml and its ecosystem.


[my initial observations, experiences and thoughts about OCaml]
<https://batsov.com/articles/2022/08/29/ocaml-at-first-glance/>

[Hackage] <https://hackage.haskell.org/>


Kiran Gopinathan replied
────────────────────────

  Nice blog post!

        I’d say the development tooling for OCaml is pretty
        decent, although I wouldn’t go as far as saying it’s
        great.

  Finally, a shameless plug, if you’re more familiar with lisp
  development tooling, have you tried [gopcaml-mode]? It provides
  paredit style structural editing support for OCaml:

  
<https://global.discourse-cdn.com/standard11/uploads/ocaml/original/2X/9/99180dcb28ea3021307e66801d8ee6f9f9b2c1b5.gif>


[gopcaml-mode] <https://github.com/gopiandcode/gopcaml-mode>


GADTs for typed option getter/setter
════════════════════════════════════

  Archive:
  <https://discuss.ocaml.org/t/gadts-for-typed-option-getter-setter/10398/1>


Romain Beauxis announced
────────────────────────

  I’ve had a nice use-case of GADTs recently in [ocaml-srt] that I
  thought I would share.

  On the `C' side, the library implements an API /a la/ `syscall' with
  named options and polymorphic types:
  ┌────
  │ SRT_API       int srt_getsockopt   (SRTSOCKET u, int level /*ignored*/, 
SRT_SOCKOPT optname, void* optval, int*
  │ optlen);
  │ SRT_API       int srt_setsockopt   (SRTSOCKET u, int level /*ignored*/, 
SRT_SOCKOPT optname, const void* optval, int
  │ optlen);
  └────
  And the socket options are listed in an `enum':
  ┌────
  │ typedef enum SRT_SOCKOPT {
  │ 
  │    SRTO_MSS = 0,             // the Maximum Transfer Unit
  │    SRTO_SNDSYN = 1,          // if sending is blocking
  │    SRTO_RCVSYN = 2,          // if receiving is blocking
  │    SRTO_ISN = 3,             // Initial Sequence Number (valid only after 
srt_connect or srt_accept-ed sockets)
  │    SRTO_FC = 4,              // Flight flag size (window size)
  │    SRTO_SNDBUF = 5,          // maximum buffer in sending queue
  │    SRTO_RCVBUF = 6,          // UDT receiving buffer size
  │ ...
  └────

  On the OCaml side, it is then pretty natural to also want a
  polymorphic API;
  ┌────
  │ type 'a socket_opt
  │ 
  │ val messageapi : bool socket_opt
  │ val payloadsize : int socket_opt
  │ val rcvsyn : bool socket_opt
  │ val sndsyn : bool socket_opt
  │ 
  │ val getsockflag : socket -> 'a socket_opt -> 'a
  │ val setsockflag : socket -> 'a socket_opt -> 'a -> unit
  └────

  This can be achieved in a cool type-safe way and without writing any C
  by combining [ctypes] and GADTs!

  First, we export the socket option enums as OCaml polymorphic variants
  using the `ctypes' API:
  ┌────
  │   type socket_opt =
  │     [ `Messageapi
  │     | `Payloadsize
  │     | `Rcvsyn
  │     | `Sndsyn]
  │ 
  │   let socket_opt : socket_opt typ =
  │     enum "SRT_SOCKOPT"
  │       [
  │         (`Messageapi, constant "SRTO_MESSAGEAPI" int64_t);
  │         (`Payloadsize, constant "SRTO_PAYLOADSIZE" int64_t);
  │         (`Rcvsyn, constant "SRTO_RCVSYN" int64_t);
  │         (`Sndsyn, constant "SRTO_SNDSYN" int64_t)
  │       ]
  └────

  Next, on our public OCaml API side, we use regular variant types with
  a type annotation to use for GADTs pattern matching and match then
  with the polymorphic variants returned by `ctypes':
  ┌────
  │ type _ socket_opt =
  │   | Messageapi : bool socket_opt
  │   | Payloadsize : int socket_opt
  │   | Rcvsyn : bool socket_opt
  │   | Sndsyn : bool socket_opt
  │ 
  │ let messageapi = Messageapi
  │ let payloadsize = Payloadsize
  │ let rcvsyn = Rcvsyn
  │ let sndsyn = Sndsyn
  │ 
  │ let srt_socket_opt_of_socket_opt (type a) : a socket_opt -> Srt.socket_opt =
  │   function
  │   | Messageapi -> `Messageapi
  │   | Payloadsize -> `Payloadsize
  │   | Rcvsyn -> `Rcvsyn
  │   | Sndsyn -> `Sndsyn
  └────

  `ctypes' also. gives us bindings to the `get~/~set' functions from the
  `C' library:
  ┌────
  │   let setsockflag =
  │     foreign "srt_setsockflag"
  │       (int @-> socket_opt @-> ptr void @-> int @-> returning int)
  │ 
  │   let getsockflag =
  │     foreign "srt_getsockflag"
  │       (int @-> socket_opt @-> ptr void @-> ptr int @-> returning int)
  └────

  Now, we’re ready to implement our `get~/~set' polymorphic functions:
  ┌────
  │ let getsockflag : type a. socket -> a socket_opt -> a =
  │  fun sock opt ->
  │   let arg = allocate int 0 in
  │   let arglen = allocate int (sizeof int) in
  │   ignore
  │     (check_err
  │        (getsockflag sock
  │           (srt_socket_opt_of_socket_opt opt)
  │           (to_voidp arg) arglen));
  │   let to_bool () = !@arg <> 0 in
  │   let to_int () = !@arg in
  │   match opt with
  │     | Rcvsyn -> to_bool ()
  │     | Sndsyn -> to_bool ()
  │     | Messageapi -> to_bool ()
  │     | Payloadsize -> to_int ()
  │ 
  │ let setsockflag : type a. socket -> a socket_opt -> a -> unit =
  │  fun sock opt v ->
  │   let f t v = to_voidp (allocate t v) in
  │   let of_bool v =
  │     let v = if v then 1 else 0 in
  │     (f int v, sizeof int)
  │   in
  │   let of_int v = (f int v, sizeof int) in
  │   let arg, arglen =
  │     match opt with
  │       | Rcvsyn -> of_bool v
  │       | Sndsyn -> of_bool v
  │       | Messageapi -> of_bool v
  │       | Payloadsize -> of_int v
  └────

  *⚠️ Question ⚠️*

  I wasn’t able to join cases of the same type, for instance this:
  ┌────
  │   match opt with
  │     | Rcvsyn
  │     | Sndsyn
  │     | Messageapi -> to_bool ()
  │     | Payloadsize -> to_int ()
  └────
  Is this a theoretical or implementation limitation?


[ocaml-srt] <https://github.com/savonet/ocaml-srt>

[ctypes] <https://github.com/ocamllabs/ocaml-ctypes>


yallop replied
──────────────

  It’s an implementation limitation. There are some details at
  <https://github.com/ocaml/ocaml/issues/5736>


Christian Lindig said
─────────────────────

  Slightly related to the problem of sharing constants between the C
  side and the OCaml side but much less sophisticated:

  For my small epoll library [polly] I am creating a function in C using
  a macro that returns the constant:

  ┌────
  │ /* Make all constants available to clients by exporting them via a
  │  * function. This avoids having to hard code them on the client side.
  │  * */
  │ 
  │ #define CONSTANT(name) \
  │   CAMLprim value caml_polly_ ## name(value unit) { return Val_int(name); }
  │ 
  │ CONSTANT(EPOLLIN);
  │ CONSTANT(EPOLLPRI);
  │ CONSTANT(EPOLLOUT);
  └────

  In the bindings I have one function per constant and call it once to
  obtain the constant; the actual value of the constant is not part of
  the OCaml code.

  ┌────
  │   type t = int
  │ 
  │   external polly_IN : unit -> t = "caml_polly_EPOLLIN"
  │   external polly_PRI : unit -> t = "caml_polly_EPOLLPRI"
  │   external polly_OUT : unit -> t = "caml_polly_EPOLLOUT"
  │ 
  │   let inp = polly_IN ()
  │   let pri = polly_PRI ()
  │   let out = polly_OUT ()
  └────


[polly] <https://github.com/lindig/polly>


shuttle v0.3.1 released
═══════════════════════

  Archive:
  <https://discuss.ocaml.org/t/ann-shuttle-v0-3-1-released/8684/2>


Anurag Soni announced
─────────────────────

  There have been some significant changes since this last release
  (Versions 0.4.0 and 0.5.0 are available on opam):

  • Buffered reader has a new utility method that allows reading lines
  • Shuttle now supports file descriptors that don’t support nonblocking
    I/O. For blocking I/O Shuttle uses async’s support for running
    syscalls in its thread pool
  • Buffered reader’s api has been simplified to remove
    `read_one_chunk_at_a_time' in favor of a more familiar `read',
    `read_line' etc. `refill' operation is supported to perform a read
    syscall to fill a channel’s buffer, and `Input_channel.view' can be
    used to get a view into the channel’s underlying buffer.
  • Supports v0.15 series of the janestreet libraries
  • Buffered reader now uses an auto-growing buffer instead of a fixed
    size buffer than notified users that the internal buffer is full and
    no progress can be made unless some content is consumed. This should
    allow starting with a smaller buffer without needing to worry about
    implementing some client side buffering to hold unconsumed data.
    Channels allow configuring an upper bound on the internal buffer
    length, if a buffer grows beyond that an exception is raised.
  • Buffered writer’s support a richer flush interface. Flush operations
    report errors encountered while attempting to write any pending
    bytes. This results in a flush operation that returns a deferred
    that will resolve at some point with either a success or an error,
    instead of the older flush operation that would return a deferred
    that never resolved if there was an error during a write syscall.


coinductive data types
══════════════════════

  Archive:
  <https://sympa.inria.fr/sympa/arc/caml-list/2022-08/msg00009.html>


Aaron Gray asked and François Pottier replied
─────────────────────────────────────────────

        Does either ML or OCaML have coinductive data types ? And
        if so could you please point me at the/some appropriate
        documentation on them.

  ML and OCaml have algebraic data types, which are recursive (that is,
  more general than inductive and co-inductive types). Algebraic data
  type definitions are not subject to a positivity restriction, and
  algebraic data types can be constructed and deconstructed by recursive
  functions, which are not subject to a termination check.

  If you want to see a typical example of a “co-inductive” data
  structure encoded in OCaml, I suggest to have a look at “sequences”,
  which can be described as potentially infinite lists:

  <https://v2.ocaml.org/api/Seq.html>


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].

  [Alan Schmitt]


[send me a message] <mailto:alan.schm...@polytechnique.org>

[the archive] <https://alan.petitepomme.net/cwn/>

[RSS feed of the archives] <https://alan.petitepomme.net/cwn/cwn.rss>

[online] <http://lists.idyll.org/listinfo/caml-news-weekly/>

[Alan Schmitt] <https://alan.petitepomme.net/>

_______________________________________________
caml-news-weekly mailing list
caml-news-weekly@lists.idyll.org
http://lists.idyll.org/listinfo/caml-news-weekly

Reply via email to