OCaml Weekly News
Hello
Here is the latest OCaml Weekly News, for the week of June 25 to July 02, 2019.
Table of Contents
Learn Ocsigen: Graffiti tutorial updated
Vincent Balat announced
Graffiti tutorial explains step by step how to write a multi-user client-server drawing application in OCaml.
It is the best starting point for beginners with Ocsigen.
An updated version of this tutorial is now online, thanks to corentinjuvigny and chrismamo1.
Please report any problem (mistakes etc.) here.
Release of OCamlFormat 0.10
Guillaume Petiot announced
Release of OCamlFormat 0.10
We are pleased to announce the release of OCamlFormat 0.10 (available on opam).
There have been numerous changes since the last release, so here is a comprehensive list of the new features and breaking changes to help the transition from OCamlFormat 0.9.
ocamlformat-0.10
now works on the 4.08 AST, although the formatting should not differ greatly from the one of ocamlformat-0.9
in this regard.
Please note that it is necessary to build ocamlformat
with 4.08 to be able to parse new features like let*
.
Upgrading from ocamlformat-0.9
requires to install the following dependencies:
- ocaml-migrate-parsetree >= 1.3.1 (upgrade)
- uuseg >= 10.0.0 (new)
- uutf >= 1.0.1 (upgrade)
This release focuses on preserving the style of the original source and on handling more ocp-indent
options.
Style preservation
- Expression grouping
The new option
exp-grouping
has been added to preserve the keywordsbegin~/~end
that are used to delimit expressions instead of parentheses.exp-grouping=parens
always uses parentheses to delimit expressions.exp-grouping=preserve
preserves the original grouping syntax (parentheses orbegin~/~end
). - Horizontal alignment
Horizontal alignment is something that users often use to make pattern-matching or type declarations easier to read, and it is a feature that has been requested many times. Three new options have been added to horizontally align the lines.
align-cases
horizontally aligns the match/try cases:let fooooooooooo = match foooooooooooooooooooooooo with | Bfooooooooooooooooo -> foooooooooooo | C (a, b, c, d) -> fooooooooooooooooooo | _ -> fooooooooooooooooooo
align-constructors-decl
horizontally aligns type declarations:type t = | ( :: ) of a * b | [] of looooooooooooooooooooooooooooooooooooooong_break
align-variants-decl
horizontally aligns variants type declarations:type x = [ ~Foooooooo of int | ~Fooooooooooooo of int ]
- Preserve blank lines in sequences
The new option
sequence-blank-line
decides whether a blank line is preserved between expressions of a sequence.sequence-blank-line=compact
will not keep any blank line between expressions of a sequence, this is still the default behavior.sequence-blank-line=preserve
will keep a blank line between two expressions of a sequence if the input contains at least one.This option can help preserving the readability of the code in this situation:
let foo x y = do_some_setup y ; important_function x
Supporting more ocp-indent
options
The long term goal of ocamlformat
is to handle every ocp-indent
option, this release got closer to this goal as the following ocp-indent
options are now supported by ocamlformat
:
- max_indent
- with
- strict_with
- ppx_stritem_ext
- base
- in
- type
- Offset added to a new line
The new option
max-indent
sets the maximum offset (number of columns) added to a new line in addition to the offset of the previous line. If this offset is set to 2 columns, then each new line can only be indented by 2 columns more in addition to the previous line, for example:let () = fooooo |> List.iter (fun x -> let x = x $ y in fooooooooooo x)
This option is equivalent to the
max_indent
option ofocp-indent
, and it will be set ifmax_indent
is set in an.ocp-indent
configuration file. - Indentation of pattern matching cases
The new options
funtion-indent
andmatch-indent
respectively decide the indentation of function cases and the indentation of match/try cases. These options are equivalent to thewith
option ofocp-indent
, and they will be set ifwith
is set in anocp-indent
configuration file. If the indentation is set to 4 columns, cases are formatted like this:let foooooooo = function | fooooooooooooooooooooooo -> foooooooooooooooooooooooooo let foooooooo = match fooooooooooooooooooooooo with | fooooooooooooooooooooooo -> foooooooooooooooooooooooooo
The new options
function-indent-nested
andmatch-indent-nested
respectively decide whether thefunction-indent
and thematch-indent
parameters should be applied even when in a sub-block. If these options are set tonever
, it only appliesfunction-indent
ormatch-indent
if the function or match block starts a line. If these options are set toalways
, then the indent parameters are always applied. Theauto
value applies the indentation parameter when seen fit.These options are equivalent to the
strict_with
option ofocp-indent
, and they will be set ifstrict_with
is set in anocp-indent
configuration file. - Indentation inside extension nodes
The new option
extension-indent
sets the indentation of items (that are not at structure level) inside extension nodes. The new optionstritem-extension-indent
sets the indentation of structure items inside extension nodes. This option is equivalent to theppx_stritem_ext
option ofocp-indent
, and it will be set ifppx_stritem_ext
is set in an.ocp-indent
configuration file.For example if
extension-indent
is set to 5 andstritem-extension-indent
is set to 3:let foo = [%foooooooooo fooooooooooooooooooooooooooo foooooooooooooooooooooooooooooooooo foooooooooooooooooooooooooooo] [@@foooooooooo fooooooooooooooooooooooooooo foooooooooooooooooooooooooooooooooo foooooooooooooooooooooooooooo] [@@@foooooooooo fooooooooooooooooooooooooooo foooooooooooooooooooooooooooooooooo foooooooooooooooooooooooooooo]
- Let-binding indentation
The new option
let-binding-indent
sets the indentation of let binding expressions if they do not fit on a single line. This option is equivalent to thebase
option ofocp-indent
. The new optionindent-after-in
sets the indentation afterlet ... in
, unless followed by anotherlet
. This option is equivalent to thein
option ofocp-indent
. The new optiontype-decl-indent
sets the indentation of type declarations if they do not fit on a single line. This option is equivalent to thetype
option ofocp-indent
.These options will be set if their
ocp-indent
counterparts are set in an.ocp-indent
configuration file.
Miscellaneous features
This release also brings some new options, new values for existing features, or corrects erroneous behaviours.
- Indicate multiline delimiters
The former
indicate-multiline-delimiters
boolean option is now a 3-valued option:indicate-multiline-delimiters=space
(was equivalent totrue
) prints a space inside the delimiter to indicate the matching one is on a different line.indicate-multiline-delimiters=no
(was equivalent tofalse
) doesn't do anything special to indicate the closing delimiter.indicate-multiline-delimiters=closing-on-separate-line
is the new feature of this option, it makes sure that the closing delimiter is on its own line.
On this example we can see the closing parenthesis delimiting the nested pattern-matchings are on their own line and are aligned with the matching opening parenthesis:
let () = match v with | None -> None | Some x -> ( match x with | None -> None | Some x -> ( match x with | None -> None | Some x -> x ) )
- Formatting of literal strings
break-string-literals=newlines
now takes into account pretty-printing commands like@,
,@;
and@\n
to produce more readable strings. A new value for this option has been added,break-string-literals=newlines-and-wrap
, to break lines at newlines delimiters (including pretty-printing commands) and also wrap the string literals at the margin.Here is how
break-string-literals=newlines-and-wrap
formats a string:let fooooooooooo = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod \ tempor incididunt ut labore et dolore magna aliqua.@;\ Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi \ ut aliquip ex ea commodo consequat.@;\ Duis aute irure dolor in reprehenderit in voluptate velit esse cillum \ dolore eu fugiat nulla pariatur.@;\ Excepteur sint occaecat cupidatat non proident, sunt in culpa qui \ officia deserunt mollit anim id est laborum."
Warning: the
break-string-literals
will likely be removed in the next release and the default behavior would benewlines-and-wrap
. - Break before the
in
keyword
The new option
break-before-in
has been added to decide whether the line should break before thein
keyword of alet
binding.break-before-in=fit-or-vertical
will always break the line before thein
keyword if the wholelet
binding does not fit on a single line, it is still the default behavior.break-before-in=auto
will only break the line if thein
keyword does not fit on the previous line.For example:
let _ = let short = this is short in let fooo = (this is very long) but (the in keyword can fit) on the same line in foooooo
- Indentation of nested pattern-matching
The new option
nested-match
defines the style of pattern-matchings nested in the last case of another pattern-matching.nested-match=wrap
wraps the nested pattern-matching with parentheses and adds indentation, this is still the default behavior.nested-match=align
vertically aligns the nested pattern-matching under the encompassing pattern-matching, for example:let () = match v with | None -> None | Some x -> match x with | None -> None | Some x -> x
The new option
cases-matching-exp-indent
decides the indentation of cases right-hand sides which arematch
ortry
expressions.cases-matching-exp-indent=compact
forces an indentation of 2, unlessnested-match
is set toalign
and this is the last case of the pattern matching.compact
is the default behavior.cases-matching-exp-indent=normal
indents as it would any other expression. - Whitelist of files to format
A new kind of configuration files is now handled by
ocamlformat
:.ocamlformat-enable
files. If thedisable
option is set, an.ocamlformat-enable
file can list the files thatocamlformat
should format even when thedisable
option is set. Each line in an.ocamlformat-enable
file specifies a filename relative to the directory containing the.ocamlformat-enable
file.The
.ocamlformat-enable
files are using the same syntax as the.ocamlformat-ignore
files: lines starting with#
are ignored and can be used as comments.These new configuration files do not contradict the existing
.ocamlformat-ignore
files, as.ocamlformat-enable
are only considered whendisable
is set, and.ocamlformat-ignore
are only considered whendisable
is not set. - Disable outside detected project
The
disable-outside-detected-project
option is now set by default.When the option
--enable-outside-detected-project
is not set,.ocamlformat
files outside of the project (including the one inXDG_CONFIG_HOME
) are not read. The project root of an input file is taken to be the nearest ancestor directory that contains a .git or .hg or dune-project file. If no config file is found, formatting is disabled. - Space around collection-expressions
The former option
space-around-collection-expressions
that was deciding whether a space should be added inside the delimiters of collection expressions (lists, arrays, records, variants) has been replaced by 4 new options:space-around-arrays
,space-around-lists
,space-around-records
andspace-around-variants
, to allow a finer grain customization. - Fit-or-vertical mode for pattern matching
The
break-cases
option that decides the shape of pattern matching has a new valuefit-or-vertical
.break-cases=fit-or-vertical
tries to fit all or-patterns on the same line, otherwise breaks each or-pattern (they are wrapped in other modes). For example if this set of or-patterns does not fit on a single line, we get the following output:let ffffff = match foooooooooooo with | Aaaaaaaaaaaaaaaaa | Bbbbbbbbbbbbbbbbb | Ccccccccccccccccc | Ddddddddddddddddd | Eeeeeeeeeeeeeeeee -> foooooooooooooooooooo | Fffffffffffffffff -> fooooooooooooooooo
- K&R style for if-then-else
The
if-then-else
option now has a new valuek-r
that uses parentheses (when necessary) to reproduce a formatting close to the K&R style. For example:let _ = if b then ( something loooooooooooooooooooooooooooooooong enough to_trigger a break ; this is more ) else if b1 then ( something loooooooooooooooooooooooooooooooong enough to_trigger a break ; this is more ) else e
Breaking changes
- the
indicate-multiline-delimiters
option is no longer a boolean option but now has 3 values:space
,no
andclosing-on-separate-line
that are detailed in this patch note. - the
disable-outside-detected-project
option is now set by default. - the
default
preset profile has been removed (it was equivalent to theocamlformat
profile withbreak-cases=fit
). - the
space-around-collection-expressions
option has been replaced by 4 new options:space-around-arrays
,space-around-lists
,space-around-records
andspace-around-variants
.
What's next?
We strongly encourage our users to try out the conventional
preset profile, as we plan to make it the default profile in a future release. This profile's purpose is to reproduce the most commonly encountered styles, and it may be more pleasing to the eye than the current default options.
As stated previously, the break-string-literals
will likely be removed in the next release and the default behavior would be newlines-and-wrap
.
Credits
This release also contains many other changes and bug fixes that we cannot detail here.
We would like to thank our maintainers and contributors for this release: Jules Aguillon, Josh Berdine, Hugo Heuzard, Guillaume Petiot and Thomas Refis, and especially our industrial users Jane Street, Ahrefs and Nomadic Labs that made this work possible by funding this project and providing helpful contributions and feedback.
We would be happy to provide support for more customers, please contact us at contact@tarides.com
If you wish to get involved with OCamlFormat development or file an issue, please read the contributing guide, any contribution is welcomed.
Ocaml 4.09.0+beta1
Damien Doligez announced
The release of OCaml 4.09.0 is approaching. We have created a beta version to help you prepare for the release.
The source code is available at these addresses:
https://github.com/ocaml/ocaml/archive/4.09.0+beta1.tar.gz
https://caml.inria.fr/pub/distrib/ocaml-4.09/ocaml-4.09.0+beta1.tar.gz
The compiler can also be installed as an OPAM switch with one of the following commands.
opam switch create ocaml-variants.4.09.0+beta1 --repositories=default,beta=git+https://github.com/ocaml/ocaml-beta-repository.git
or
opam switch create ocaml-variants.4.09.0+beta1+<VARIANT> --repositories=default,beta=git+https://github.com/ocaml/ocaml-beta-repository.git
where you replace <VARIANT> with one of these:
- afl
- default_unsafe_string
- flambda
- fp
- fp+flambda
We want to know about all bugs. Please report them here: https://github.com/ocaml/ocaml/issues
Parallel and distributed execution of command lines, pardi!
Archive: https://discuss.ocaml.org/t/ann-parallel-and-distributed-execution-of-command-lines-pardi/4015/1
UnixJunkie announced
I am pleased to announce the first release of pardi (which the community recently helped to debug):
https://github.com/UnixJunkie/pardi
Pardi is a command line tool to parallelize programs which are not parallel; provided that you can cut an input file into independent chunks.
For example, to compress a file in parallel using 1MB chunks:
pardi -d b:1048576 -m s -i <YOUR_BIG_FILE> -o <YOUR_BIG_FILE>.gz \ -w 'xz -c -9 %IN > %OUT'
Using the right option, you can cut an input file by lines (e.g. SMI files), by number of bytes (for binary files), by separating lines verifying a regexp (quite generic) or by a block separating line (e.g. MOL2/SDF/PDB file formats).
If processing a single record of your input file is too fine grained, you can play with the -c option to reach better parallelization (try 10,20,50,100,200,500,etc).
usage: pardi ... {-i|--input} <file>: where to read from (default=stdin) {-o|--output} <file>: where to write to (default=stdout) {-n|--nprocs} <int>: max jobs in parallel (default=all cores) {-c|--chunks} <int>: how many chunks per job (default=1) {-d|--demux} {l|b:<int>|r:<regexp>|s:<string>}: how to cut input file into chunks (line/bytes/regexp/sep_line; default=line) {-w|--work} <string>: command to execute on each chunk {-m|--mux} {c|s|n}: how to mux job results in output file (cat/sorted_cat/null; default=cat)
Other OCaml News
From the ocamlcore planet blog
Here are links from many OCaml blogs aggregated at OCaml Planet.
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.