OCaml Weekly News
Hello
Here is the latest OCaml Weekly News, for the week of November 19 to 26, 2019.
Table of Contents
tiny_httpd 0.1
Simon Cruanes announced
Hello and good morning, I'm pleased to announce that tiny_httpd 0.1 has been released and is on opam.
The goal is to emulate python's standard http.server
by providing a 0-dependencies, minimalist, simple HTTP server for embedding in applications that are not primarily a website, with very basic routing (thanks to Scanf
). A binary http_of_dir
is also distributed and can be used to serve a directory, with optional upload of files.
printbox.0.3
Simon Cruanes announced
let b = let open PrintBox in PrintBox_unicode.setup(); frame @@ grid_l [ [text "subject"; text_with_style Style.bold "announce: printbox 0.3"]; [text "explanation"; frame @@ text {|PrintBox is a library for rendering nested tables, trees, and similar structures in monospace text or HTML.|}]; [text "github"; text_with_style Style.(bg_color Blue) "https://github.com/c-cube/printbox/releases/tag/0.3"]; [text "contributors"; vlist_map (text_with_style Style.(fg_color Green)) ["Simon"; "Guillaume"; "Matt"]]; [text "dependencies"; tree empty [tree (text "mandatory") [text "dune"; text "bytes"]; tree (text "optional") [text "uutf"; text "uucp"; text "tyxml"]]]; [text "expected reaction"; text "🎉"]; ] let () = print_endline @@ PrintBox_text.to_string b
v0.13 release of Jane Street packages
Xavier Clerc announced
We are pleased to announce the v0.13 release of Jane Street packages!
This release comes with 14 new packages, and a number of fixes and enhancements. The documentation for this release is available on our website:
https://ocaml.janestreet.com/ocaml-core/v0.13/doc/
The remainder of this mail highlights the main changes since the v0.12 release; we hope it will be useful to developers in the process of migrating to the new version. A comprehensive changelog is available at the end.
Notable changes
- Changed
Base
,Core_kernel
, andCore
functions to raiseNot_found_s
instead ofNot_found
.Hashtbl.find_exn
andMap.find_exn
now include the key in their error message. - Changed
Core
andCore_kernel
to exportint
comparison rather than polymorphic comparison. - Removed the "robust" float comparison operators (
>.
,=.
, …) from the default namespace. - Replaced
sexp_*
types (sexp_list
,sexp_option
,sexp_opaque
, …) with preprocessor attributes ([@sexp.list]
,[@sexp.option]
,[@sexp.opaque]
, …). - Changed
let%map
syntax fromlet%map.Foo.Let_syntax
tolet%map.Foo
. - Added to
match%optional
support for specifying a path, so you can writematch%optional.Foo foo_option
rather thanlet open Foo.Optional_syntax in match%optional foo_option
. - Improved
Base.Backtrace
so that it enables recording of backtraces in more situations, specifically whenOCAMLRUNPARAM
is defined but doesn't mention the backtrace flag,b
. - Added javascript support for
Zarith
,Bigint
,Bignum
, andBigdecimal
. - Changed
Hashtbl.create
's defaultsize
from 128 to 0. - Changed
Core_kernel.Command
so that all commands accept double dash flags:--help
,--version
, and--build-info
.
New packages
- async_udp (https://github.com/janestreet/async_udp): UDP support for Async.
- async_websocket (https://github.com/janestreet/async_websocket): A library that implements the websocket protocol on top of Async.
- bonsai (https://github.com/janestreet/bonsai): A library for building dynamic webapps, using Js_of_ocaml.
- postgres_async (https://github.com/janestreet/postgres_async): OCaml/async implementation of the postgres protocol (i.e., does not use C-bindings to libpq).
- ppx_cold (https://github.com/janestreet/ppx_cold): Expands
[@cold]
into[@inline never][@specialise never][@local never]
. - ppx_pattern_bind (https://github.com/janestreet/ppx_pattern_bind): A ppx for writing fast incremental bind nodes in a pattern match.
- ppx_python (https://github.com/janestreet/ppx_python):
[@@deriving]
plugin to generate Python conversion functions. - ppx_yojson_conv (https://github.com/janestreet/ppx_yojson_conv):
[@@deriving]
plugin to generate Yojson conversion functions. - ppx_yojson_conv_lib (https://github.com/janestreet/ppx_yojson_conv_lib):
Runtime lib for
ppx_yojson_conv
. - pythonlib (https://github.com/janestreet/pythonlib): A library to help writing wrappers around OCaml code for python.
- sexp_select (https://github.com/janestreet/sexp_select): A library to use CSS-style selectors to traverse sexp trees.
- timezone (https://github.com/janestreet/timezone): Time-zone handling.
- toplevel_backend (https://github.com/janestreet/toplevel_backend): Shared backend for setting up toplevels.
- zarith_stubs_js (https://github.com/janestreet/zarith_stubs_js): Javascript stubs for the Zarith library.
Deprecations / Removals
Async_kernel
:
- Deprecated monadic
ignore
functions in favor ofignore_m
.
Base
:
- Deleted
Array.replace
andreplace_all
functions, which have been deprecated since before the last public release. - Deprecated
Result.ok_unit
; useOk ()
. - Removed the
Monad
andApplicative
interfaces'all_ignore
function; it was previously deprecated and replaced byall_unit
. - Removed
List.dedup
, which has been deprecated since 2017-04. - Removed
String
mutation functions, which have been deprecated in favor ofBytes
since 2017-10. - Deprecated
Array.truncate
,Obj_array.unsafe_truncate
, andUniform_array.unsafe_truncate
. - Deprecated
Sys.argv
, which has been superseded byget_argv
, which is a function, reflecting the fact thatargv
can change (as of OCaml 4.09).
Core_kernel
:
- Removed
Core_kernel.Std
, which had been deprecated for a year. - Deprecated type
Command.Spec.param
in favor ofCommand.Param.t
. - Removed
Hashtbl
functions that had been deprecated for years. - Removed
Float.to_string_round_trippable
, which has been deprecated in favor ofto_string
since 2017-04. - Deprecated
Fqueue
functions where one should useFdeque
instead:bot
,bot_exn
, andenqueue_top
. - Deleted
Bus.unsubscribes
, which will be obviated by a performance improvement toBus.unsubscribe
.
Timing_wheel
:
- Removed the
alarm_upper_bound
function, which has been deprecated for 6 months, and superseded bymax_allowed_alarm_time
.
Moves
Core_kernel
:
- Moved
Bounded_int_table
to a standalone library. - Moved the
Pool
andTuple_type
modules to a standalone library,Tuple_pool
.
Async_unix
:
- Moved
Unix.Fd.replace
into aPrivate
submodule.
Changelog
opam2nix (v1)
Tim Cuthbertson announced
Anouncing opam2nix (v1)
opam2nix generates nix expressions from the opam OCaml package repository. It works similarly to bundix, node2nix, etc:
You run an (impure) command to resolve all transitive dependency versions using the current opam repository, generating a .nix file that locks down the exact package sources and versions. Then this file can be imported to provide buildInputs
for building your ocaml project in nix.
What is nix and why would I care? Well, that's a long story but the headline benefits of nix are:
- reproducible builds (if it builds for me, it builds for you)
- stateless (you don't set up switches and then install packages, each expression specifies everything it needs, and anything you don't have is fetched/built on demand)
- language agnostic (takes care of non-ocaml dependencies)
It's sadly not a shallow learning curve, but those benefits are hard to find elsewhere, so I obviously think it's worthwhile. So if you use nix (or would like to), please give it a try and provide feedback. I'll (slowly) start working on upstreaming it into nixpkgs.
GitHub Actions for OCaml / opam now available
Anil Madhavapeddy announced
I was in the GitHub Actions beta program and forward ported my code to the latest version that just went public. It's a pretty simple way to get your OCaml code tested on Linux, macOS and Windows, without requiring an external CI service. The action attempts to provide a homogenous interface across all three operating systems, so invoking 'opam' from subsequent actions should "just work".
You can find it here:
- In the GitHub Marketplace at https://github.com/marketplace/actions/setup-ocaml
- Source code on https://github.com/avsm/setup-ocaml/
- Hello World usage on https://github.com/avsm/hello-world-action-ocaml
- Usage in ocaml-yaml:
This should be considered fairly experimental as GH Actions is so new. If you do use it, then consider updating this issue with your usage. It does not current supporting caching yet, but is pretty fast to bootstrap (~4minutes).
It also doesn't have any higher level purpose other than to set up an opam environment, since most of the additional functionality such as revdeps testing is planned for addition to the ocurrent DSL. Nevertheless, this GH feature will hopefully be useful for smaller projects without a lot of computational requirements. Let me know how it goes!
Windows is currently supported through @fdopen's excellent fork that uses Cygwin. As Windows support is being mainlined into opam itself at the moment, I'm hoping that we will gradually move over to that. That should eventually remove the need for two separate opam-repositories, so I won't be adding any features that are Linux or macOS-specific and do not work on the Cygwin version.
OCurrent 0.1 (CI/CD pipeline eDSL)
Thomas Leonard announced
OCurrent 0.1 has just been released to opam-repository.
OCurrent is an OCaml eDSL intended for writing build/test/deploy pipelines. It is being used as the engine for ocaml-ci and the docker-base-images builder (used to build the OCaml Docker images, such as ocurrent/opam:alpine-3.10-ocaml-4.08
). Other good uses might be building and redeploying a Docker service or a unikernel whenever its source repository changes. It can be run locally as a single Unix process.
An OCurrent pipeline is written as an OCaml program, but the OCurrent engine ensures that it is kept up-to-date by re-running stages when their inputs change. A web UI is available so you can view your pipeline and see its current state.
OCurrent can statically analyse the pipelines before they have run, allowing it to run steps in parallel automatically and to display the whole pipeline. It does this using a light-weight alternative to arrows, which doesn't require programming in an awkward point-free style. See CI/CD Pipelines: Monad, Arrow or Dart? for more about that.
The basic functionality can be extended using "plugins" (just normal OCaml libraries). Plugins are available for interacting with Docker, Git, GitHub and Slack. These are in separate packages (e.g. current_github
) to avoid having the base package pull in too many dependencies).
There is also an optional Cap'n Proto RPC interface, in the current_rpc
opam package. This is used, for example, by citty to provide a TTY interface to ocaml-ci.
The OCurrent wiki contains examples, and documentation on the various plugins.
Here's an example pipeline (from the base image builder):
Anil Madhavapeddy then added
For those curious about the relation to the existing CI used in opam-repository, then it is no coincidence that @talex5 is the author of both :-)
This DSL is the next iteration of the datakit-ci, but specialised to be faster and simpler for extending with OCaml and more complex workflows that our OCaml Platform tools need these days (like ocamlformat linting, or dune expect promotion, or odoc cross-referenced doc generation). We are planning a smooth migration next year over to the new system, but wanted to release this early to show you some of the pieces going into this new iteration. I am particularly excited about the new tty-based interface that saves an awful lot of clicking around on web UIs for CI results…
New pages for OCaml API
Continuing this thread, sanette announced
I have uploaded a new version (same link https://sanette.github.io/ocaml-api/)
- background color for links in the TOC @Maelan
- more indentation for value descriptions @Maelan, @grayswandyr
- word wrapping long
<pre>
codes @grayswandyr - type table: remove
(*
and*)
, give more space to code wrt comments, diminish comment's color @grayswandyr
searching is not ready yet… please wait suggestions for dark theme welcome
sanette later added
I have just uploaded a new version with a basic search engine.
- for each page, you can search values/modules
- in the general index page, the search includes also the descriptions
- search results are ranked by relevance
the downside is that each page now comes with an index of about 570Kb in the form of an index.js file. I'm kind of hoping that the browser will cache this, but I'm not sure. It would be maybe better to only load the index file on demand.
Irmin 2.0.0 release
Thomas Gazagnaire announced
On behalf of the Irmin development team, I am very happy to announce the release of Irmin 2.0.0, a major release of the Git-like distributed branching and storage substrate that underpins MirageOS. We began the release process for all the components that make up Irmin back in May 2019, and there have been close to 1000 commits since Irmin 1.4.0 released back in June 2018. To celebrate this milestone, we have a new logo and opened a dedicated website: irmin.org.
More details here: https://tarides.com/blog/2019-11-21-irmin-v2
Tail cascade: a new indentation style for some OCaml constructs
Archive: https://discuss.ocaml.org/t/tail-cascade-a-new-indentation-style-for-some-ocaml-constructs/4736/1
gasche announced
I recently decided to change my indentation style for certain OCaml constructs in a way that I'm going to describe below. I just coined a name for this approach, "tail cascade". I'm creating this topic to convince everyone that this is a cool idea you should adopt as well. Or at least tolerate it when you review other people's code.
Problem
Programs that heavily use match
often see a shift to the right due to nested indentation.
match foo with | Foo -> ... | Bar x -> match bar x with | FooBar -> ... | Blah y -> match f y with | Some z -> ...
Another problem with this style is that it suffers from the "dangling bar" issue: if you try to add a new case for one of the exterior match
, it is parsed as belonging to the innermost match
. People have been recommending (rightly) to use begin match .. end
for all nested match constructs to avoid this issue.
match foo with | Foo -> ... | Bar x -> begin match bar x with | FooBar -> ... | Blah y -> begin match f y with | None -> ... | Some z -> ... end (* now this is safe *) | FooBlah -> ... end
But still the unpleasant shift to the right remains.
Proposal: cascading tail case
We should in general use begin match .. end
for nested matches. But the "cascading tail case" proposal is to not do it for the last case of the pattern-matching, and instead de-indent (dedent) this last case – tail case.
match foo with | Foo -> ... | Bar x -> match bar x with | FooBar -> ... | Blah y -> match f y with | None -> ... | Some z -> ...
Note that with this indentation style, the "dangling match" problem is also avoided: unlike with the original, non end
-protected program, the indentation makes it immediately obvious that any further case will be attached to the innermost match, and not any of the exterior ones.
A program using this "cascading tail" approach should always use begin match .. end
for nested matches, except for a nested match returned within the last branch of an outer match, which can (optionally) be dedented instead.
The choice to dedent the last case corresponds to encouraging a sequential reading of the program, where the other cases are "auxiliary cases" checked first and dispatched quickly, and the last case is the "main part" where the "rest" of the logic of the program lies. This pattern is typical of nested pattern-matching on the option
or result
type for example:
match foo x with | Error err -> fail_foo_error err | Ok y -> match bar y with | Error err -> fail_bar_error err | Ok () -> ...
Remark: it is not always the case that the Error
constructor is the auxiliary case, and the Ok
constructor is the main case; sometimes we implement fallback logic like "if foo
work then we are good, but otherwise we have to do this and that", and the error case is the most salient (and longer) part of the program logic. I would recommend being mindful, when you write code, of whether there is a most convincing way to "sequentialize" it (distinguish auxiliary and main/tail case), and avoid using cascading tails when there is no clear sequentialization choice.
Remark: some cases of tail cascades can be linearized by using a good definition of "bind" and a monadic style. This tends to be very limited however: it fixes one of the constructors to always be the "tail" constructor (always Some
, always Ok
), and it only works when the handling of the other constructors is very homogeneous (typically: return directly). In real code, many situations occur where the monadic style doesn't fit the problem, but tail cascade does help writing a readable program.
Generalization: tail cascade
While I have never seen cascading tail cases in real-world OCaml code before (I'm happy to be given pointers; I think that the idea is not new, but I'm not aware of previous attempts to give it a catchy name and spread the cascade love), this is in fact a new (to me) instance of a common technique that is used for other OCaml constructs:
if foo x then ... else if bar x then ... else ... (* this `tail else` was dedented *) let x = foo in let y = bar in (* this `tail let` was dedented *) ... (* and the rest as well *) bind foo @@ fun x -> bind bar @@ fun y -> (* this "tail function body" was dedented *) ... (* and the rest as well *)
I would call "tail cascade" (or maybe: "cascading tail") the idea of dedenting the "rest" of an OCaml expression (compared to a strict tree-nesting-based approach) when it morally describes the "rest" of the expression. I use the name "tail" because those expressions are almost always in tail-position in the sense of tail-calls.
This general approach legitimizes some styles that I have seen, and sometimes used, in the wild, while at the same time considering that I may have been doing something improper, for example:
if foo then blah else ... (* dedented *) Fun.protect ~finally:(...) @@ fun () -> ... (* dedented *) try simple_approach with exn -> ... (* dedented *) 1 + 2 + (* dedented *) ... (* dedented *)
Remark: after a then
or else
, many people share the reasonable view that any expression containing imperative constructs (foo; bar
) should be enclosed in a begin .. end
block to avoid surprising-precedence issue. Just as for nested match
, this recommendation should be lifted for "tail else" constructs.
Remark: The last example is a case where the dedented expressions are not in tail-position from a runtime-evaluation point of view. I am not sure as whether the two notions should be made to coincide more strongly, but in any case I'm not fond of the style in this particular example, I prefer to move the infix operator to the beginning of the next line instead, following a different style and justification.
The possibility this "cascading tail" style today crucially relies on the nesting properties of open-ended syntactic constructs, notably let
(commonly cascaded), and now match
and if ... else
. Proposals to transition to a syntax where match
and else
are forced to take a closing marker are incompatible with the cascading style. I have not made my mind on whether this should be considered a blocker for those proposals, but at least it shows that having the open-ended form available has value for certain programs.
Louis Gesbert then said
@gasche I prototyped a dedicated option in ocp-indent
, if you're interested in trying it out :)
opam pin git+https://github.com/OCamlPro/ocp-indent#match-tail-cascade echo "match_tail_cascade=true" >> ~/.ocp-indent
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.