<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><icon>http://ocaml.org/img/colour-icon-170x148.png</icon><generator uri="https://github.com/Cumulus/Syndic" version="1.5.3">OCaml Syndic.Atom feed aggregator</generator><id>urn:md5:ef9ae3771cdabc5f783dfcc323845980</id><title type="text">OCaml Planet</title><updated>2017-05-11T20:18:34-00:00</updated><entry><source><updated>2017-05-11T20:18:34-00:00</updated><subtitle xml:base="http://blog.shaynefletcher.org/feeds/posts/default/-/OCaml" type="html">&quot;Hooked&quot; on programming</subtitle><link type="application/atom+xml" href="http://www.blogger.com/feeds/5012565255225108517/posts/default/-/OCaml/-/OCaml?start-index=26&amp;max-results=25" rel="next"/><link href="http://pubsubhubbub.appspot.com/" rel="hub"/><link type="text/html" href="http://blog.shaynefletcher.org/search/label/OCaml" rel="alternate"/><link type="application/atom+xml" href="http://www.blogger.com/feeds/5012565255225108517/posts/default/-/OCaml" rel="self"/><link type="application/atom+xml" href="http://blog.shaynefletcher.org/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed"/><generator uri="http://www.blogger.com" version="7.00">Blogger</generator><category term="recursive descent"/><category term="ppx"/><category term="ppf"/><category term="left recursion"/><category term="grammars"/><category term="balanced binary search trees"/><category term="Windows 8.1"/><category term="Windows 7"/><category term="Variance"/><category term="Universal type"/><category term="Universal Gas Constant"/><category term="Tail recursion"/><category term="Subtyping"/><category term="Stack overflow"/><category term="Sorting"/><category term="Simulation"/><category term="Sieve of Eratosthenes"/><category term="Science"/><category term="Rings"/><category term="Recursion"/><category term="Priority queue"/><category term="Pretty-printing"/><category term="Poof"/><category term="Polynomials"/><category term="Polymorphic variants"/><category term="Permutation"/><category term="Pascal"/><category term="Numerical analysis"/><category term="Monty Hall"/><category term="Modules"/><category term="List comprehensions"/><category term="Leftist heap"/><category term="Labeled arguments"/><category term="Ideal Gas Law"/><category term="Horner's rule"/><category term="Functors"/><category term="Financial Modeling in Python"/><category term="Exponentiation by squaring"/><category term="Compression"/><category term="Combination"/><category term="Church-Turing thesis"/><category term="Church numerals"/><category term="Cartesian product"/><category term="Algorithmic complexity"/><category term="64-bit"/><category term="type-classes"/><category term="ocamlyacc"/><category term="ocamllex"/><category term="Y Combinator"/><category term="Taylor polynomials"/><category term="Streams"/><category term="Recursive lists"/><category term="Prolog"/><category term="Monads"/><category term="Dimensional analysis"/><category term="Algebra"/><category term="Regular expressions"/><category term="Powerset"/><category term="Statistics"/><category term="Lexical analysis"/><category term="Haskell"/><category term="Parsing"/><category term="data structures"/><category term="Symbolic computation"/><category term="Lambda calculus"/><category term="Felix"/><category term="Boost"/><category term="Python"/><category term="Algorithms"/><category term="C++"/><category term="Functional programming"/><category term="OCaml"/><id>tag:blogger.com,1999:blog-5012565255225108517</id><title type="text">Shayne Fletcher</title><author><email>noreply@blogger.com</email><name>Shayne Fletcher</name></author></source><published>2017-05-11T20:17:00-00:00</published><link title="Proving a &lt;code&gt;mem&lt;/code&gt;/&lt;code&gt;map&lt;/code&gt; property" type="text/html" href="http://blog.shaynefletcher.org/2017/05/proving-mem-map-property.html" rel="alternate"/><link type="application/atom+xml" href="http://www.blogger.com/feeds/5012565255225108517/posts/default/9078557494145961323" rel="self"/><link type="application/atom+xml" href="http://www.blogger.com/feeds/5012565255225108517/posts/default/9078557494145961323" rel="edit"/><content xml:base="http://blog.shaynefletcher.org/feeds/posts/default/-/OCaml" type="html">&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01//EN&quot;           &quot;http://www.w3.org/TR/html4/strict.dtd&quot;&gt;&lt;html&gt;  &lt;head&gt;    &lt;title&gt;&lt;/title&gt;  &lt;/head&gt;  &lt;body&gt;    &lt;p&gt;      Here are two well known &quot;classic&quot; functions over polymorphic       lists.     &lt;/p&gt;    &lt;p&gt;      &lt;code&gt;map f l&lt;/code&gt; computes a new list from &lt;code&gt;l&lt;/code&gt;      by applying &lt;code&gt;f&lt;/code&gt; to each of its elements.       &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;        let rec map (f : &amp;alpha; &amp;rarr; &amp;beta;) : &amp;alpha; list &amp;rarr; &amp;beta; list = function&lt;br /&gt;        | [] &amp;rarr; []&lt;br /&gt;        | h :: t &amp;rarr; f h :: map f t&lt;br /&gt;        ;;&lt;br /&gt;      &lt;/pre&gt;    &lt;/p&gt;     &lt;p&gt;&lt;code&gt;mem x l&lt;/code&gt; returns &lt;code&gt;true&lt;/code&gt; is &lt;code&gt;x&lt;/code&gt;      is an element of &lt;code&gt;l&lt;/code&gt; and returns &lt;code&gt;false&lt;/code&gt; if it       is not.       &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;        let rec mem (a : &amp;alpha;) : &amp;alpha; list &amp;rarr; bool  = function&lt;br /&gt;        | [] &amp;rarr; false&lt;br /&gt;        | x :: l &amp;rarr; a = x || mem a l&lt;br /&gt;        ;;&lt;br /&gt;      &lt;/pre&gt;    &lt;/p&gt;    &lt;p&gt;      If &lt;code&gt;y&lt;/code&gt; is an element of the list obtained by       mapping &lt;code&gt;f&lt;/code&gt; over &lt;code&gt;l&lt;/code&gt; then there must be an       element &lt;code&gt;x&lt;/code&gt; in &lt;code&gt;l&lt;/code&gt; such that &lt;code&gt;f x =         y&lt;/code&gt;. Conversely, if there exists an &lt;code&gt;x&lt;/code&gt;      in &lt;code&gt;l&lt;/code&gt; such that &lt;code&gt;y = f x&lt;/code&gt;,       then &lt;code&gt;y&lt;/code&gt; must be a member of the list obtained by       mapping &lt;code&gt;f&lt;/code&gt; over &lt;code&gt;l&lt;/code&gt;.    &lt;/p&gt;    &lt;p&gt;      We attempt a proof of correctness of the given definitions with       respect to this property.     &lt;/p&gt;     &lt;b&gt;Lemma&lt;/b&gt; &lt;code&gt;mem_map_iff&lt;/code&gt;:     &lt;pre&gt;&lt;br /&gt;    &amp;forall; (f : &amp;alpha; &amp;rarr; &amp;beta;) (l : &amp;alpha; list) (y : &amp;beta;),&lt;br /&gt;        mem y (map f l) &amp;iff; &amp;exist;(x : &amp;alpha;), f x = y &amp;and; mem x l.&lt;br /&gt;    &lt;/pre&gt;    &lt;b&gt;Proof:&lt;/b&gt;&lt;br/&gt;    &lt;ul&gt;       &lt;li&gt;We first treat the forward implication         &lt;pre&gt;&lt;br /&gt;    &amp;forall; (f : &amp;alpha; &amp;rarr; &amp;beta;) (l : &amp;alpha; list) (y : &amp;beta;), &lt;br /&gt;      mem y (map f l) &amp;Implies; &amp;exist;(x : &amp;alpha;), f x = y &amp;and; mem x l&lt;br /&gt;        &lt;/pre&gt;        and proceed by induction on &lt;code&gt;l&lt;/code&gt;.         &lt;br/&gt;        &lt;br/&gt;         &lt;ul&gt;          &lt;li&gt;&lt;code&gt;l = []&lt;/code&gt;:             &lt;ul&gt;              &lt;li&gt;Show &lt;code&gt;mem y (map f []) &amp;Implies; &amp;exist;(x : &amp;alpha;), f x = y &amp;and; mem x []&lt;/code&gt;.&lt;/li&gt;              &lt;li&gt;&lt;code&gt;mem y (map f []) &amp;equiv; False&lt;/code&gt;.&lt;/li&gt;              &lt;li&gt;Proof follows &lt;i&gt;(ex falso quodlibet)&lt;/i&gt;.&lt;/li&gt;            &lt;/ul&gt;            &lt;br/&gt;          &lt;/li&gt; &lt;!-- l is empty --&gt;         &lt;li&gt;&lt;code&gt;l&lt;/code&gt; has form &lt;code&gt;x' :: l&lt;/code&gt; (use &lt;code&gt;l&lt;/code&gt; now to refer to the tail):             &lt;ul&gt;              &lt;li&gt;Assume the induction hypothesis:                 &lt;ul&gt;&lt;li&gt;&lt;code&gt;mem y (map f l) &amp;Implies; &amp;exist;x, f x = y &amp;and; mem x l&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;              &lt;li&gt;We are required to show for an arbitrary &lt;code&gt;(x' : &amp;alpha;)&lt;/code&gt;:                 &lt;ul&gt;&lt;li&gt;&lt;code&gt;mem y (map f (x' :: l)) &amp;Implies; &amp;exist;(x : &amp;alpha;), f x = y &amp;and; mem x (x' :: l)&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;              &lt;/li&gt;              &lt;li&gt;By simplification, we can rewrite the above to:                 &lt;ul&gt;&lt;li&gt;&lt;code&gt;f x' = y &amp;or; mem y (map f l) &amp;Implies; &amp;exist;(x : &amp;alpha;), f x = y &amp;and; (x' = x &amp;or; mem x l).&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;              &lt;/li&gt;              &lt;li&gt;We assume then an &lt;code&gt;(x' : &amp;alpha;)&lt;/code&gt; and a &lt;code&gt;(y : &amp;beta;)&lt;/code&gt; such                 that:                 &lt;ol&gt;                  &lt;li&gt;&lt;code&gt;f x' = y &amp;or; mem y (map f l)&lt;/code&gt;.&lt;/li&gt;                  &lt;li&gt;&lt;code&gt;mem y (map f l) &amp;Implies; &amp;exist;(x : &amp;alpha;), f x = y &amp;and; mem x l&lt;/code&gt;.&lt;/li&gt;                &lt;/ol&gt;              &lt;/li&gt;              &lt;li&gt;Show &lt;code&gt;&amp;exist;(x : &amp;alpha;), f x = y &amp;and; (x' = x &amp;or; mem x l).&lt;/code&gt;                &lt;ul&gt;                  &lt;li&gt;First consider &lt;code&gt;f x' = y&lt;/code&gt; in (1).                     &lt;ul&gt;                      &lt;li&gt;Take &lt;code&gt;x = x'&lt;/code&gt; in the goal.&lt;/li&gt;                      &lt;li&gt;Then by (1) &lt;code&gt;f x = y &amp;and; x = x'&lt;/code&gt;.&lt;/li&gt;                      &lt;li&gt;So &lt;code&gt;x'&lt;/code&gt; is a witness.&lt;/li&gt;                    &lt;/ul&gt;                  &lt;/li&gt;                  &lt;li&gt;Now consider &lt;code&gt;mem y (map f l)&lt;/code&gt; in (1).                     &lt;ul&gt;                      &lt;li&gt;&lt;code&gt;&amp;exist;(x&lt;sup&gt;*&lt;/sup&gt; : &amp;alpha;), f x&lt;sup&gt;*&lt;/sup&gt; = y &amp;and; mem x&lt;sup&gt;*&lt;/sup&gt; l&lt;/code&gt; by (2).&lt;/li&gt;                      &lt;li&gt;Take &lt;code&gt;x = x&lt;sup&gt;*&lt;/sup&gt;&lt;/code&gt; in the goal.&lt;/li&gt;                      &lt;li&gt;By the above &lt;code&gt;f x&lt;sup&gt;*&lt;/sup&gt; = y &amp;and; mem x&lt;sup&gt;*&lt;/sup&gt; l&lt;/code&gt;&lt;/li&gt;                      &lt;li&gt;So &lt;code&gt;x&lt;sup&gt;*&lt;/sup&gt;&lt;/code&gt; is a witness&lt;/code&gt;.&lt;/li&gt;                    &lt;/ul&gt;                  &lt;/li&gt;                &lt;/ul&gt;              &lt;/li&gt;            &lt;/ul&gt;          &lt;/li&gt; &lt;!-- l is non-empty --&gt;        &lt;/ul&gt;        &lt;br/&gt;&lt;/br&gt;      &lt;/li&gt;&lt;!-- Forward implication --&gt;       &lt;li&gt;      We now work on the reverse implication. We want to show that       &lt;pre&gt;&lt;br /&gt;    &amp;forall; (f : &amp;alpha; &amp;rarr; &amp;beta;) (l : &amp;alpha; list) (y : &amp;beta;),&lt;br /&gt;       &amp;exist;(x : &amp;alpha;), f x = y &amp;and; mem x l &amp;Implies; mem y (map f l)&lt;br /&gt;      &lt;/pre&gt;      and proceed by induction on &lt;code&gt;l&lt;/code&gt;.       &lt;br/&gt;&lt;br/&gt;      &lt;ul&gt;        &lt;li&gt;&lt;code&gt;l = []:&lt;/code&gt;        &lt;ul&gt;          &lt;li&gt;Assume &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt; with &lt;code&gt;f x = y &amp;and; mem x []&lt;/code&gt;.&lt;/li&gt;          &lt;li&gt;Show &lt;code&gt;mem y (map f [])&lt;/code&gt;:&lt;/li&gt;           &lt;ul&gt;             &lt;li&gt;&lt;code&gt;mem x [] &amp;equiv; false&lt;/code&gt;.&lt;/li&gt;             &lt;li&gt;Proof follows &lt;i&gt;(ex falso quodlibet)&lt;/i&gt;.&lt;/li&gt;           &lt;/ul&gt;        &lt;/ul&gt;        &lt;/li&gt;&lt;!-- l = [] --&gt;         &lt;li&gt;&lt;code&gt;l&lt;/code&gt; has form &lt;code&gt;x' :: l&lt;/code&gt; (use &lt;code&gt;l&lt;/code&gt; now to refer to the tail):           &lt;ul&gt;            &lt;li&gt;Assume the induction hypothesis:             &lt;ul&gt;&lt;li&gt;&lt;code&gt;&amp;exist;(x : &amp;alpha;), f x = y &amp;and; mem x l &amp;Implies; mem y (map f l)&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;            &lt;/li&gt;            &lt;li&gt;We are required to show for an arbitrary &lt;code&gt;(x' : &amp;alpha;)&lt;/code&gt;:               &lt;ul&gt;&lt;li&gt;&lt;code&gt;&amp;exist; (x : &amp;alpha;), f x = y &amp;and; mem x (x' :: l) &amp;Implies; mem y (map f (x' :: l))&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;            &lt;/li&gt;            &lt;li&gt;By simplification, we can rewrite the above to:               &lt;ul&gt;&lt;li&gt;&lt;code&gt;&amp;exist; (x : &amp;alpha;), f x = y &amp;and; x = x' &amp;or; mem x l &amp;Implies; f x' = y &amp;or; mem y (map f l)&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;            &lt;/li&gt;            &lt;li&gt;Assume the goal and induction hypotheses:               &lt;ul&gt;                &lt;li&gt;There is &lt;code&gt;(x : &amp;alpha;)&lt;/code&gt; and &lt;code&gt;(y : &amp;beta;)&lt;/code&gt; such that:                   &lt;ol&gt;                    &lt;li&gt;&lt;code&gt;f x = y &amp;and; (x = x' &amp;or; mem x l)&lt;/code&gt;&lt;/li&gt;                    &lt;li&gt;&lt;code&gt;f x = y &amp;and; mem x l &amp;Implies; mem y (map f l)&lt;/code&gt;&lt;/li&gt;                  &lt;/ol&gt;                &lt;/li&gt;              &lt;/ul&gt;            &lt;/li&gt;            &lt;li&gt;Show &lt;code&gt;f x' = y &amp;or; mem y (map f l)&lt;/code&gt;.               &lt;ul&gt;                &lt;li&gt;Assume &lt;code&gt;x = x'&lt;/code&gt; in (1) and show &lt;code&gt;f x' = y&lt;/code&gt;:                   &lt;ul&gt;                   &lt;li&gt;Since, &lt;code&gt;f x = y&lt;/code&gt; is given by (1.), &lt;code&gt;f x' = y&lt;/code&gt;.&lt;/li&gt;                  &lt;/ul&gt;                &lt;/li&gt;                &lt;li&gt;Assume &lt;code&gt;mem x l&lt;/code&gt; in (1) and show &lt;code&gt;mem y (map f l)&lt;/code&gt;:                   &lt;ul&gt;                      &lt;li&gt;Rewrite &lt;code&gt;mem y (map f l)&lt;/code&gt; via (2) to &lt;code&gt;f x = y &amp;and; mem x l&lt;/code&gt;.&lt;/li&gt;                    &lt;li&gt;&lt;code&gt;f x = y&lt;/code&gt; by (1) so &lt;code&gt;mem y (map f l)&lt;/code&gt;.&lt;/li&gt;                  &lt;/ul&gt;                &lt;/li&gt;              &lt;/ul&gt;            &lt;/li&gt;          &lt;/ul&gt;        &lt;/li&gt;&lt;!-- l is non-empty --&gt;      &lt;/ul&gt;      &lt;/li&gt;&lt;!-- Reverse implication --&gt;    &lt;/ul&gt;&amp;#8718;     &lt;hr/&gt;    &lt;p&gt;    References:&lt;br/&gt;    &lt;a href=&quot;https://www.cis.upenn.edu/~bcpierce/sf/current/index.html&quot;&gt;&quot;Sofware Foundations&quot;&lt;/a&gt; -- Pierce et. al.     &lt;/p&gt;  &lt;/body&gt;&lt;/html&gt;</content><category scheme="http://www.blogger.com/atom/ns#" term="Poof"/><category scheme="http://www.blogger.com/atom/ns#" term="OCaml"/><id>tag:blogger.com,1999:blog-5012565255225108517.post-9078557494145961323</id><title type="text">Proving a mem/map property</title><updated>2017-05-11T20:18:34-00:00</updated><author><email>noreply@blogger.com</email><uri>https://plus.google.com/104436573144909855029</uri><name>Shayne Fletcher</name></author></entry><entry><source><updated>2017-05-11T13:20:05-00:00</updated><logo>http://www.ocamlpro.com/wp-content/uploads/2016/02/cropped-favicon-32x32.png</logo><link title="OCamlPro" type="text/html" href="http://www.ocamlpro.com" rel="related"/><link title="OCamlPro" type="application/rss+xml" href="http://www.ocamlpro.com/feed/" rel="self"/><generator>https://wordpress.org/?v=4.7.4</generator><id>http://www.ocamlpro.com</id><title type="text">OCamlPro</title><author><name>OCamlPro</name></author></source><link href="http://www.ocamlpro.com/2017/05/11/new-opam-features-more-expressive-dependencies/" rel="alternate"/><link href="http://www.ocamlpro.com/2017/05/11/new-opam-features-more-expressive-dependencies/#respond" rel="related"/><content xml:base="http://www.ocamlpro.com/feed/" type="html">&lt;p&gt;This blog will cover yet another aspect of the improvements opam 2.0 has over opam 1.2. It may be a little more technical than previous issues, as it covers a feature directed specifically at packagers and repository maintainers, and regarding the package definition format.&lt;/p&gt;
&lt;h3 id=&quot;Specifyingdependenciesinopam12&quot;&gt;Specifying dependencies in opam 1.2&lt;/h3&gt;
&lt;p&gt;Opam 1.2 already has an advanced way of specifying package dependencies, using formulas on packages and versions, with the following syntax:&lt;/p&gt;
&lt;pre class=&quot;brush: bash; title: ; notranslate&quot;&gt;
depends: [
  &amp;quot;foo&amp;quot; {&amp;gt;= &amp;quot;3.0&amp;quot; &amp;amp; &amp;lt; &amp;quot;4.0~&amp;quot;}
  ( &amp;quot;bar&amp;quot; | &amp;quot;baz&amp;quot; {&amp;gt;= &amp;quot;1.0&amp;quot;} )
]
&lt;/pre&gt;
&lt;p&gt;meaning that the package being defined depends on both package &lt;code&gt;foo&lt;/code&gt;, within the &lt;code&gt;3.x&lt;/code&gt; series, and one of &lt;code&gt;bar&lt;/code&gt; or &lt;code&gt;baz&lt;/code&gt;, the latter with version at least &lt;code&gt;1.0&lt;/code&gt;. See &lt;a href='https://opam.ocaml.org/doc/Manual.html#PackageFormulas'&gt;here&lt;/a&gt; for a complete documentation.&lt;/p&gt;
&lt;p&gt;This only allows, however, dependencies that are static for a given package.&lt;/p&gt;
&lt;p&gt;Opam 1.2 introduced &lt;code&gt;build&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt; and &lt;code&gt;doc&lt;/code&gt; &amp;#8220;dependency flags&amp;#8221; that could provide some specifics for dependencies (&lt;em&gt;e.g.&lt;/em&gt; &lt;code&gt;test&lt;/code&gt; dependencies would only be needed when tests were requested for the package). These were constrained to appear before the version constraints, &lt;em&gt;e.g.&lt;/em&gt; &lt;code&gt;&quot;foo&quot; {build &amp; doc &amp; &gt;= &quot;3.0&quot;}&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;Extensionsinopam20&quot;&gt;Extensions in opam 2.0&lt;/h3&gt;
&lt;p&gt;Opam 2.0 generalises the dependency flags, and makes the dependencies specification more expressive by allowing to mix &lt;em&gt;filters&lt;/em&gt;, &lt;em&gt;i.e.&lt;/em&gt; formulas based on opam variables, with the version constraints. If that formula holds, the dependency is enforced, if not, it is discarded.&lt;/p&gt;
&lt;p&gt;This is documented in more detail &lt;a href='https://opam.ocaml.org/doc/2.0/Manual.html#Filteredpackageformulas'&gt;in the opam 2.0 manual&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Note also that, since the compilers are now packages, the required OCaml version is now expressed using this mechanism as well, through a dependency to the (virtual) package &lt;code&gt;ocaml&lt;/code&gt;, &lt;em&gt;e.g.&lt;/em&gt; &lt;code&gt;depends: [ &quot;ocaml&quot; {&gt;= &quot;4.03.0&quot;} ]&lt;/code&gt;. This replaces uses of the &lt;code&gt;available:&lt;/code&gt; field and &lt;code&gt;ocaml-version&lt;/code&gt; switch variable.&lt;/p&gt;
&lt;h4 id=&quot;Conditionaldependencies&quot;&gt;Conditional dependencies&lt;/h4&gt;
&lt;p&gt;This makes it trivial to add, for example, a condition on the OS to a given dependency, using the built-in variable &lt;code&gt;os&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;brush: bash; title: ; notranslate&quot;&gt;
depends: [ &amp;quot;foo&amp;quot; {&amp;gt;= &amp;quot;3.0&amp;quot; &amp;amp; &amp;lt; &amp;quot;4.0~&amp;quot; &amp;amp; os = &amp;quot;linux&amp;quot;} ]
&lt;/pre&gt;
&lt;p&gt;here, &lt;code&gt;foo&lt;/code&gt; is simply not needed if the OS isn&amp;#39;t Linux. We could also be more specific about other OSes using more complex formulas:&lt;/p&gt;
&lt;pre class=&quot;brush: bash; title: ; notranslate&quot;&gt;
depends: [
  &amp;quot;foo&amp;quot; { &amp;quot;1.0+linux&amp;quot; &amp;amp; os = &amp;quot;linux&amp;quot; |
          &amp;quot;1.0+osx&amp;quot; &amp;amp; os = &amp;quot;darwin&amp;quot; }
  &amp;quot;bar&amp;quot; { os != &amp;quot;osx&amp;quot; &amp;amp; os != &amp;quot;darwin&amp;quot; }
]
&lt;/pre&gt;
&lt;p&gt;Meaning that Linux and OSX require &lt;code&gt;foo&lt;/code&gt;, respectively versions &lt;code&gt;1.0+linux&lt;/code&gt; and &lt;code&gt;1.0+osx&lt;/code&gt;, while other systems require &lt;code&gt;bar&lt;/code&gt;, any version.&lt;/p&gt;
&lt;h4 id=&quot;Dependencyflags&quot;&gt;Dependency flags&lt;/h4&gt;
&lt;p&gt;Dependency flags, as used in 1.2, are no longer needed, and are replaced by variables that can appear anywhere in the version specification. The following variables are typically useful there:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;with-test&lt;/code&gt;, &lt;code&gt;with-doc&lt;/code&gt;: replace the &lt;code&gt;test&lt;/code&gt; and &lt;code&gt;doc&lt;/code&gt; dependency flags, and are &lt;code&gt;true&lt;/code&gt; when the package&amp;#39;s tests or documentation have been requested&lt;/li&gt;
&lt;li&gt;likewise, &lt;code&gt;build&lt;/code&gt; behaves similarly as before, limiting the dependency to a &amp;#8220;build-dependency&amp;#8221;, implying that the package won&amp;#39;t need to be rebuilt if the dependency changes&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dev&lt;/code&gt;: this boolean variable holds &lt;code&gt;true&lt;/code&gt; on &amp;#8220;development&amp;#8221; packages, that is, packages that are bound to a non-stable source (a version control system, or if the package is pinned to an archive without known checksum). &lt;code&gt;dev&lt;/code&gt; sources often happen to need an additional preliminary step (e.g. &lt;code&gt;autoconf&lt;/code&gt;), which may have its own dependencies.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Use &lt;code&gt;opam config list&lt;/code&gt; for a list of pre-defined variables. Note that the &lt;code&gt;with-test&lt;/code&gt;, &lt;code&gt;with-doc&lt;/code&gt; and &lt;code&gt;build&lt;/code&gt; variables are not available everywhere: the first two are allowed only in the &lt;code&gt;depends:&lt;/code&gt;, &lt;code&gt;depopts:&lt;/code&gt;, &lt;code&gt;build:&lt;/code&gt; and &lt;code&gt;install:&lt;/code&gt; fields, and the latter is specific to the &lt;code&gt;depends:&lt;/code&gt; and &lt;code&gt;depopts:&lt;/code&gt; fields.&lt;/p&gt;
&lt;p&gt;For example, the &lt;code&gt;datakit.0.9.0&lt;/code&gt; package has:&lt;/p&gt;
&lt;pre class=&quot;brush: bash; title: ; notranslate&quot;&gt;
depends: [
  ...
  &amp;quot;datakit-server&amp;quot; {&amp;gt;= &amp;quot;0.9.0&amp;quot;}
  &amp;quot;datakit-client&amp;quot; {with-test &amp;amp; &amp;gt;= &amp;quot;0.9.0&amp;quot;}
  &amp;quot;datakit-github&amp;quot; {with-test &amp;amp; &amp;gt;= &amp;quot;0.9.0&amp;quot;}
  &amp;quot;alcotest&amp;quot; {with-test &amp;amp; &amp;gt;= &amp;quot;0.7.0&amp;quot;}
]
&lt;/pre&gt;
&lt;p&gt;When running &lt;code&gt;opam install datakit.0.9.0&lt;/code&gt;, the &lt;code&gt;with-test&lt;/code&gt; variable is set to &lt;code&gt;false&lt;/code&gt;, and the &lt;code&gt;datakit-client&lt;/code&gt;, &lt;code&gt;datakit-github&lt;/code&gt; and &lt;code&gt;alcotest&lt;/code&gt; dependencies are filtered out: they won&amp;#39;t be required. With &lt;code&gt;opam install datakit.0.9.0 --with-test&lt;/code&gt;, the &lt;code&gt;with-test&lt;/code&gt; variable is true (for that package only, tests on packages not listed on the command-line are not enabled!). In this case, the dependencies resolve to:&lt;/p&gt;
&lt;pre class=&quot;brush: bash; title: ; notranslate&quot;&gt;
depends: [
  ...
  &amp;quot;datakit-server&amp;quot; {&amp;gt;= &amp;quot;0.9.0&amp;quot;}
  &amp;quot;datakit-client&amp;quot; {&amp;gt;= &amp;quot;0.9.0&amp;quot;}
  &amp;quot;datakit-github&amp;quot; {&amp;gt;= &amp;quot;0.9.0&amp;quot;}
  &amp;quot;alcotest&amp;quot; {&amp;gt;= &amp;quot;0.7.0&amp;quot;}
]
&lt;/pre&gt;
&lt;p&gt;which is treated normally.&lt;/p&gt;
&lt;h4 id=&quot;Computedversions&quot;&gt;Computed versions&lt;/h4&gt;
&lt;p&gt;It is also possible to use variables, not only as conditions, but to compute the version values: &lt;code&gt;&quot;foo&quot; {= var}&lt;/code&gt; is allowed and will require the version of package &lt;code&gt;foo&lt;/code&gt; corresponding to the value of variable &lt;code&gt;var&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is useful, for example, to define a family of packages, which are released together with the same version number: instead of having to update the dependencies of each package to match the common version at each release, you can leverage the &lt;code&gt;version&lt;/code&gt; package-variable to mean &amp;#8220;that other package, at the same version as current package&amp;#8221;. For example, &lt;code&gt;foo-client&lt;/code&gt; could have the following:&lt;/p&gt;
&lt;pre class=&quot;brush: bash; title: ; notranslate&quot;&gt;
depends: [ &amp;quot;foo-core&amp;quot; {= version} ]
&lt;/pre&gt;
&lt;p&gt;It is even possible to use variable interpolations within versions, &lt;em&gt;e.g.&lt;/em&gt; specifying an os-specific version differently than above:&lt;/p&gt;
&lt;pre class=&quot;brush: bash; title: ; notranslate&quot;&gt;
depends: [ &amp;quot;foo&amp;quot; {= &amp;quot;1.0+%{os}%&amp;quot;} ]
&lt;/pre&gt;
&lt;p&gt;this will expand the &lt;code&gt;os&lt;/code&gt; variable, resolving to &lt;code&gt;1.0+linux&lt;/code&gt;, &lt;code&gt;1.0+darwin&lt;/code&gt;, etc.&lt;/p&gt;
&lt;p&gt;Getting back to our &lt;code&gt;datakit&lt;/code&gt; example, we could leverage this and rewrite it to the more generic:&lt;/p&gt;
&lt;pre class=&quot;brush: bash; title: ; notranslate&quot;&gt;
depends: [
  ...
  &amp;quot;datakit-server&amp;quot; {&amp;gt;= version}
  &amp;quot;datakit-client&amp;quot; {with-test &amp;amp; &amp;gt;= version}
  &amp;quot;datakit-github&amp;quot; {with-test &amp;amp; &amp;gt;= version}
  &amp;quot;alcotest&amp;quot; {with-test &amp;amp; &amp;gt;= &amp;quot;0.7.0&amp;quot;}
]
&lt;/pre&gt;
&lt;p&gt;Since the &lt;code&gt;datakit-*&lt;/code&gt; packages follow the same versioning, this avoids having to rewrite the opam file on every new version, with a risk of error each time.&lt;/p&gt;
&lt;p&gt;As a side note, these variables are consistent with what is now used in the &lt;a href='http://opam.ocaml.org/doc/2.0/Manual.html#opamfield-build'&gt;&lt;code&gt;build:&lt;/code&gt;&lt;/a&gt; field, and the &lt;a href='http://opam.ocaml.org/doc/2.0/Manual.html#opamfield-build-test'&gt;&lt;code&gt;build-test:&lt;/code&gt;&lt;/a&gt; field is now deprecated. So this other part of the same &lt;code&gt;datakit&lt;/code&gt; opam file:&lt;/p&gt;
&lt;pre class=&quot;brush: bash; title: ; notranslate&quot;&gt;
build:
  [&amp;quot;ocaml&amp;quot; &amp;quot;pkg/pkg.ml&amp;quot; &amp;quot;build&amp;quot; &amp;quot;--pinned&amp;quot; &amp;quot;%{pinned}%&amp;quot; &amp;quot;--tests&amp;quot; &amp;quot;false&amp;quot;]
build-test: [
  [&amp;quot;ocaml&amp;quot; &amp;quot;pkg/pkg.ml&amp;quot; &amp;quot;build&amp;quot; &amp;quot;--pinned&amp;quot; &amp;quot;%{pinned}%&amp;quot; &amp;quot;--tests&amp;quot; &amp;quot;true&amp;quot;]
  [&amp;quot;ocaml&amp;quot; &amp;quot;pkg/pkg.ml&amp;quot; &amp;quot;test&amp;quot;]
]
&lt;/pre&gt;
&lt;p&gt;would now be preferably written as:&lt;/p&gt;
&lt;pre class=&quot;brush: bash; title: ; notranslate&quot;&gt;
build:
  [&amp;quot;ocaml&amp;quot; &amp;quot;pkg/pkg.ml&amp;quot; &amp;quot;build&amp;quot; &amp;quot;--pinned&amp;quot; &amp;quot;%{pinned}%&amp;quot; &amp;quot;--tests&amp;quot; &amp;quot;%{with-test}%&amp;quot;]
run-test:
  [&amp;quot;ocaml&amp;quot; &amp;quot;pkg/pkg.ml&amp;quot; &amp;quot;test&amp;quot;]
&lt;/pre&gt;
&lt;p&gt;which avoids building twice just to change the options.&lt;/p&gt;
&lt;h4 id=&quot;Conclusion&quot;&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;Hopefully this extension to expressivity in dependencies will make the life of packagers easier; feedback is welcome on your personal use-cases.&lt;/p&gt;
&lt;p&gt;Note that the official repository is still in 1.2 format (served as 2.0 at &lt;code&gt;https://opam.ocaml.org/2.0&lt;/code&gt;, through automatic conversion), and will only be migrated a little while after opam 2.0 is finally released. You are welcome to experiment on custom repositories or pinned packages already, but will need a little more patience before you can contribute package definitions making use of the above to the &lt;a href='https://github.com/ocaml/opam-repository'&gt;official repository&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;NOTE: this article is cross-posted on &lt;a href='https://opam.ocaml.org/blog/'&gt;opam.ocaml.org&lt;/a&gt; and &lt;a href='http://www.ocamlpro.com/category/blog/'&gt;ocamlpro.com&lt;/a&gt;. Please head to the latter for the comments!&lt;/p&gt;
&lt;/blockquote&gt;
</content><category term="Blog"/><id>http://www.ocamlpro.com/?p=664</id><title type="text">New opam features: more expressive dependencies</title><updated>2017-05-11T13:20:05-00:00</updated><author><name>OCamlPro</name></author></entry><entry><source><updated>2017-05-09T12:00:00-00:00</updated><link title="OCaml Weekly News" type="text/html" href="http://alan.petitepomme.net/cwn/" rel="related"/><link title="OCaml Weekly News" type="application/rss+xml" href="http://alan.petitepomme.net/cwn/cwn.rss" rel="self"/><id>http://alan.petitepomme.net/cwn/</id><title type="text">OCaml Weekly News</title><author><name>OCaml Weekly News</name></author></source><link href="http://alan.petitepomme.net/cwn/2017.05.09.html" rel="alternate"/><content xml:base="http://alan.petitepomme.net/cwn/cwn.rss" type="html">&lt;ol&gt;&lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.05.09.html#1&gt;OCaml / Ocsigen developer positions&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.05.09.html#2&gt;tjr_btree 0.1.0 (initial release)&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.05.09.html#3&gt;Other OCaml News&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;</content><id>http://alan.petitepomme.net/cwn/2017.05.09.html</id><title type="text">Weekly News</title><updated>2017-05-09T12:00:00-00:00</updated><author><name>OCaml Weekly News</name></author></entry><entry><source><updated>2017-05-08T15:23:58-00:00</updated><link href="http://jobs.github.com/" rel="alternate"/><link href="http://jobs.github.com/positions.atom?description=ocaml" rel="self"/><id>urn:uuid:0a9333c4-71da-11e0-9ac7-692793c00b45</id><title type="text">
    GitHub Jobs
      matching ocaml
  </title><author><email>jobs@github.com</email><name>GitHub Jobs</name></author></source><link href="http://jobs.github.com/positions/0a9333c4-71da-11e0-9ac7-692793c00b45" rel="alternate"/><content xml:base="https://jobs.github.com/positions.atom?description=ocaml" type="html">&lt;p&gt;Software Developer &lt;/p&gt;

&lt;p&gt;Jane Street is a proprietary quantitative trading firm, focusing primarily on trading equities and equity derivatives. We use innovative technology, a scientific approach, and a deep understanding of markets to stay successful in our highly competitive field. We operate around the clock and around the globe, employing over 400 people in offices in New York, London and Hong Kong.&lt;/p&gt;

&lt;p&gt;The markets in which we trade change rapidly, but our intellectual approach changes faster still. Every day, we have new problems to solve and new theories to test. Our entrepreneurial culture is driven by our talented team of traders and programmers. At Jane Street, we don&amp;#39;t come to work wanting to leave. We come to work excited to test new theories, have thought-provoking discussions, and maybe sneak in a game of ping-pong or two. Keeping our culture casual and our employees happy is of paramount importance to us.&lt;/p&gt;

&lt;p&gt;We are looking to hire great software developers with an interest in functional programming. OCaml, a statically typed functional programming language with similarities to Haskell, Scheme, Erlang, F# and SML, is our language of choice. We&amp;#39;ve got the largest team of OCaml developers in any industrial setting, and probably the world&amp;#39;s largest OCaml codebase. We use OCaml for running our entire business, supporting everything from research to systems administration to trading systems. If you&amp;#39;re interested in seeing how functional programming plays out in the real world, there&amp;#39;s no better place.&lt;/p&gt;

&lt;p&gt;The atmosphere is informal and intellectual. There is a focus on education, and people learn about software and trading, both through formal classes and on the job. The work is challenging, and you get to see the practical impact of your efforts in quick and dramatic terms. Jane Street is also small enough that people have the freedom to get involved in many different areas of the business. Compensation is highly competitive, and there&amp;#39;s a lot of room for growth.&lt;/p&gt;

&lt;p&gt;You can learn more about Jane Street and our technology from our main site, janestreet.com. You can also look at a a talk given at CMU about why Jane Street uses functional programming (&lt;a href=&quot;http://ocaml.janestreet.com/?q=node/61&quot;&gt;http://ocaml.janestreet.com/?q=node/61&lt;/a&gt;), and our programming blog (&lt;a href=&quot;http://ocaml.janestreet.com&quot;&gt;http://ocaml.janestreet.com&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;We also have extensive benefits, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;90% book reimbursement for work-related books&lt;/li&gt;
&lt;li&gt;90% tuition reimbursement for continuing education&lt;/li&gt;
&lt;li&gt;Excellent, zero-premium medical and dental insurance&lt;/li&gt;
&lt;li&gt;Free lunch delivered daily from a selection of restaurants&lt;/li&gt;
&lt;li&gt;Catered breakfasts and fresh brewed Peet&amp;#39;s coffee&lt;/li&gt;
&lt;li&gt;An on-site, private gym in New York with towel service&lt;/li&gt;
&lt;li&gt;Kitchens fully stocked with a variety of snack choices&lt;/li&gt;
&lt;li&gt;Full company 401(k) match up to 6% of salary, vests immediately&lt;/li&gt;
&lt;li&gt;Three weeks of paid vacation for new hires in the US&lt;/li&gt;
&lt;li&gt;16 weeks fully paid maternity/paternity leave for primary caregivers, plus additional unpaid leave&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More information at &lt;a href=&quot;http://janestreet.com/culture/benefits/&quot;&gt;http://janestreet.com/culture/benefits/&lt;/a&gt;&lt;/p&gt;
</content><id>urn:uuid:0a9333c4-71da-11e0-9ac7-692793c00b45</id><title type="text">Full Time: Software Developer (Functional Programming) at Jane Street in New York, NY; London, UK; Hong Kong</title><updated>2017-05-08T15:23:58-00:00</updated><author><email>jobs@github.com</email><name>GitHub Jobs</name></author></entry><entry><source><updated>2017-05-11T20:18:34-00:00</updated><subtitle xml:base="http://blog.shaynefletcher.org/feeds/posts/default/-/OCaml" type="html">&quot;Hooked&quot; on programming</subtitle><link type="application/atom+xml" href="http://www.blogger.com/feeds/5012565255225108517/posts/default/-/OCaml/-/OCaml?start-index=26&amp;max-results=25" rel="next"/><link href="http://pubsubhubbub.appspot.com/" rel="hub"/><link type="text/html" href="http://blog.shaynefletcher.org/search/label/OCaml" rel="alternate"/><link type="application/atom+xml" href="http://www.blogger.com/feeds/5012565255225108517/posts/default/-/OCaml" rel="self"/><link type="application/atom+xml" href="http://blog.shaynefletcher.org/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed"/><generator uri="http://www.blogger.com" version="7.00">Blogger</generator><category term="recursive descent"/><category term="ppx"/><category term="ppf"/><category term="left recursion"/><category term="grammars"/><category term="balanced binary search trees"/><category term="Windows 8.1"/><category term="Windows 7"/><category term="Variance"/><category term="Universal type"/><category term="Universal Gas Constant"/><category term="Tail recursion"/><category term="Subtyping"/><category term="Stack overflow"/><category term="Sorting"/><category term="Simulation"/><category term="Sieve of Eratosthenes"/><category term="Science"/><category term="Rings"/><category term="Recursion"/><category term="Priority queue"/><category term="Pretty-printing"/><category term="Poof"/><category term="Polynomials"/><category term="Polymorphic variants"/><category term="Permutation"/><category term="Pascal"/><category term="Numerical analysis"/><category term="Monty Hall"/><category term="Modules"/><category term="List comprehensions"/><category term="Leftist heap"/><category term="Labeled arguments"/><category term="Ideal Gas Law"/><category term="Horner's rule"/><category term="Functors"/><category term="Financial Modeling in Python"/><category term="Exponentiation by squaring"/><category term="Compression"/><category term="Combination"/><category term="Church-Turing thesis"/><category term="Church numerals"/><category term="Cartesian product"/><category term="Algorithmic complexity"/><category term="64-bit"/><category term="type-classes"/><category term="ocamlyacc"/><category term="ocamllex"/><category term="Y Combinator"/><category term="Taylor polynomials"/><category term="Streams"/><category term="Recursive lists"/><category term="Prolog"/><category term="Monads"/><category term="Dimensional analysis"/><category term="Algebra"/><category term="Regular expressions"/><category term="Powerset"/><category term="Statistics"/><category term="Lexical analysis"/><category term="Haskell"/><category term="Parsing"/><category term="data structures"/><category term="Symbolic computation"/><category term="Lambda calculus"/><category term="Felix"/><category term="Boost"/><category term="Python"/><category term="Algorithms"/><category term="C++"/><category term="Functional programming"/><category term="OCaml"/><id>tag:blogger.com,1999:blog-5012565255225108517</id><title type="text">Shayne Fletcher</title><author><email>noreply@blogger.com</email><name>Shayne Fletcher</name></author></source><published>2017-05-04T20:27:00-00:00</published><link title="Preprocessor extensions for code generation" type="text/html" href="http://blog.shaynefletcher.org/2017/05/preprocessor-extensions-for-code.html" rel="alternate"/><link type="application/atom+xml" href="http://www.blogger.com/feeds/5012565255225108517/posts/default/7862603271486676192" rel="self"/><link type="application/atom+xml" href="http://www.blogger.com/feeds/5012565255225108517/posts/default/7862603271486676192" rel="edit"/><content xml:base="http://blog.shaynefletcher.org/feeds/posts/default/-/OCaml" type="html">&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01//EN&quot;           &quot;http://www.w3.org/TR/html4/strict.dtd&quot;&gt;&lt;html&gt;  &lt;head&gt;    &lt;title&gt;PPX&lt;/title&gt;  &lt;/head&gt;  &lt;body&gt;  &lt;h2&gt;Preprocessor extensions for code generation&lt;/h2&gt;  &lt;p&gt;&quot;A Guide to Extension Points in OCaml&quot;[1] provides a great   &quot;quick-start&quot; on using the OCaml extension points API to implement   preprocessor extensions for abstract syntax tree rewrites. This   post picks up where that tutorial leaves off by showing how to write   a ppx that does code generation.   &lt;/p&gt;  &lt;p&gt;The problem treated here is one posed in Whitequark's blog :   &quot;Implement a syntax extension that would accept type declarations of   the form    &lt;code&gt;type t = A [@id 1] | B of int [@id 4] [@@id_of]&lt;/code&gt;    to generate a function mapping a value of type &lt;code&gt;t&lt;/code&gt; to its   integer representation.&quot;   &lt;/p&gt;   &lt;h2&gt;Implementing the &quot;&lt;code&gt;id_of&lt;/code&gt;&quot; ppx&lt;/h2&gt;   &lt;h3&gt;The basic strategy&lt;/h3&gt;  &lt;p&gt;In the OCaml parse tree, structures are lists of structure   items. Type declarations are structure items as are let-bindings to   functions.   &lt;/p&gt;  &lt;p&gt;In this program, analysis of an inductive type declaration &lt;code&gt;t&lt;/code&gt;    may result in the production of a new structure item, the AST of an &lt;code&gt;of_id&lt;/code&gt; function   to be appended to the structure containing &lt;code&gt;t&lt;/code&gt;.   &lt;/p&gt;  &lt;p&gt;Now the general strategy in writing a ppx is to provide a record   of type &lt;code&gt;Ast_mapper.mapper&lt;/code&gt;. That record is based on   the &lt;code&gt;Ast_mapper.default_mapper&lt;/code&gt; record but selectively   overriding those fields for those sytactic categories that the ppx   is intending to transform.   &lt;/p&gt;  &lt;p&gt;Now, as we determined above, the effect of the ppx is to provide   a function from a structure to a new structure. Accordingly, at a   minimum then we'll want to override the &lt;code&gt;structure&lt;/code&gt; field   of the default mapper. Schematically then our ppx code will take on   the following shape.   &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;  open Ast_mapper&lt;br /&gt;  open Ast_helper&lt;br /&gt;  open Asttypes&lt;br /&gt;  open Parsetree&lt;br /&gt;  open Longident&lt;br /&gt;&lt;br /&gt;  let structure_mapper mapper structure =&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;   let id_of_mapper =  {&lt;br /&gt;     default_mapper with structure = structure_mapper&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   let () = register &quot;id_of&quot; id_of_mapper&lt;br /&gt;  &lt;/pre&gt;  &lt;/p&gt;  &lt;p&gt;  This program goes just a little bit further  though. Any &lt;code&gt;@id&lt;/code&gt; or &lt;code&gt;@@id_of&lt;/code&gt; attributes that   get as far as the OCaml compiler would be ignored. So, it's not   neccessary that they be removed by our ppx once they've been acted   upon but it seems tidy to do so. Accordingly, there are two more   syntactic constructs that this ppx operates on.   &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;  open Ast_mapper&lt;br /&gt;  open Ast_helper&lt;br /&gt;  open Asttypes&lt;br /&gt;  open Parsetree&lt;br /&gt;  open Longident&lt;br /&gt;&lt;br /&gt;  let structure_mapper mapper structure =&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;  let type_declaration_mapper mapper decl =&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;  let constructor_declaration_mapper mapper decl =&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;  let id_of_mapper argv = {&lt;br /&gt;    default_mapper with&lt;br /&gt;      structure = structure_mapper;&lt;br /&gt;      type_declaration = type_declaration_mapper;&lt;br /&gt;      constructor_declaration = constructor_declaration_mapper&lt;br /&gt;  }&lt;br /&gt;  &lt;/pre&gt;  &lt;/p&gt;  &lt;h3&gt;Implementing the mappings&lt;/h3&gt;  &lt;p&gt;To warm up, lets start with the easy mappers.&lt;/p&gt;  &lt;p&gt;The role of &lt;code&gt;type_declaration_mapper&lt;/code&gt; is a function   from a &lt;code&gt;type_declaration&lt;/code&gt; argument to   a &lt;code&gt;type_declaration&lt;/code&gt; result that is the argument in all   but that any &lt;code&gt;@@id_of&lt;/code&gt; attribute has been removed.   &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;  let type_declaration_mapper &lt;br /&gt;      (mapper : mapper) &lt;br /&gt;      (decl : type_declaration) : type_declaration  =&lt;br /&gt;    match decl with&lt;br /&gt;      (*Case of an inductive type &quot;t&quot;*)&lt;br /&gt;    | {ptype_name = {txt = &quot;t&quot;; _};&lt;br /&gt;       ptype_kind = Ptype_variant constructor_declarations;&lt;br /&gt;       ptype_attributes;_} -&gt;&lt;br /&gt;      let (_, attrs) = &lt;br /&gt;        List.partition (fun ({txt;_},_) -&gt;txt=&quot;id_of&quot;) ptype_attributes in&lt;br /&gt;      {(default_mapper.type_declaration mapper decl) &lt;br /&gt;      with ptype_attributes=attrs}&lt;br /&gt;    (*Not an inductive type named &quot;t&quot;*)&lt;br /&gt;    | _ -&gt; default_mapper.type_declaration mapper decl&lt;br /&gt;    &lt;/pre&gt;  &lt;/p&gt;  &lt;p&gt;&lt;code&gt;constructor_declaration_mapper&lt;/code&gt; is analogous   to &lt;code&gt;type_declaration_mapper&lt;/code&gt; above but this time   its &lt;code&gt;@id&lt;/code&gt; attributes that are removed.   &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;  let constructor_declaration_mapper &lt;br /&gt;      (mapper : mapper) &lt;br /&gt;      (decl : constructor_declaration) : constructor_declaration =&lt;br /&gt;    match decl with&lt;br /&gt;    | {pcd_attributes; _} -&gt;&lt;br /&gt;      let (_, attrs) = &lt;br /&gt;        List.partition (fun ({txt;_}, _) -&gt; txt=&quot;id&quot;) pcd_attributes  in&lt;br /&gt;      {(default_mapper.constructor_declaration mapper decl) &lt;br /&gt;      with pcd_attributes=attrs}&lt;br /&gt;    &lt;/pre&gt;  &lt;/p&gt;  &lt;p&gt;Now to the raison d'etre of the   ppx, &lt;code&gt;structure_mapper&lt;/code&gt;.    &lt;/p&gt;  &lt;p&gt;First, a utility function that computes from   a &lt;code&gt;constructor_declaration&lt;/code&gt; with an &lt;code&gt;@id&lt;/code&gt;  attribute, a (function) &lt;code&gt;case&lt;/code&gt; for it. For example,   suppose &quot;&lt;code&gt;Bar of int [@id 4]&lt;/code&gt;&quot; is the constructor   declaration, then the &lt;code&gt;case&lt;/code&gt; to be computed is the AST   corresponding to the code &quot;&lt;code&gt;| Bar _ -&gt; 4&lt;/code&gt;&quot;.   &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;  let case_of_constructor_declaration : &lt;br /&gt;      constructor_declaration -&gt; case =  function&lt;br /&gt;    | {pcd_name={txt;loc};pcd_args;pcd_attributes; _} -&gt;&lt;br /&gt;      match List.filter (fun ({txt;_}, _) -&gt; txt=&quot;id&quot;) pcd_attributes with&lt;br /&gt;      (*No &quot;@id&quot;*)&lt;br /&gt;      | [] -&gt; &lt;br /&gt;        raise (Location.Error (Location.error ~loc &quot;[@id] : Missing&quot;))&lt;br /&gt;      (*Single &quot;@id&quot;*)&lt;br /&gt;      | [(_, payload)] -&gt; &lt;br /&gt;        begin match payload with &lt;br /&gt;          | PStr [{pstr_desc=Pstr_eval ({pexp_desc=&lt;br /&gt;              Pexp_constant (Pconst_integer (id, None)); _}, _)&lt;br /&gt;            }] -&gt;&lt;br /&gt;            Exp.case &lt;br /&gt;              (Pat.construct &lt;br /&gt;                 {txt=Lident txt; loc=(!default_loc)}  &lt;br /&gt;                 (match pcd_args with &lt;br /&gt;                 | Pcstr_tuple [] -&gt; None | _ -&gt; Some (Pat.any ())))&lt;br /&gt;              (Exp.constant (Pconst_integer (id, None)))&lt;br /&gt;          | _ -&gt; &lt;br /&gt;            raise (Location.Error (Location.error ~loc &lt;br /&gt;            &quot;[@id] : Bad (or missing) argument (should be int e.g. [@id 4])&quot;))&lt;br /&gt;        end&lt;br /&gt;      (*Many &quot;@id&quot;s*)&lt;br /&gt;      | (_ :: _) -&gt; &lt;br /&gt;        raise (Location.Error (Location.error ~loc &lt;br /&gt;        &quot;[@id] : Multiple occurences&quot;))&lt;br /&gt;  &lt;/pre&gt;  &lt;p&gt;One more utility function is required.&lt;/p&gt;  &lt;p&gt;&lt;code&gt;eval_structure_item item acc&lt;/code&gt; computes structure   items to push on the front of &lt;code&gt;acc&lt;/code&gt;. If &lt;code&gt;item&lt;/code&gt;  is a single declaration of an inductive type &lt;code&gt;t&lt;/code&gt;  attributed with &lt;code&gt;@@id_of&lt;/code&gt;, then two structure items will   be produced : one for &lt;code&gt;t&lt;/code&gt; and one synthesized   for &lt;code&gt;t&lt;/code&gt;'s &lt;code&gt;of_id&lt;/code&gt; function. In all other   cases, just one structure item will be pushed onto &lt;code&gt;acc&lt;/code&gt;.   &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;  let eval_structure_item&lt;br /&gt;      (mapper : mapper) &lt;br /&gt;      (item : structure_item) &lt;br /&gt;      (acc : structure) : structure =&lt;br /&gt;    match item with&lt;br /&gt;    (*Case of a single inductive type declaration*)&lt;br /&gt;    | { pstr_desc = Pstr_type (_, [type_decl]); pstr_loc} -&gt;&lt;br /&gt;      begin&lt;br /&gt;        match type_decl with&lt;br /&gt;        (*Case where the type identifer is [t]*)&lt;br /&gt;        | {ptype_name = {txt = &quot;t&quot;; _};&lt;br /&gt;           ptype_kind = Ptype_variant constructor_declarations;&lt;br /&gt;           ptype_attributes;&lt;br /&gt;           _} -&gt;&lt;br /&gt;          begin&lt;br /&gt;            match List.filter (fun ({txt;_},_) -&gt;txt=&quot;id_of&quot;) &lt;br /&gt;              ptype_attributes &lt;br /&gt;            with&lt;br /&gt;            (*No [@@id_of]*)&lt;br /&gt;            | [] -&gt; default_mapper.structure_item mapper item :: acc&lt;br /&gt;  &lt;br /&gt;            (*At least one [@@id_of] (treat multiple occurences as if&lt;br /&gt;              one)*)&lt;br /&gt;            | _ -&gt;&lt;br /&gt;              (*Cases of an [id_of] function for [t], one for each&lt;br /&gt;                of its constructors*)&lt;br /&gt;              let cases= &lt;br /&gt;                List.fold_right &lt;br /&gt;                  (fun x acc -&gt; &lt;br /&gt;                    case_of_constructor_declaration x :: acc) &lt;br /&gt;                  constructor_declarations [] in&lt;br /&gt;              (*The [id_of] function itself*)&lt;br /&gt;              let id_of : structure_item = &lt;br /&gt;                Str.value Nonrecursive [&lt;br /&gt;                  Vb.mk &lt;br /&gt;                    (Pat.var {txt=&quot;id_of&quot;; loc=(!default_loc)}) &lt;br /&gt;                    (Exp.function_ cases)] in&lt;br /&gt;  &lt;br /&gt;              default_mapper.structure_item mapper item :: id_of :: acc&lt;br /&gt;          end&lt;br /&gt;        (*Case the type identifier is something other than [t]*)&lt;br /&gt;        | _ -&gt; default_mapper.structure_item mapper item :: acc&lt;br /&gt;      end&lt;br /&gt;    (*Case this structure item is something other than a single type&lt;br /&gt;      declaration*)&lt;br /&gt;    | _ -&gt; default_mapper.structure_item mapper item :: acc&lt;br /&gt;  &lt;/pre&gt;  &lt;/p&gt;  &lt;p&gt;Finally we can write &lt;code&gt;structure_mapper&lt;/code&gt; itself as a   simple fold over a structure.   &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;  let structure_mapper &lt;br /&gt;      (mapper : mapper) &lt;br /&gt;      (structure : structure) : structure =&lt;br /&gt;    List.fold_right (eval_structure_item mapper) structure []&lt;br /&gt;  &lt;/pre&gt;  &lt;/p&gt; &lt;h3&gt;Building and testing&lt;/h3&gt;  &lt;p&gt;So that's it, this preprocessor extension is complete. Assuming   the code is contained in a file called &lt;code&gt;ppx_id_of.ml&lt;/code&gt; it   can be compiled with a command along the lines of the following.   &lt;pre&gt;&lt;br /&gt;  ocamlc -o ppx_id_of.exe  -I +compiler-libs ocamlcommon.cma ppx_id_of.ml&lt;br /&gt;  &lt;/pre&gt;  When built, it can be tested with a command like   &lt;code&gt; ocamlc -dsource -ppx ppx_id_of.exe test.ml&lt;/code&gt;.   &lt;/p&gt;  &lt;p&gt;  For example, when invoked on the following program,   &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;  type t = &lt;br /&gt;    | A [@id 2] &lt;br /&gt;    | B of int [@id 4] [@@id_of]&lt;br /&gt;&lt;br /&gt;  module M = struct&lt;br /&gt;    type t =&lt;br /&gt;    | Foo of int [@id 42]&lt;br /&gt;    | Bar [@id 43] [@@id_of]&lt;br /&gt;&lt;br /&gt;    module N = struct&lt;br /&gt;       type t = &lt;br /&gt;       | Baz [@id 8] &lt;br /&gt;       | Quux of string * int [@id 7] [@@id_of]&lt;br /&gt;&lt;br /&gt;      module Q = struct&lt;br /&gt;        type t = &lt;br /&gt;          | U [@id 0] [@@id_of]&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;  &lt;/pre&gt;  the resulting output is,   &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;  type t =&lt;br /&gt;    | A&lt;br /&gt;    | B of int&lt;br /&gt;  let id_of = function | A  -&gt; 2 | B _ -&gt; 4&lt;br /&gt;  module M =&lt;br /&gt;    struct&lt;br /&gt;      type t =&lt;br /&gt;        | Foo of int&lt;br /&gt;        | Bar&lt;br /&gt;      let id_of = function | Foo _ -&gt; 42 | Bar  -&gt; 43&lt;br /&gt;      module N =&lt;br /&gt;        struct&lt;br /&gt;          type t =&lt;br /&gt;            | Baz&lt;br /&gt;            | Quux of string * int&lt;br /&gt;          let id_of = function | Baz  -&gt; 8 | Quux _ -&gt; 7&lt;br /&gt;          module Q = struct type t =&lt;br /&gt;                              | U&lt;br /&gt;                            let id_of = function | U  -&gt; 0  end&lt;br /&gt;        end&lt;br /&gt;    end&lt;br /&gt;    &lt;/pre&gt;  &lt;/p&gt;  &lt;hr/&gt;  &lt;p&gt;    References:&lt;br/&gt;     [1] &lt;a href=&quot;https://whitequark.org/blog/2014/04/16/a-guide-to-extension-points-in-ocaml/&quot;&gt;&quot;A      Guide to Extension Points in OCaml&quot; -- Whitequark (blog post      2014)&lt;/a&gt;  &lt;/p&gt;  &lt;/body&gt;&lt;/html&gt;  </content><category scheme="http://www.blogger.com/atom/ns#" term="ppx"/><category scheme="http://www.blogger.com/atom/ns#" term="OCaml"/><id>tag:blogger.com,1999:blog-5012565255225108517.post-7862603271486676192</id><title type="text">Preprocessor extensions for code generation</title><updated>2017-05-05T12:14:38-00:00</updated><author><email>noreply@blogger.com</email><uri>https://plus.google.com/104436573144909855029</uri><name>Shayne Fletcher</name></author></entry><entry><source><updated>2017-05-11T13:20:05-00:00</updated><logo>http://www.ocamlpro.com/wp-content/uploads/2016/02/cropped-favicon-32x32.png</logo><link title="OCamlPro" type="text/html" href="http://www.ocamlpro.com" rel="related"/><link title="OCamlPro" type="application/rss+xml" href="http://www.ocamlpro.com/feed/" rel="self"/><generator>https://wordpress.org/?v=4.7.4</generator><id>http://www.ocamlpro.com</id><title type="text">OCamlPro</title><author><name>OCamlPro</name></author></source><link href="http://www.ocamlpro.com/2017/05/04/new-opam-features-opam-install-dir/" rel="alternate"/><link href="http://www.ocamlpro.com/2017/05/04/new-opam-features-opam-install-dir/#comments" rel="related"/><content xml:base="http://www.ocamlpro.com/feed/" type="html">&lt;p&gt;After the &lt;a href=&quot;../opam-build&quot;&gt;opam build&lt;/a&gt; feature was announced followed a lot of discussions, mainly having to do with its interface, and misleading name. The base features it offered, though, were still widely asked for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a way to work directly with the project in the current directory, assuming it contains definitions for one or more packages&lt;/li&gt;
&lt;li&gt;a way to copy the installed files of a package below a specified &lt;code&gt;destdir&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;an easier way to get started hacking on a project, even without an initialised opam&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;Statusofopambuild&quot;&gt;Status of &lt;code&gt;opam build&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;opam build&lt;/code&gt;, as described in a &lt;a href=&quot;../opam-build&quot;&gt;previous post&lt;/a&gt; has been dropped. It will be absent from the next Beta, where the following replaces it.&lt;/p&gt;
&lt;h3 id=&quot;Handlingalocalproject&quot;&gt;Handling a local project&lt;/h3&gt;
&lt;p&gt;Consistently with what was done with local switches, it was decided, where meaningful, to overload the &lt;code&gt;&amp;lt;packages&amp;gt;&lt;/code&gt; arguments of the commands, allowing directory names instead, and meaning &amp;#8220;all packages defined there&amp;#8221;, with some side-effects.&lt;/p&gt;
&lt;p&gt;For example, the following command is now allowed, and I believe it will be extra convenient to many:&lt;/p&gt;
&lt;pre class=&quot;brush: bash; title: ; notranslate&quot;&gt;
opam install . --deps-only
&lt;/pre&gt;
&lt;p&gt;What this does is find &lt;code&gt;opam&lt;/code&gt; (or &lt;code&gt;&amp;lt;pkgname&amp;gt;.opam&lt;/code&gt;) files in the current directory (&lt;code&gt;.&lt;/code&gt;), resolve their installations, and install all required packages. That should be the single step before running the source build by hand.&lt;/p&gt;
&lt;p&gt;The following is a little bit more complex:&lt;/p&gt;
&lt;pre class=&quot;brush: bash; title: ; notranslate&quot;&gt;
opam install .
&lt;/pre&gt;
&lt;p&gt;This also retrieves the packages defined at &lt;code&gt;.&lt;/code&gt;, &lt;strong&gt;pins them&lt;/strong&gt; to the current source (using version-control if present), and installs them. Note that subsequent runs actually synchronise the pinnings, so that packages removed or renamed in the source tree are tracked properly (&lt;em&gt;i.e.&lt;/em&gt; removed ones are unpinned, new ones pinned, the other ones upgraded as necessary).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;opam upgrade&lt;/code&gt;, &lt;code&gt;opam reinstall&lt;/code&gt;, and &lt;code&gt;opam remove&lt;/code&gt; have also been updated to handle directories as arguments, and will work on &amp;#8220;all packages pinned to that target&amp;#8221;, &lt;em&gt;i.e.&lt;/em&gt; the packages pinned by the previous call to &lt;code&gt;opam install &amp;lt;dir&amp;gt;&lt;/code&gt;. In addition, &lt;code&gt;opam remove &amp;lt;dir&amp;gt;&lt;/code&gt; unpins the packages, consistently reverting the converse &lt;code&gt;install&lt;/code&gt; operation.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;opam show&lt;/code&gt; already had a &lt;code&gt;--file&lt;/code&gt; option, but has also been extended in the same way, for consistency and convenience.&lt;/p&gt;
&lt;p&gt;This all, of course, works well with a local switch at &lt;code&gt;./&lt;/code&gt;, but the two features can be used completely independently. Note also that the directory name must be made unambiguous with a possible package name, so make sure to use &lt;code&gt;./foo&lt;/code&gt; rather than just &lt;code&gt;foo&lt;/code&gt; for a local project in subdirectory &lt;code&gt;foo&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;Specifyingadestdir&quot;&gt;Specifying a destdir&lt;/h3&gt;
&lt;p&gt;This relies on installed files tracking, but was actually independent from the other &lt;code&gt;opam build&lt;/code&gt; features. It is now simply a new option to &lt;code&gt;opam install&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;brush: bash; title: ; notranslate&quot;&gt;
opam install foo --destdir ~/local/
&lt;/pre&gt;
&lt;p&gt;will install &lt;code&gt;foo&lt;/code&gt; normally (if it isn&amp;#8217;t installed already) and copy all its installed files, following the same hierarchy, into &lt;code&gt;~/local&lt;/code&gt;. &lt;code&gt;opam remove --destdir&lt;/code&gt; is also supported, to remove these files.&lt;/p&gt;
&lt;h3 id=&quot;Initialising&quot;&gt;Initialising&lt;/h3&gt;
&lt;p&gt;Automatic initialisation has been dropped for the moment. It was only saving one command (&lt;code&gt;opam init&lt;/code&gt;, that opam will kindly print out for you if you forget it), and had two drawbacks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;some important details (like shell setup for opam) were skipped&lt;/li&gt;
&lt;li&gt;the initialisation options were much reduced, so you would often have to go back to &lt;code&gt;opam init&lt;/code&gt; anyway. The other possibility being to duplicate &lt;code&gt;init&lt;/code&gt; options to all commands, adding lots of noise. Keeping things separate has its merits.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Granted, another command, &lt;code&gt;opam switch create .&lt;/code&gt;, was made implicit. But using a local switch is a user choice, and worse, in contradiction with the previous de facto opam default, so not creating one automatically seems safer: having to specify &lt;code&gt;--no-autoinit&lt;/code&gt; to &lt;code&gt;opam build&lt;/code&gt; in order to get the more simple behaviour was inconvenient and error-prone.&lt;/p&gt;
&lt;p&gt;One thing is provided to help with initialisation, though: &lt;code&gt;opam switch create &amp;lt;dir&amp;gt;&lt;/code&gt; has been improved to handle package definitions at &lt;code&gt;&amp;lt;dir&amp;gt;&lt;/code&gt;, and will use them to choose a compatible compiler, as &lt;code&gt;opam build&lt;/code&gt; did. This avoids the frustration of creating a switch, then finding out that the package wasn&amp;#8217;t compatible with the chosen compiler version, and having to start over with an explicit choice of a different compiler.&lt;/p&gt;
&lt;p&gt;If you would really like automatic initialisation, and have a better interface to propose, your feedback is welcome!&lt;/p&gt;
&lt;h3 id=&quot;Morerelatedoptions&quot;&gt;More related options&lt;/h3&gt;
&lt;p&gt;A few other new options have been added to &lt;code&gt;opam install&lt;/code&gt; and related commands, to improve the project-local workflows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;opam install --keep-build-dir&lt;/code&gt; is now complemented with &lt;code&gt;--reuse-build-dir&lt;/code&gt;, for incremental builds within opam (assuming your build-system supports it correctly). At the moment, you should specify both on every upgrade of the concerned packages, or you could set the &lt;code&gt;OPAMKEEPBUILDDIR&lt;/code&gt; and &lt;code&gt;OPAMREUSEBUILDDIR&lt;/code&gt; environment variables.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;opam install --inplace-build&lt;/code&gt; runs the scripts directly within the source dir instead of a dedicated copy. If multiple packages are pinned to the same directory, this disables parallel builds of these packages.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;opam install --working-dir&lt;/code&gt; uses the working directory state of your project, instead of the state registered in the version control system. Don&amp;#8217;t worry, opam will warn you if you have uncommitted changes and forgot to specify &lt;code&gt;--working-dir&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;&lt;p&gt;NOTE: this article is cross-posted on &lt;a href=&quot;https://opam.ocaml.org/blog/&quot;&gt;opam.ocaml.org&lt;/a&gt; and &lt;a href=&quot;http://www.ocamlpro.com/category/blog/&quot;&gt;ocamlpro.com&lt;/a&gt;. Please head to the latter for the comments!&lt;/p&gt;&lt;/blockquote&gt;
</content><category term="Blog"/><id>http://www.ocamlpro.com/?p=660</id><title type="text">New opam features: “opam install DIR”</title><updated>2017-05-04T12:48:25-00:00</updated><author><name>OCamlPro</name></author></entry><entry><source><updated>2017-05-09T12:00:00-00:00</updated><link title="OCaml Weekly News" type="text/html" href="http://alan.petitepomme.net/cwn/" rel="related"/><link title="OCaml Weekly News" type="application/rss+xml" href="http://alan.petitepomme.net/cwn/cwn.rss" rel="self"/><id>http://alan.petitepomme.net/cwn/</id><title type="text">OCaml Weekly News</title><author><name>OCaml Weekly News</name></author></source><link href="http://alan.petitepomme.net/cwn/2017.05.02.html" rel="alternate"/><content xml:base="http://alan.petitepomme.net/cwn/cwn.rss" type="html">&lt;ol&gt;&lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.05.02.html#1&gt;PPX is harmful to our community in the long term&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.05.02.html#2&gt;aws-s3 0.9.0&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.05.02.html#3&gt;Other OCaml News&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;</content><id>http://alan.petitepomme.net/cwn/2017.05.02.html</id><title type="text">Weekly News</title><updated>2017-05-02T12:00:00-00:00</updated><author><name>OCaml Weekly News</name></author></entry><entry><summary xml:base="https://blogs.janestreet.com/wp-atom.php" type="html">&lt;p&gt;Jane Street is looking to hire a technical writer. If you're interested, or know someone who you think would be a good match, here's the &lt;a href=&quot;https://www.janestreet.com/join-jane-street/apply/?city=nyc&amp;#38;category=software-development&amp;#38;position=technical-writer&amp;#38;availability=full-time&quot;&gt;application link&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We've always believed that developers should spend time and effort documenting their own code, but at the same time, a great writer with a feel for the technology can raise the level of quality in a way that few developers can. And as we've grown, having someone dedicated to writing makes a ton of sense.&lt;/p&gt;
&lt;p&gt;Here are the kinds of things we'd like to have a technical writer work on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Training material.&lt;/strong&gt; We have a training program that many new hires go through, including most new developers and all new traders. In that program, they learn about OCaml, our base libraries, our build system, the UNIX shell, Emacs, and our dev tools. Part of the job would be to help make the course better, both by improving what we have, and by adding new material.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Improving library documentation.&lt;/strong&gt; While we expect developers to do a reasonable job of documenting their code, our most important libraries deserve the time and care to make them really shine. This is aimed both internally and externally, since a lot of these libraries, like Async, Core and Incremental, are open source.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Writing longer pieces.&lt;/strong&gt; We need more tutorials and overviews on a variety of topics. Part of the work would be to create great new documentation, and part of it is to serve as an example for others as to what good documentation looks like. And where possible, we want to do this so that the documentation effectively compiles against our current APIs, preventing it from just drifting out of date.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In terms of skills, we want someone who is both a clear and effective written communicator, and who is good enough at programming to navigate our codebase, work through our tutorials, and write up examples. An interest in functional programming and expressive type systems is a plus, but you don't need to know any OCaml (the language we use). That's something we're happy to teach you here.&lt;/p&gt;
&lt;/p&gt;</summary><source><updated>2017-05-11T19:02:45-00:00</updated><subtitle type="text">Jane Street' blogs (Systems and OCaml rolled into one)</subtitle><link type="application/atom+xml" href="https://blogs.janestreet.com/category/ocaml/feed/atom/" rel="self"/><link type="text/html" href="https://blogs.janestreet.com" rel="alternate"/><generator uri="https://wordpress.org/" version="4.7.4">WordPress</generator><id>https://blogs.janestreet.com/feed/atom/</id><title type="text">OCaml – Jane Street Tech Blogs</title><author><name>Jane Street</name></author></source><published>2017-05-01T18:34:07-00:00</published><link type="application/atom+xml" href="https://blogs.janestreet.com/looking-for-a-technical-writer/feed/atom/" rel="replies"/><link type="text/html" href="https://blogs.janestreet.com/looking-for-a-technical-writer/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=looking-for-a-technical-writer#comments" rel="replies"/><link type="text/html" href="https://blogs.janestreet.com/looking-for-a-technical-writer/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=looking-for-a-technical-writer" rel="alternate"/><content xml:base="https://blogs.janestreet.com/wp-atom.php" type="html">&lt;p&gt;Jane Street is looking to hire a technical writer. If you're interested, or know someone who you think would be a good match, here's the &lt;a href=&quot;https://www.janestreet.com/join-jane-street/apply/?city=nyc&amp;amp;category=software-development&amp;amp;position=technical-writer&amp;amp;availability=full-time&quot;&gt;application link&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We've always believed that developers should spend time and effort documenting their own code, but at the same time, a great writer with a feel for the technology can raise the level of quality in a way that few developers can. And as we've grown, having someone dedicated to writing makes a ton of sense.&lt;/p&gt;
&lt;p&gt;Here are the kinds of things we'd like to have a technical writer work on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Training material.&lt;/strong&gt; We have a training program that many new hires go through, including most new developers and all new traders. In that program, they learn about OCaml, our base libraries, our build system, the UNIX shell, Emacs, and our dev tools. Part of the job would be to help make the course better, both by improving what we have, and by adding new material.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Improving library documentation.&lt;/strong&gt; While we expect developers to do a reasonable job of documenting their code, our most important libraries deserve the time and care to make them really shine. This is aimed both internally and externally, since a lot of these libraries, like Async, Core and Incremental, are open source.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Writing longer pieces.&lt;/strong&gt; We need more tutorials and overviews on a variety of topics. Part of the work would be to create great new documentation, and part of it is to serve as an example for others as to what good documentation looks like. And where possible, we want to do this so that the documentation effectively compiles against our current APIs, preventing it from just drifting out of date.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In terms of skills, we want someone who is both a clear and effective written communicator, and who is good enough at programming to navigate our codebase, work through our tutorials, and write up examples. An interest in functional programming and expressive type systems is a plus, but you don't need to know any OCaml (the language we use). That's something we're happy to teach you here.&lt;/p&gt;
</content><category scheme="https://blogs.janestreet.com" term="OCaml"/><id>https://blogs.janestreet.com/?p=1742</id><title xml:base="https://blogs.janestreet.com/wp-atom.php" type="html">Looking for a technical writer</title><updated>2017-05-01T18:38:29-00:00</updated><author><name>Yaron Minsky</name></author></entry><entry><source><updated>2017-04-30T02:22:00-00:00</updated><rights type="text">Copyright 2006-2010 Erik de Castro Lopo</rights><link title="m3ga blog" type="text/html" href="http://www.mega-nerd.com/erikd/Blog" rel="related"/><link title="m3ga blog" type="application/rss+xml" href="http://www.mega-nerd.com/erikd/Blog/index.rss20" rel="self"/><generator>PyBlosxom http://pyblosxom.sourceforge.net/ 1.4.3 01/10/2008</generator><id>http://www.mega-nerd.com/erikd/Blog</id><title type="text">m3ga blog</title><author><name>Erik de Castro Lopo</name></author></source><link href="http://www.mega-nerd.com/erikd/Blog/CodeHacking/Haskell/what_do_you_mean.html" rel="alternate"/><content xml:base="http://www.mega-nerd.com/erikd/Blog/index.rss20" type="html">

&lt;p&gt;
Disclaimer: I work at Ambiata (our
	&lt;a href=&quot;https://github.com/ambiata/&quot;&gt;Github&lt;/a&gt;
presence) probably the biggest Haskell shop in the southern hemisphere.
Although I mention some of Ambiata's coding practices, in this blog post I am
speaking for myself and not for Ambiata.
However, the way I'm using &lt;b&gt;&lt;tt&gt;ExceptT&lt;/tt&gt;&lt;/b&gt; and handling exceptions in
this post is something I learned from my colleagues at Ambiata.
&lt;/p&gt;

&lt;p&gt;
At work, I've been spending some time tracking down exceptions in some of our
Haskell code that have been bubbling up to the top level an killing a complex
multi-threaded program.
On Friday I posted a somewhat flippant comment to
	&lt;a href=&quot;https://plus.google.com/+ErikdeCastroLopo/posts/TbRiXuNucED&quot;&gt;Google Plus&lt;/a&gt;:
&lt;/p&gt;

&lt;blockquote&gt;
Using exceptions for control flow is the root of many evils in software.ï»¿
&lt;/blockquote&gt;

&lt;p&gt;
Lennart Kolmodin who I remember from my very earliest days of using Haskell in
2008 and who I met for the first time at ICFP in Copenhagen in 2011 responded:
&lt;/p&gt;

&lt;blockquote&gt;
Yet what to do if you want composable code? Currently I have&lt;br/&gt;
type Rpc a = ExceptT RpcError IO a&lt;br/&gt;
which is terrible
&lt;/blockquote&gt;

&lt;p&gt;
But what do we mean by &quot;composable&quot;?
I like the
	&lt;a href=&quot;https://en.wikipedia.org/wiki/Composability&quot;&gt;wikipedia&lt;/a&gt;
definition:
&lt;/p&gt;

&lt;blockquote&gt;
ï»¿Composability is a system design principle that deals with the inter-relationships
of components. A highly composable system provides recombinant components that
can be selected and assembled in various combinations to satisfy specific user
requirements.
&lt;/blockquote&gt;

&lt;p&gt;
The ensuing discussion, which also included Sean Leather, suggested that these
two experienced Haskellers were not aware that with the help of some combinator
functions, &lt;b&gt;&lt;tt&gt;ExceptT&lt;/tt&gt;&lt;/b&gt; composes very nicely and results in more
readable and more reliable code.
&lt;/p&gt;

&lt;p&gt;
At Ambiata, our coding guidelines strongly discourage the use of partial
functions.
Since the type signature of a function doesn't include information about the
exceptions it might throw, the use of exceptions is strongly discouraged.
When using library functions that may throw exceptions, we try to catch those
exceptions as close as possible to their source and turn them into
errors that are explicit in the type signatures of the code we write.
Finally, we avoid using &lt;b&gt;&lt;tt&gt;String&lt;/tt&gt;&lt;/b&gt; to hold errors.
Instead we construct data types to carry error messages and render functions
to convert them to &lt;b&gt;&lt;tt&gt;Text&lt;/tt&gt;&lt;/b&gt;.
&lt;/p&gt;

&lt;p&gt;
In order to properly demonstrate the ideas, I've written some demo code and
made it available in
	&lt;a href=&quot;https://github.com/erikd/exceptT-demo&quot;&gt;this GitHub repo&lt;/a&gt;.
It compiles and even runs (providing you give it the required number of command
line arguments) and hopefully does a good job demonstrating how the bits fit
together.
&lt;/p&gt;

&lt;p&gt;
So lets look at the naive version of a program that doesn't do any exception
handling at all.
&lt;/p&gt;

&lt;pre class=&quot;code&quot;&gt;

  import Data.ByteString.Char8 (readFile, writeFile)

  import Naive.Cat (Cat, parseCat)
  import Naive.Db (Result, processWithDb, renderResult, withDatabaseConnection)
  import Naive.Dog (Dog, parseDog)

  import Prelude hiding (readFile, writeFile)

  import System.Environment (getArgs)
  import System.Exit (exitFailure)

  main :: IO ()
  main = do
    args &amp;lt;- getArgs
    case args of
      [inFile1, infile2, outFile] -&gt; processFiles inFile1 infile2 outFile
      _ -&gt; putStrLn &quot;Expected three file names.&quot; &gt;&gt; exitFailure

  readCatFile :: FilePath -&gt; IO Cat
  readCatFile fpath = do
    putStrLn &quot;Reading Cat file.&quot;
    parseCat &amp;lt;$&gt; readFile fpath

  readDogFile :: FilePath -&gt; IO Dog
  readDogFile fpath = do
    putStrLn &quot;Reading Dog file.&quot;
    parseDog &amp;lt;$&gt; readFile fpath

  writeResultFile :: FilePath -&gt; Result -&gt; IO ()
  writeResultFile fpath result = do
    putStrLn &quot;Writing Result file.&quot;
    writeFile fpath $ renderResult result

  processFiles :: FilePath -&gt; FilePath -&gt; FilePath -&gt; IO ()
  processFiles infile1 infile2 outfile = do
    cat &amp;lt;- readCatFile infile1
    dog &amp;lt;- readDogFile infile2
    result &amp;lt;- withDatabaseConnection $ \ db -&gt;
                 processWithDb db cat dog
    writeResultFile outfile result

&lt;/pre&gt;

&lt;p&gt;
Once built as per the instructions in the repo, it can be run with:
&lt;/p&gt;

&lt;pre class=&quot;code&quot;&gt;

  dist/build/improved/improved Naive/Cat.hs Naive/Dog.hs /dev/null
  Reading Cat file 'Naive/Cat.hs'
  Reading Dog file 'Naive/Dog.hs'.
  Writing Result file '/dev/null'.

&lt;/pre&gt;


&lt;p&gt;
The above code is pretty naive and there is zero indication of what can and
cannot fail or how it can fail.
Here's a list of some of the obvious failures that may result in an exception
being thrown:
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Either of the two &lt;b&gt;&lt;tt&gt;readFile&lt;/tt&gt;&lt;/b&gt; calls.&lt;/li&gt;
&lt;li&gt;The &lt;b&gt;&lt;tt&gt;writeFile&lt;/tt&gt;&lt;/b&gt; call.&lt;/li&gt;
&lt;li&gt;The parsing functions &lt;b&gt;&lt;tt&gt;parseCat&lt;/tt&gt;&lt;/b&gt; and
	&lt;b&gt;&lt;tt&gt;parseDog&lt;/tt&gt;&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;Opening the database connection.&lt;/li&gt;
&lt;li&gt;The database connection could terminate during the processing stage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
So lets see how the use of the standard &lt;b&gt;&lt;tt&gt;Either&lt;/tt&gt;&lt;/b&gt; type,
&lt;b&gt;&lt;tt&gt;ExceptT&lt;/tt&gt;&lt;/b&gt; from the &lt;b&gt;&lt;tt&gt;transformers&lt;/tt&gt;&lt;/b&gt; package and
combinators from Gabriel Gonzales' &lt;b&gt;&lt;tt&gt;errors&lt;/tt&gt;&lt;/b&gt; package can improve
things.
&lt;/p&gt;

&lt;p&gt;
Firstly the types of &lt;b&gt;&lt;tt&gt;parseCat&lt;/tt&gt;&lt;/b&gt; and &lt;b&gt;&lt;tt&gt;parseDog&lt;/tt&gt;&lt;/b&gt; were
ridiculous.
Parsers can fail with parse errors, so these should both return an
&lt;b&gt;&lt;tt&gt;Either&lt;/tt&gt;&lt;/b&gt; type.
Just about everything else should be in the &lt;b&gt;&lt;tt&gt;ExceptT e IO&lt;/tt&gt;&lt;/b&gt;
monad.
Lets see what that looks like:
&lt;/p&gt;

&lt;pre class=&quot;code&quot;&gt;

  {-# LANGUAGE OverloadedStrings #-}
  import           Control.Exception (SomeException)
  import           Control.Monad.IO.Class (liftIO)
  import           Control.Error (ExceptT, fmapL, fmapLT, handleExceptT
                                 , hoistEither, runExceptT)

  import           Data.ByteString.Char8 (readFile, writeFile)
  import           Data.Monoid ((&amp;lt;&amp;gt;))
  import           Data.Text (Text)
  import qualified Data.Text as T
  import qualified Data.Text.IO as T

  import           Improved.Cat (Cat, CatParseError, parseCat, renderCatParseError)
  import           Improved.Db (DbError, Result, processWithDb, renderDbError
                               , renderResult, withDatabaseConnection)
  import           Improved.Dog (Dog, DogParseError, parseDog, renderDogParseError)

  import           Prelude hiding (readFile, writeFile)

  import           System.Environment (getArgs)
  import           System.Exit (exitFailure)

  data ProcessError
    = ECat CatParseError
    | EDog DogParseError
    | EReadFile FilePath Text
    | EWriteFile FilePath Text
    | EDb DbError

  main :: IO ()
  main = do
    args &amp;lt;- getArgs
    case args of
      [inFile1, infile2, outFile] -&gt;
              report =&amp;lt;&amp;lt; runExceptT (processFiles inFile1 infile2 outFile)
      _ -&gt; do
          putStrLn &quot;Expected three file names, the first two are input, the last output.&quot;
          exitFailure

  report :: Either ProcessError () -&gt; IO ()
  report (Right _) = pure ()
  report (Left e) = T.putStrLn $ renderProcessError e


  renderProcessError :: ProcessError -&gt; Text
  renderProcessError pe =
    case pe of
      ECat ec -&gt; renderCatParseError ec
      EDog ed -&gt; renderDogParseError ed
      EReadFile fpath msg -&gt; &quot;Error reading '&quot; &amp;lt;&amp;gt; T.pack fpath &amp;lt;&amp;gt; &quot;' : &quot; &amp;lt;&amp;gt; msg
      EWriteFile fpath msg -&gt; &quot;Error writing '&quot; &amp;lt;&amp;gt; T.pack fpath &amp;lt;&amp;gt; &quot;' : &quot; &amp;lt;&amp;gt; msg
      EDb dbe -&gt; renderDbError dbe


  readCatFile :: FilePath -&gt; ExceptT ProcessError IO Cat
  readCatFile fpath = do
    liftIO $ putStrLn &quot;Reading Cat file.&quot;
    bs &amp;lt;- handleExceptT handler $ readFile fpath
    hoistEither . fmapL ECat $ parseCat bs
    where
      handler :: SomeException -&gt; ProcessError
      handler e = EReadFile fpath (T.pack $ show e)

  readDogFile :: FilePath -&gt; ExceptT ProcessError IO Dog
  readDogFile fpath = do
    liftIO $ putStrLn &quot;Reading Dog file.&quot;
    bs &amp;lt;- handleExceptT handler $ readFile fpath
    hoistEither . fmapL EDog $ parseDog bs
    where
      handler :: SomeException -&gt; ProcessError
      handler e = EReadFile fpath (T.pack $ show e)

  writeResultFile :: FilePath -&gt; Result -&gt; ExceptT ProcessError IO ()
  writeResultFile fpath result = do
    liftIO $ putStrLn &quot;Writing Result file.&quot;
    handleExceptT handler . writeFile fpath $ renderResult result
    where
      handler :: SomeException -&gt; ProcessError
      handler e = EWriteFile fpath (T.pack $ show e)

  processFiles :: FilePath -&gt; FilePath -&gt; FilePath -&gt; ExceptT ProcessError IO ()
  processFiles infile1 infile2 outfile = do
    cat &amp;lt;- readCatFile infile1
    dog &amp;lt;- readDogFile infile2
    result &amp;lt;- fmapLT EDb . withDatabaseConnection $ \ db -&gt;
                 processWithDb db cat dog
    writeResultFile outfile result

&lt;/pre&gt;

&lt;p&gt;
The first thing to notice is that changes to the structure of the main
processing function &lt;b&gt;&lt;tt&gt;processFiles&lt;/tt&gt;&lt;/b&gt; are minor but &lt;i&gt;all&lt;/i&gt; errors
are now handled explicitly.
In addition, all possible exceptions are caught as close as possible to the
source and turned into errors that are explicit in the function return types.
Sceptical?
Try replacing one of the  &lt;b&gt;&lt;tt&gt;readFile&lt;/tt&gt;&lt;/b&gt; calls with an
&lt;b&gt;&lt;tt&gt;error&lt;/tt&gt;&lt;/b&gt; call or a &lt;b&gt;&lt;tt&gt;throw&lt;/tt&gt;&lt;/b&gt; and see it get caught
and turned into an error as specified by the type of the function.
&lt;/p&gt;

&lt;p&gt;
We also see that despite having many different error types (which happens when
code is split up into many packages and modules), a constructor for an error
type higher in the stack can encapsulate error types lower in the stack.
For example, this value of type &lt;b&gt;&lt;tt&gt;ProcessError&lt;/tt&gt;&lt;/b&gt;:
&lt;/p&gt;

&lt;pre class=&quot;code&quot;&gt;

  EDb (DbError3 ResultError1)

&lt;/pre&gt;

&lt;p&gt;
contains a &lt;b&gt;&lt;tt&gt;DbError&lt;/tt&gt;&lt;/b&gt; which in turn contains a
&lt;b&gt;&lt;tt&gt;ResultError&lt;/tt&gt;&lt;/b&gt;.
Nesting error types like this aids composition, as does the separation of error
rendering (turning an error data type into text to be printed) from printing.
&lt;/p&gt;

&lt;p&gt;
We also see that with the use of combinators like
	&lt;a href=&quot;https://hackage.haskell.org/package/errors-2.2.0/docs/Data-EitherR.html#v:fmapLT&quot;&gt;&lt;b&gt;&lt;tt&gt;fmapLT&lt;/tt&gt;&lt;/b&gt;&lt;/a&gt;,
and the nested error types of the previous paragraph, means that
&lt;b&gt;&lt;tt&gt;ExceptT&lt;/tt&gt;&lt;/b&gt; monad transformers do compose.
&lt;/p&gt;

&lt;p&gt;
Using &lt;b&gt;&lt;tt&gt;ExceptT&lt;/tt&gt;&lt;/b&gt; with the combinators from the
&lt;b&gt;&lt;tt&gt;errors&lt;/tt&gt;&lt;/b&gt; package to catch exceptions as close as possible to their
source and converting them to errors has numerous benefits including:
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Errors are explicit in the types of the functions, making the code easier
	to reason about.&lt;/li&gt;
&lt;li&gt; Its easier to provide better error messages and more context than what
	is normally provided by the &lt;b&gt;&lt;tt&gt;Show&lt;/tt&gt;&lt;/b&gt; instance of most
	exceptions.&lt;/li&gt;
&lt;li&gt; The programmer spends less time chasing the source of exceptions in large
	complex code bases.&lt;/li&gt;
&lt;li&gt; More robust code, because the programmer is forced to think about and
	write code to handle errors instead of error handling being and optional
	afterthought.
	&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
Want to discuss this?
Try &lt;a href=&quot;https://www.reddit.com/r/haskell/comments/68kyfx/what_do_you_mean_exceptt_doesnt_compose/&quot;&gt;reddit&lt;/a&gt;.
&lt;/p&gt;

</content><category scheme="http://www.mega-nerd.com/erikd/Blog" term="/CodeHacking/Haskell"/><id>http://www.mega-nerd.com/erikd/Blog#dfe951a7a5e460ae1254005169456a78</id><title type="text">What do you mean ExceptT doesn't Compose?</title><updated>2017-04-30T02:22:00-00:00</updated><author><name>Erik de Castro Lopo</name></author></entry><entry><source><updated>2017-05-11T13:20:05-00:00</updated><logo>http://www.ocamlpro.com/wp-content/uploads/2016/02/cropped-favicon-32x32.png</logo><link title="OCamlPro" type="text/html" href="http://www.ocamlpro.com" rel="related"/><link title="OCamlPro" type="application/rss+xml" href="http://www.ocamlpro.com/feed/" rel="self"/><generator>https://wordpress.org/?v=4.7.4</generator><id>http://www.ocamlpro.com</id><title type="text">OCamlPro</title><author><name>OCamlPro</name></author></source><link href="http://www.ocamlpro.com/2017/04/27/new-opam-features-local-switches/" rel="alternate"/><link href="http://www.ocamlpro.com/2017/04/27/new-opam-features-local-switches/#comments" rel="related"/><content xml:base="http://www.ocamlpro.com/feed/" type="html">&lt;p&gt;Among the areas we wanted to improve on for opam 2.0 was the handling of &lt;em&gt;switches&lt;/em&gt;. In opam 1.2, they are simply accessed by a name (the OCaml version by default), and are always stored into &lt;code&gt;~/.opam/&amp;lt;name&amp;gt;&lt;/code&gt;. This is fine, but can get a bit cumbersome when many switches are in presence, as there is no way to sort them or associate them with a given project.&lt;/p&gt;
&lt;blockquote&gt;
&lt;h3 id=&quot;Areminderaboutswitches&quot;&gt;A reminder about &lt;em&gt;switches&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;For those unfamiliar with it, switches, in opam, are independent prefixes with their own compiler and set of installed packages. The &lt;code&gt;opam switch&lt;/code&gt; command allows to create and remove switches, as well as select the currently active one, where operations like &lt;code&gt;opam install&lt;/code&gt; will operate.&lt;/p&gt;
&lt;p&gt;Their uses include easily juggling between versions of OCaml, or of a library, having incompatible packages installed separately but at the same time, running tests without damaging your &amp;#8220;main&amp;#8221; environment, and, quite often, separation of environment for working on different projects.&lt;/p&gt;
&lt;p&gt;You can also select a specific switch for a single command, with&lt;/p&gt;
&lt;pre class=&quot;brush: bash; title: ; notranslate&quot;&gt;
opam install foo --switch other
&lt;/pre&gt;
&lt;p&gt;or even for a single shell session, with&lt;/p&gt;
&lt;pre class=&quot;brush: bash; title: ; notranslate&quot;&gt;
eval $(opam env --switch other)
&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;What opam 2.0 adds to this is the possibility to create so-called &lt;em&gt;local switches&lt;/em&gt;, stored below a directory of your choice. This gets users back in control of how switches are organised, and wiping the directory is a safe way to get rid of the switch.&lt;/p&gt;
&lt;h3 id=&quot;Usingwithinprojects&quot;&gt;Using within projects&lt;/h3&gt;
&lt;p&gt;This is the main intended use: the user can define a switch within the source of a project, for use specifically in that project. One nice side-effect to help with this is that, if a &amp;#8220;local switch&amp;#8221; is detected in the current directory or a parent, opam will select it automatically. Just don&amp;#8217;t forget to run &lt;code&gt;eval $(opam env)&lt;/code&gt; to make the environment up-to-date before running &lt;code&gt;make&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;Interface&quot;&gt;Interface&lt;/h3&gt;
&lt;p&gt;The interface simply overloads the &lt;code&gt;switch-name&lt;/code&gt; arguments, wherever they were present, allowing directory names instead. So for example:&lt;/p&gt;
&lt;pre class=&quot;brush: bash; title: ; notranslate&quot;&gt;
cd ~/src/project
opam switch create ./
&lt;/pre&gt;
&lt;p&gt;will create a local switch in the directory &lt;code&gt;~/src/project&lt;/code&gt;. Then, it is for example equivalent to run &lt;code&gt;opam list&lt;/code&gt; from that directory, or &lt;code&gt;opam list --switch=~/src/project&lt;/code&gt; from anywhere.&lt;/p&gt;
&lt;p&gt;Note that you can bypass the automatic local-switch selection if needed by using the &lt;code&gt;--switch&lt;/code&gt; argument, by defining the variable &lt;code&gt;OPAMSWITCH&lt;/code&gt; or by using &lt;code&gt;eval $(opam env --switch &amp;lt;name&amp;gt;)&lt;/code&gt;&lt;/p&gt;
&lt;h3 id=&quot;Implementation&quot;&gt;Implementation&lt;/h3&gt;
&lt;p&gt;In practice, the switch contents are placed in a &lt;code&gt;_opam/&lt;/code&gt; subdirectory. So if you create the switch &lt;code&gt;~/src/project&lt;/code&gt;, you can browse its contents at &lt;code&gt;~/src/project/_opam&lt;/code&gt;. This is the direct prefix for the switch, so e.g. binaries can be found directly at &lt;code&gt;_opam/bin/&lt;/code&gt;: easier than searching the opam root! The opam metadata is placed below that directory, in a &lt;code&gt;.opam-switch/&lt;/code&gt; subdirectory.&lt;/p&gt;
&lt;p&gt;Local switches still share the opam root, and in particular depend on the repositories defined and cached there. It is now possible, however, to select different repositories for different switches, but that is a subject for another post.&lt;/p&gt;
&lt;p&gt;Finally, note that removing that &lt;code&gt;_opam&lt;/code&gt; directory is handled transparently by opam, and that if you want to share a local switch between projects, symlinking the &lt;code&gt;_opam&lt;/code&gt; directory is allowed.&lt;/p&gt;
&lt;h3 id=&quot;Currentstatus&quot;&gt;Current status&lt;/h3&gt;
&lt;p&gt;This feature has been present in our dev builds for a while, and you can already use it in the &lt;a href=&quot;https://github.com/ocaml/opam/releases/tag/2.0.0-beta2&quot;&gt;current beta&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;Limitationsandfutureextensions&quot;&gt;Limitations and future extensions&lt;/h3&gt;
&lt;p&gt;It is not, at the moment, possible to move a local switch directory around, mainly due to issues related to relocating the OCaml compiler.&lt;/p&gt;
&lt;p&gt;Creating a new switch still implies to recompile all the packages, and even the compiler itself (unless you rely on a system installation). The projected solution is to add a build cache, avoiding the need to recompile the same package with the same dependencies. This should actually be possible with the current opam 2.0 code, by leveraging the new hooks that are made available. Note that relocation of OCaml is also an issue for this, though.&lt;/p&gt;
&lt;p&gt;Editing tools like &lt;code&gt;ocp-indent&lt;/code&gt; or &lt;code&gt;merlin&lt;/code&gt; can also become an annoyance with the multiplication of switches, because they are not automatically found if not installed in the current switch. But the &lt;code&gt;user-setup&lt;/code&gt; plugin (run &lt;code&gt;opam user-setup install&lt;/code&gt;) already handles this well, and will access &lt;code&gt;ocp-indent&lt;/code&gt; or &lt;code&gt;tuareg&lt;/code&gt; from their initial switch, if not found in the current one. You will still need to install tools that are tightly bound to a compiler version, like &lt;code&gt;merlin&lt;/code&gt; and &lt;code&gt;ocp-index&lt;/code&gt;, in the switches where you need them, though.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;NOTE: this article is cross-posted on &lt;a href=&quot;https://opam.ocaml.org/blog/&quot;&gt;opam.ocaml.org&lt;/a&gt; and &lt;a href=&quot;http://www.ocamlpro.com/category/blog/&quot;&gt;ocamlpro.com&lt;/a&gt;. Please head to the latter for the comments!&lt;/p&gt;&lt;/blockquote&gt;
</content><category term="Blog"/><id>http://www.ocamlpro.com/?p=652</id><title type="text">New opam features: local switches</title><updated>2017-04-27T16:27:32-00:00</updated><author><name>OCamlPro</name></author></entry><entry><summary xml:base="https://blogs.janestreet.com/wp-atom.php" type="html">&lt;p&gt;We have a new &lt;a href=&quot;https://www.janestreet.com/tech-talks/&quot;&gt;tech talk&lt;/a&gt; coming up on May 17th, from our very own Dominick LoBraico. This one is about how to represent configurations with programs. In some sense, this is an obvious idea. Lots of programmers have experienced the dysphoria that comes from watching your elegant little configuration format metamorphize into a badly constructed programming language with miserable tools. This happens because, as you try to make your configs clearer and more concise, you often end up walking down the primrose path of making your config format ever more language-like. But you never really have the time to make it into a proper language.&lt;/p&gt; &lt;a href=&quot;https://blogs.janestreet.com/caveat-configurator-how-to-replace-configs-with-code-and-why-you-might-not-want-to/&quot;&gt;&amp;#187; Continue Reading.&lt;/a&gt;</summary><source><updated>2017-05-11T19:02:45-00:00</updated><subtitle type="text">Jane Street' blogs (Systems and OCaml rolled into one)</subtitle><link type="application/atom+xml" href="https://blogs.janestreet.com/category/ocaml/feed/atom/" rel="self"/><link type="text/html" href="https://blogs.janestreet.com" rel="alternate"/><generator uri="https://wordpress.org/" version="4.7.4">WordPress</generator><id>https://blogs.janestreet.com/feed/atom/</id><title type="text">OCaml – Jane Street Tech Blogs</title><author><name>Jane Street</name></author></source><published>2017-04-25T22:16:53-00:00</published><link type="application/atom+xml" href="https://blogs.janestreet.com/caveat-configurator-how-to-replace-configs-with-code-and-why-you-might-not-want-to/feed/atom/" rel="replies"/><link type="text/html" href="https://blogs.janestreet.com/caveat-configurator-how-to-replace-configs-with-code-and-why-you-might-not-want-to/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=caveat-configurator-how-to-replace-configs-with-code-and-why-you-might-not-want-to#comments" rel="replies"/><link type="text/html" href="https://blogs.janestreet.com/caveat-configurator-how-to-replace-configs-with-code-and-why-you-might-not-want-to/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=caveat-configurator-how-to-replace-configs-with-code-and-why-you-might-not-want-to" rel="alternate"/><content xml:base="https://blogs.janestreet.com/wp-atom.php" type="html">&lt;p&gt;We have a new &lt;a href=&quot;https://www.janestreet.com/tech-talks/&quot;&gt;tech talk&lt;/a&gt; coming up on May 17th, from our very own Dominick LoBraico. This one is about how to represent configurations with programs. In some sense, this is an obvious idea. Lots of programmers have experienced the dysphoria that comes from watching your elegant little configuration format metamorphize into a badly constructed programming language with miserable tools. This happens because, as you try to make your configs clearer and more concise, you often end up walking down the primrose path of making your config format ever more language-like. But you never really have the time to make it into a proper language.&lt;/p&gt;
&lt;p&gt;The obvious alternative is to just use a real language, one that comes with decent tooling and well-designed abstractions. (And ideally, a functional language, because they tend to be better at writing clear, declarative code.)&lt;/p&gt;
&lt;p&gt;This talk discusses what happens when you try to put this obvious idea into practice, which is less, well, obvious. I like this kind of topic because it represents the kind of hard-won knowledge you can only get by trying something and screwing it up a few times.&lt;/p&gt;
&lt;p&gt;So please join us! You can register &lt;a href=&quot;https://docs.google.com/a/janestreet.com/forms/d/e/1FAIpQLSdJamD_TBdFq6NjaGLN6FaNKTHIGXgWFON2QQSde-7X7SoXUA/viewform?c=0&amp;amp;w=1&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
</content><category scheme="https://blogs.janestreet.com" term="OCaml"/><id>https://blogs.janestreet.com/?p=1732</id><title xml:base="https://blogs.janestreet.com/wp-atom.php" type="html">Caveat Configurator: how to replace configs with code, and why you might not want to</title><updated>2017-04-25T22:18:47-00:00</updated><author><name>Yaron Minsky</name></author></entry><entry><source><updated>2017-05-09T12:00:00-00:00</updated><link title="OCaml Weekly News" type="text/html" href="http://alan.petitepomme.net/cwn/" rel="related"/><link title="OCaml Weekly News" type="application/rss+xml" href="http://alan.petitepomme.net/cwn/cwn.rss" rel="self"/><id>http://alan.petitepomme.net/cwn/</id><title type="text">OCaml Weekly News</title><author><name>OCaml Weekly News</name></author></source><link href="http://alan.petitepomme.net/cwn/2017.04.25.html" rel="alternate"/><content xml:base="http://alan.petitepomme.net/cwn/cwn.rss" type="html">&lt;ol&gt;&lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.04.25.html#1&gt;error messages in multiple languages ?&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.04.25.html#2&gt;support for OCaml on unusual platforms (ia64-hpux, etc.)&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.04.25.html#3&gt;OCaml jobs at genomics company in New York City&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.04.25.html#4&gt;Ocaml 4.04.1 released&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.04.25.html#5&gt;release of batteries-2.6.0&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.04.25.html#6&gt;New release of Menhir (20170418)&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.04.25.html#7&gt;Lwt 3.0.0 – monadic promises and concurrent I/O&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.04.25.html#8&gt;PPX is harmful to our community in the long term&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.04.25.html#9&gt;BuckleScript 1.7&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.04.25.html#10&gt;CUFP 2017 Call for Tutorials&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.04.25.html#11&gt;Ocaml Github Pull Requests&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.04.25.html#12&gt;Other OCaml News&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;</content><id>http://alan.petitepomme.net/cwn/2017.04.25.html</id><title type="text">Weekly News</title><updated>2017-04-25T12:00:00-00:00</updated><author><name>OCaml Weekly News</name></author></entry><entry><source><updated>2017-05-08T15:23:58-00:00</updated><link href="http://jobs.github.com/" rel="alternate"/><link href="http://jobs.github.com/positions.atom?description=ocaml" rel="self"/><id>urn:uuid:0a9333c4-71da-11e0-9ac7-692793c00b45</id><title type="text">
    GitHub Jobs
      matching ocaml
  </title><author><email>jobs@github.com</email><name>GitHub Jobs</name></author></source><link href="http://jobs.github.com/positions/9c9c5cac-28e3-11e7-8515-f5b67b252bbb" rel="alternate"/><content xml:base="https://jobs.github.com/positions.atom?description=ocaml" type="html">&lt;p&gt;&lt;strong&gt;Fulltime, Copenhagen&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;issuu is the world&amp;#39;s fastest-growing digital publishing platform. We are looking for a new member to join our fantastic team. With great people, unique ideas and stunning technology, we&amp;#39;re changing the future of publishing today. Can you be the best at what you do? Join us!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;About this job&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As a Front-end Developer at issuu, you will be joining a team of highly skilled web enthusiasts building web applications in an agile environment.
We currently develop for desktops, tablets and mobile web. This requires great responsive sites that ensure the best possible user experience on all platforms.&lt;/p&gt;

&lt;p&gt;We run a NodeJS server in a production system that serves billions of pages every month. Our client-side applications are a mix of vanilla JavaScript (transpiled with Babel from ES2015), and React / Redux, apps with an in-house developed, modular, BEM-styled styling framework.SASS enables us to keep our CSS well structured.&lt;/p&gt;

&lt;p&gt;As our ideal candidate, you are excited about HTML5 features, like SVG and &lt;canvas/&gt;, and have a feel for the pulse of new developments in browser technology.In a system the size of issuu’s, code maintainability is just as important as accessibility. That also means that you are willing to share your code with other people or sit together for pair-programming sessions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What we Like&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We think browsers are awesome.&lt;/li&gt;
&lt;li&gt;We love HTML5, CSS3 and all the new exciting web APIs.&lt;/li&gt;
&lt;li&gt;We use React, Redux, ES2015 and CSS Modules.&lt;/li&gt;
&lt;li&gt;We draw with Canvas, WebGL and SVGs.&lt;/li&gt;
&lt;li&gt;We build modern progressive web apps.&lt;/li&gt;
&lt;li&gt;We like declarative and functional programming.&lt;/li&gt;
&lt;li&gt;We used to like jQuery and Backbone, but now we sort of grew apart.&lt;/li&gt;
&lt;li&gt;We also like it if our front-end developers aren’t afraid of touching our backends, which we make with -&lt;/li&gt;
&lt;li&gt;Python, NodeJS, OCaml and Erlang.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Qualifications&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Demonstrated ability to deliver results in a fast-paced environment as a self-starter and quick learner&lt;/li&gt;
&lt;li&gt;Expert understanding of browsers, web technologies (object-oriented JavaScript, ES2015, HTML, 
CSS), and a passion for the latest and greatest web standards&lt;/li&gt;
&lt;li&gt;Experience in collaborating with UI Designers&lt;/li&gt;
&lt;li&gt;Experience architecting and building robust, high-performance production web applications&lt;/li&gt;
&lt;li&gt;Used to working with Design and Product teams in an agile fashion&lt;/li&gt;
&lt;li&gt;Experience with building web applications for mobile web is a plus&lt;/li&gt;
&lt;li&gt;Experience with MVC-based web applications is a plus&lt;/li&gt;
&lt;li&gt;Experience with server-side languages like Python is a plus&lt;/li&gt;
&lt;li&gt;Solid communications skills in English&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What we Offer&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You’ll be a part of issuu – an amazing place with room for parents, foodies, geeks, odd birds and the occasional normal person&lt;/li&gt;
&lt;li&gt;Informal, inclusive and very flexible workplace&lt;/li&gt;
&lt;li&gt;Competitive compensation package&lt;/li&gt;
&lt;li&gt;Flat hierarchy – every opinion matters regardless of team and position&lt;/li&gt;
&lt;li&gt;Regular hackathons&lt;/li&gt;
&lt;li&gt;A sleek Mac and a pretty sweet desk setup&lt;/li&gt;
&lt;li&gt;Great offices in Copenhagen, Palo Alto and Berlin&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;About the Team and Office&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You will be joining our DK engineering team in Copenhagen consisting of approx. 27 developers. We are a diverse office with members of all parts of issuu, including Customer Support, Product, Design, Data Analytics and Management.&lt;/p&gt;

&lt;p&gt;In a company the size of issuu, code maintainability is just as important as site accessibility. That also means that you are willing to share your code with other people or sit together for pair programming sessions.&lt;/p&gt;

&lt;p&gt;Our office is conveniently located next to the Copenhagen Central Station. We provide nice, catered lunches each day, regular outings and monthly Friday bars with drinks, snacks and activities. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;About issuu&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;issuu connects the world’s publishers to an audience of active consumers, on a global scale. Every day millions of people find, read and share billions of pieces of content they find meaningful, from every device. Millions of magazine, newspaper and catalog creators are empowered to distribute, measure and monetize their work through the issuu platform &lt;a href=&quot;http://issuu.com&quot;&gt;issuu&lt;/a&gt;. 
If you are interested in a sneak peek of who we are as issuuees, have a look at our &lt;a href=&quot;https://issuu.com/issuu/docs/issuubrandbook&quot;&gt;brandbook&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Details&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It’s a prerequisite that you have a valid EU work permit&lt;/p&gt;
</content><id>urn:uuid:9c9c5cac-28e3-11e7-8515-f5b67b252bbb</id><title type="text">Full Time: Front-end Developer at issuu in Copenhagen</title><updated>2017-04-24T11:46:46-00:00</updated><author><email>jobs@github.com</email><name>GitHub Jobs</name></author></entry><entry><source><updated>2017-04-18T12:00:00-00:00</updated><link title="OCaml Labs compiler hacking" type="text/html" href="http://ocamllabs.github.com/compiler-hacking/" rel="related"/><link title="OCaml Labs compiler hacking" type="application/rss+xml" href="http://ocamllabs.github.com/compiler-hacking/rss.xml" rel="self"/><id>http://ocamllabs.github.com/compiler-hacking/</id><title type="text">OCaml Labs compiler hacking</title><author><name>OCaml Labs compiler hacking</name></author></source><link href="http://ocamllabs.github.com/compiler-hacking/2017/04/18/seventeenth-compiler-hacking-may" rel="alternate"/><content xml:base="http://ocamllabs.github.com/compiler-hacking/rss.xml" type="html">&lt;p&gt;Our next OCaml Compiler Hacking event will be on Tuesday 16th May in The Old Library at Pembroke College, Cambridge.&lt;/p&gt;

&lt;p&gt;If you&amp;#39;re planning to come along, it&amp;#39;d be helpful if you could &lt;a href=&quot;https://doodle.com/poll/dxvcih4d9en2t5vy&quot;&gt;indicate interest via Doodle&lt;/a&gt; and &lt;a href=&quot;http://lists.ocaml.org/admin/cam-compiler-hacking&quot;&gt;sign up to the mailing list&lt;/a&gt; to receive updates.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Where&lt;/strong&gt;&lt;/em&gt;: The Old Library, Pembroke College​, ​Cambridge​ ​CB2 1RF&lt;/p&gt;

&lt;p&gt;​The Old Library is the first building on the left straight after the Porters Lodge.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;When&lt;/strong&gt;&lt;/em&gt;: 6:30pm, Tuesday 16​th ​May&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Who&lt;/strong&gt;&lt;/em&gt;: anyone interested in improving OCaml. Knowledge of OCaml programming will obviously be helpful, but prior experience of working on OCaml internals isn&amp;#39;t necessary.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Refreshments&lt;/strong&gt;&lt;/em&gt;: either the Pembroke buttery between 5:45-6:45pm (cash only) or there will be a finger buffet in​ The Old Library​ itself.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;What&lt;/strong&gt;&lt;/em&gt;: fixing bugs, implementing new features, learning about OCaml internals&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Wiki&lt;/strong&gt;&lt;/em&gt;: https://github.com/ocamllabs/compiler-hacking/wiki&lt;/p&gt;

&lt;p&gt;We&amp;#39;re defining &amp;quot;compiler&amp;quot; pretty broadly, to include anything that&amp;#39;s part of the standard distribution, which means at least the
 &lt;a href=&quot;https://github.com/ocaml/ocaml/tree/trunk/stdlib&quot;&gt;standard library&lt;/a&gt;,
 &lt;a href=&quot;https://github.com/ocaml/ocaml/tree/trunk/byterun&quot;&gt;run&lt;/a&gt;&lt;a href=&quot;https://github.com/ocaml/ocaml/tree/trunk/asmrun&quot;&gt;time&lt;/a&gt;, tools
    (&lt;a href=&quot;http://caml.inria.fr/pub/docs/manual-ocaml/depend.html&quot;&gt;ocamldep&lt;/a&gt;,
     &lt;a href=&quot;https://realworldocaml.org/v1/en/html/parsing-with-ocamllex-and-menhir.html&quot;&gt;ocamllex&lt;/a&gt;,
     &lt;a href=&quot;http://caml.inria.fr/pub/docs/manual-ocaml-4.00/manual026.html&quot;&gt;ocamlyacc&lt;/a&gt;, etc.), the
 &lt;a href=&quot;http://caml.inria.fr/pub/docs/manual-ocaml/debugger.html&quot;&gt;debugger&lt;/a&gt;, the
 &lt;a href=&quot;https://github.com/ocaml/ocaml/tree/trunk/manual&quot;&gt;documentation&lt;/a&gt;, and the
 &lt;a href=&quot;https://github.com/ocaml/ocaml&quot;&gt;compiler&lt;/a&gt; itself. We&amp;#39;ll have
 &lt;a href=&quot;https://github.com/ocamllabs/compiler-hacking/wiki/Things-to-work-on&quot;&gt;suggestions for mini-projects&lt;/a&gt; for various levels of experience, but feel free to come along and work on whatever you fancy.&lt;/p&gt;
</content><id>http://ocamllabs.github.com/compiler-hacking/2017/04/18/seventeenth-compiler-hacking-may</id><title type="text">Seventeenth OCaml compiler hacking evening at Pembroke</title><updated>2017-04-18T12:00:00-00:00</updated><author><email>cl-ocamllabs@lists.cam.ac.uk</email><name>OCaml Labs</name></author></entry><entry><source><updated>2017-04-17T00:00:00-00:00</updated><link title="Drup's thingies" type="text/html" href="https://drup.github.io/" rel="related"/><link title="Drup's thingies" type="application/rss+xml" href="http://drup.github.io/feed-ocaml.xml" rel="self"/><id>https://drup.github.io/</id><title type="text">Drup's thingies</title><author><name>Gabriel Radanne</name></author></source><link href="https://drup.github.io/2017/04/17/tyre-news/" rel="alternate"/><content xml:base="http://drup.github.io/feed-ocaml.xml" type="html">
        
        
        
        &lt;p&gt;Here are some news about &lt;a href=&quot;https://github.com/Drup/tyre&quot;&gt;Tyre&lt;/a&gt;, along with release of version 0.3.&lt;/p&gt;


        
        </content><id>https://drup.github.io/2017/04/17/tyre-news/</id><title type="text">News about Tyre | Drup's thingies</title><updated>2017-04-17T00:00:00-00:00</updated><author><name>Gabriel Radanne</name></author></entry><entry><source><updated>2017-05-11T13:20:05-00:00</updated><logo>http://www.ocamlpro.com/wp-content/uploads/2016/02/cropped-favicon-32x32.png</logo><link title="OCamlPro" type="text/html" href="http://www.ocamlpro.com" rel="related"/><link title="OCamlPro" type="application/rss+xml" href="http://www.ocamlpro.com/feed/" rel="self"/><generator>https://wordpress.org/?v=4.7.4</generator><id>http://www.ocamlpro.com</id><title type="text">OCamlPro</title><author><name>OCamlPro</name></author></source><link href="http://www.ocamlpro.com/2017/04/11/ezsudoku/" rel="alternate"/><link href="http://www.ocamlpro.com/2017/04/11/ezsudoku/#comments" rel="related"/><content xml:base="http://www.ocamlpro.com/feed/" type="html">&lt;p&gt;As you may have noticed, on the begining of April I have some urge to write something technical about some deeply specific point of OCaml. This time I&amp;#8217;d like to tackle that through sudoku.&lt;/p&gt;
&lt;p&gt;It appearch that Sudoku is of great importance considering the number of posts explaining how to write a solver. Following that trend I will explain how to write one in OCaml. But with a twist.&lt;/p&gt;
&lt;p&gt;We will try to optimize it. I won&amp;#8217;t show you anything as obvious as how to micro-optimize your code or some smart heuristc. No we are not aiming for being merely algorithmically good. We will try to make something serious, we are want it to be solved even before the program starts.&lt;/p&gt;
&lt;p&gt;Yes really. Before. And I will show you how to use a feature of OCaml 4.03 that is sadly not well known.&lt;/p&gt;
&lt;p&gt;&amp;#8212;&lt;/p&gt;
&lt;p&gt;First of all, as we do like type and safe programs, we will define what a well formed sudoku solution looks like. And by defining of course I mean declaring some GADTs with enough constraints to ensure that only well correct solutions are valid.&lt;/p&gt;
&lt;p&gt;I assume tha you know the rules of Sudoku and will refrain from infuriating you by explaining it. But we will still need some vocabulary.&lt;/p&gt;
&lt;p&gt;So the aim of sudoku is to fill a &amp;#8216;grid&amp;#8217; with &amp;#8216;symbols&amp;#8217; satisfying some &amp;#8216;row&amp;#8217; &amp;#8216;column&amp;#8217; and &amp;#8216;square&amp;#8217; constraints.&lt;/p&gt;
&lt;p&gt;To make the code examples readable we will stick to 4*4 sudokus. It&amp;#8217;s the smallest size that behaves the same way as 9*9 ones (I considered going for 1*1 ones, but the article ended up being a bit short). Of course everything would still apply to any n^2*n^2 sized one.&lt;/p&gt;
&lt;p&gt;So let&amp;#8217;s start digging in some types. As we will refine them along the way, I will leave some parts to be filled later. This is represented by &amp;#8216;&amp;#8230;&amp;#8217; .&lt;/p&gt;
&lt;p&gt;First there are symbols, just 4 of them befause we reduced the size. Nothing special about that right now.&lt;/p&gt;
&lt;pre class=&quot;brush: fsharp; title: ; notranslate&quot;&gt;
type ... symbol =
| A : ...
| B : ...
| C : ...
| D : ...
&lt;/pre&gt;
&lt;p&gt;And a grid is 16 symbols. To avoid too much visual clutter in the type I just put them linearly. The comment show how it is supposed to be seen in the 2d representation of the grid:&lt;/p&gt;
&lt;pre class=&quot;brush: fsharp; title: ; notranslate&quot;&gt;
(* a b c d
   e f g h
   i j k l
   m n o p *)

type grid =
Grid :
... symbol * (* a *)
... symbol * (* b *)
... symbol * (* c *)
... symbol * (* d *)

... symbol * (* e *)
... symbol * (* f *)
... symbol * (* g *)
... symbol * (* h *)

... symbol * (* i *)
... symbol * (* j *)
... symbol * (* k *)
... symbol * (* l *)

... symbol * (* m *)
... symbol * (* n *)
... symbol * (* o *)
... symbol (* p *)
-&amp;gt; solution
&lt;/pre&gt;
&lt;p&gt;Right now grid is a simple 16-uple of symbols, but we will soon start filling those &amp;#8216;&amp;#8230;&amp;#8217; to forbid any set of symbols that is not a valid solution.&lt;/p&gt;
&lt;p&gt;Each constraint looks like, &amp;#8216;among those 4 positions neither 2 symbols are the same&amp;#8217;. To express that (in fact something equivalent but a bit simpler to state with our types), we will need to name positions. So let&amp;#8217;s introduce some names:&lt;/p&gt;
&lt;pre class=&quot;brush: fsharp; title: ; notranslate&quot;&gt;
type r1 (* the first position among a row constraint *)
type r2 (* the second position among a row constraint *)
type r3
type r4

type c1 (* the first position among a column constraint *)
type c2
type c3
type c4

type s1
type s2
type s3
type s4

type ('row, 'column, 'square) position
&lt;/pre&gt;
&lt;p&gt;On the 2d grid this is how the various positions will be mapped.&lt;/p&gt;
&lt;pre class=&quot;brush: plain; title: ; notranslate&quot;&gt;
r1 r2 r3 r4
r1 r2 r3 r4
r1 r2 r3 r4
r1 r2 r3 r4

c1 c1 c1 c1
c2 c2 c2 c2
c3 c3 c3 c3
c4 c4 c4 c4

s1 s2 s1 s2
s3 s4 s3 s4
s1 s2 s1 s2
s3 s4 s4 s4
&lt;/pre&gt;
&lt;p&gt;For instance, the position g, in the 2nd row, 3rd column, will at the 3rd position in its row constraint, 2nd in its column constraint, and 3rd in its square constraint:&lt;/p&gt;
&lt;pre class=&quot;brush: fsharp; title: ; notranslate&quot;&gt;
type g = (r3, c2, s3) position
&lt;/pre&gt;
&lt;p&gt;We could have declare a single constraint position type, but this is slightly more readable. than:&lt;/p&gt;
&lt;pre class=&quot;brush: fsharp; title: ; notranslate&quot;&gt;
type g = (p3, p2, p3) position
&lt;/pre&gt;
&lt;p&gt;The position type is phantom, we could have provided a representation, but since no value of this type will ever be created, it&amp;#8217;s less confusing to state it that way.&lt;/p&gt;
&lt;pre class=&quot;brush: fsharp; title: ; notranslate&quot;&gt;
type a = (r1, c1, s1) position
type b = (r2, c1, s2) position
type c = (r3, c1, s1) position
type d = (r4, c1, s2) position

type e = (r1, c2, s3) position
type f = (r2, c2, s4) position
type g = (r3, c2, s3) position
type h = (r4, c2, s4) position

type i = (r1, c3, s1) position
type j = (r2, c3, s2) position
type k = (r3, c3, s1) position
type r = (r4, c3, s2) position

type m = (r1, c4, s3) position
type n = (r2, c4, s4) position
type o = (r3, c4, s3) position
type p = (r4, c4, s4) position
&lt;/pre&gt;
&lt;p&gt;It is now possible to state for each symbol in which position it is, so we will start filling a bit those types.&lt;/p&gt;
&lt;pre class=&quot;brush: fsharp; title: ; notranslate&quot;&gt;
type ('position, ...) symbol =
| A : (('r, 'c, 's) position, ...) symbol
| B : (('r, 'c, 's) position, ...) symbol
| C : (('r, 'c, 's) position, ...) symbol
| D : (('r, 'c, 's) position, ...) symbol
&lt;/pre&gt;
&lt;p&gt;This means that a symbol value is then associated to a single position in each constraint. We will need to state that in the grid type too:&lt;/p&gt;
&lt;pre class=&quot;brush: fsharp; title: ; notranslate&quot;&gt;
type grid =
Grid :
(a, ...) symbol * (* a *)
(b, ...) symbol * (* b *)
(c, ...) symbol * (* c *)
(d, ...) symbol * (* d *)

(e, ...) symbol * (* e *)
(f, ...) symbol * (* f *)
(g, ...) symbol * (* g *)
(h, ...) symbol * (* h *)

(i, ...) symbol * (* i *)
(j, ...) symbol * (* j *)
(k, ...) symbol * (* k *)
(l, ...) symbol * (* l *)

(m, ...) symbol * (* m *)
(n, ...) symbol * (* n *)
(o, ...) symbol * (* o *)
(p, ...) symbol (* p *)
-&amp;gt; solution
&lt;/pre&gt;
&lt;p&gt;We just need to forbid a symbol to appear in two different positions of a given row/column/square to prevent invalid solutions.&lt;/p&gt;
&lt;pre class=&quot;brush: fsharp; title: ; notranslate&quot;&gt;
type 'fields row constraint 'fields = &amp;lt; a : 'a; b : 'b; c : 'c; d : 'd &amp;gt;
type 'fields column constraint 'fields = &amp;lt; a : 'a; b : 'b; c : 'c; d : 'd &amp;gt;
type 'fields square constraint 'fields = &amp;lt; a : 'a; b : 'b; c : 'c; d : 'd &amp;gt;
&lt;/pre&gt;
&lt;p&gt;Those types represent the statement &amp;#8216;in this line/column/square, the symbol a is at the position &amp;#8216;a, the symbol b is at the position &amp;#8216;b, &amp;#8230;&amp;#8217;&lt;/p&gt;
&lt;p&gt;For instance, the row &amp;#8216;A D B C&amp;#8217; will be represented by&lt;/p&gt;
&lt;pre class=&quot;brush: fsharp; title: ; notranslate&quot;&gt;
&amp;lt; a : l1; b : l3; c : l4; d : l2 &amp;gt; row
&lt;/pre&gt;
&lt;p&gt;Which reads: &amp;#8216;The symbol A is in first position, B in third position, C in fourth, and D in second&amp;#8217;&lt;/p&gt;
&lt;p&gt;The object type is used to make things a bit lighter later and allow to state names.&lt;/p&gt;
&lt;p&gt;Now the symbols can be a bit more annotated:&lt;/p&gt;
&lt;pre class=&quot;brush: fsharp; title: ; notranslate&quot;&gt;
type ('position, 'row, 'column, 'square) symbol =
| A : (('r, 'c, 's) position,
&amp;lt; a : 'r; .. &amp;gt; row,
&amp;lt; a : 'c; .. &amp;gt; column,
&amp;lt; a : 's; .. &amp;gt; square)
symbol

| B : (('r, 'c, 's) position,
&amp;lt; b : 'r; .. &amp;gt; row,
&amp;lt; b : 'c; .. &amp;gt; column,
&amp;lt; b : 's; .. &amp;gt; square)
symbol

| C : (('r, 'c, 's) position,
&amp;lt; c : 'r; .. &amp;gt; row,
&amp;lt; c : 'c; .. &amp;gt; column,
&amp;lt; c : 's; .. &amp;gt; square)
symbol

| D : (('r, 'c, 's) position,
&amp;lt; d : 'r; .. &amp;gt; row,
&amp;lt; d : 'c; .. &amp;gt; column,
&amp;lt; d : 's; .. &amp;gt; square)
symbol
&lt;/pre&gt;
&lt;p&gt;Notice that &amp;#8216;..&amp;#8217; is not &amp;#8216;&amp;#8230;&amp;#8217;. Those dots are really part of the OCaml syntax: it means &amp;#8216;put whatever you want here, I don&amp;#8217;t care&amp;#8217;. There is nothing more to add to this type.&lt;/p&gt;
&lt;p&gt;This type declaration reports the position information. Using the same variable name &amp;#8216;r in the position and in the row constraint parameter for instance means that both fields will have the same type.&lt;/p&gt;
&lt;p&gt;For instance, a symbol &amp;#8216;B&amp;#8217; in position &amp;#8216;g&amp;#8217; would be in the 3rd position of its row, 2nd position of its column , and 3rd position of its square:&lt;/p&gt;
&lt;pre class=&quot;brush: fsharp; title: ; notranslate&quot;&gt;
# let v : (g, _, _, _) symbol = B;;
val v :
(g, &amp;lt; b : r3 &amp;gt; row,
    &amp;lt; b : c2 &amp;gt; column,
    &amp;lt; b : s3 &amp;gt; square)
symbol = B
&lt;/pre&gt;
&lt;p&gt;Those types constraints ensure that this is correctly reported.&lt;/p&gt;
&lt;p&gt;The real output of the type checker is a bit more verbose, but I remove the irrelevant part:&lt;/p&gt;
&lt;pre class=&quot;brush: fsharp; title: ; notranslate&quot;&gt;
val v :
(g, &amp;lt; a : 'a; b : r3; c : 'b; d : 'c &amp;gt; row,
    &amp;lt; a : 'd; b : c2; c : 'e; d : 'f &amp;gt; column,
    &amp;lt; a : 'g; b : s3; c : 'h; d : 'i &amp;gt; square)
symbol = B
&lt;/pre&gt;
&lt;p&gt;We are now quite close from a completely constrained type. We just need to say that the various symbols from the same row/line/column constraint have the same type:&lt;/p&gt;
&lt;pre class=&quot;brush: fsharp; title: ; notranslate&quot;&gt;
type grid =
Grid :
(a, 'row1, 'column1, 'square1) symbol *
(b, 'row1, 'column2, 'square1) symbol *
(c, 'row1, 'column3, 'square2) symbol *
(d, 'row1, 'column4, 'square2) symbol *

(e, 'row2, 'column1, 'square1) symbol *
(f, 'row2, 'column2, 'square1) symbol *
(g, 'row2, 'column3, 'square2) symbol *
(h, 'row2, 'column4, 'square2) symbol *

(i, 'row3, 'column1, 'square3) symbol *
(j, 'row3, 'column2, 'square3) symbol *
(k, 'row3, 'column3, 'square4) symbol *
(l, 'row3, 'column4, 'square4) symbol *

(m, 'row4, 'column1, 'square3) symbol *
(n, 'row4, 'column2, 'square3) symbol *
(o, 'row4, 'column3, 'square4) symbol *
(p, 'row4, 'column4, 'square4) symbol *
&lt;/pre&gt;
&lt;p&gt;That is two symbols in the same row/column/square will share the same &amp;#8216;row/&amp;#8217;symbol/&amp;#8217;square type. For any couple of symbols in say, a row, they must agree on that type, hence, on the position of every symbol.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s look at the &amp;#8216;A&amp;#8217; symbol for the &amp;#8216;a&amp;#8217; and &amp;#8216;c&amp;#8217; position for instance. Both share the same &amp;#8216;row1 type variable. There are two cases. Either both are &amp;#8216;A&amp;#8217;s ore one is not.&lt;/p&gt;
&lt;p&gt;* If one symbol is not a &amp;#8216;A&amp;#8217;, let&amp;#8217;s say those are &amp;#8216;C&amp;#8217; and &amp;#8216;A&amp;#8217; symbols. Their row type (pun almost intended) will be respectively &lt;code&gt;&amp;lt; c : r1; .. &amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt; a : r3; .. &amp;gt;&lt;/code&gt;. Meaning that &amp;#8216;C&amp;#8217; does not care about the position of &amp;#8216;A&amp;#8217; and conversly. Those types are compatible. No problem here.&lt;/p&gt;
&lt;p&gt;* If both are &amp;#8216;A&amp;#8217;s then something else happens. Their row types will be &lt;code&gt;&amp;lt; a : r1; .. &amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt; a : r3; .. &amp;gt;&lt;/code&gt; which is certainly not compatible since r1 and r3 are not compatible. This will be rejected.&lt;/p&gt;
&lt;p&gt;Now we have a grid type that checks the sudoku constraints !&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s try it.&lt;/p&gt;
&lt;pre class=&quot;brush: fsharp; title: ; notranslate&quot;&gt;
let ok =
Grid
(A, B, C, D,
C, D, A, B,

D, A, B, C,
B, C, D, A)

val ok : grid = Grid (A, B, C, D, C, D, A, B, D, A, B, C, B, C, D, A)

let not_ok =
Grid
(A, B, C, D,
C, D, A, B,

D, A, B, C,
B, C, A, D)

B, C, A, D);;
^
Error: This expression has type
(o, &amp;lt; a : r3; b : r1; c : r2; d : 'a &amp;gt; row,
    &amp;lt; a : c4; b : 'b; c : 'c; d : 'd &amp;gt; column,
    &amp;lt; a : s3; b : 'e; c : 'f; d : 'g &amp;gt; square)
  symbol
but an expression was expected of type
(o, &amp;lt; a : r3; b : r1; c : r2; d : 'a &amp;gt; row,
    &amp;lt; a : c2; b : c3; c : c1; d : 'h &amp;gt; column,
    &amp;lt; a : 'i; b : s1; c : s2; d : 'j &amp;gt; square)
  symbol
Types for method a are incompatible
&lt;/pre&gt;
&lt;p&gt;What it is trying to say is that &amp;#8216;A&amp;#8217; is both at position &amp;#8216;2&amp;#8217; and &amp;#8216;4&amp;#8217; of its column. Well it seems to work.&lt;/p&gt;
&lt;h3&gt;Solving it&lt;/h3&gt;
&lt;p&gt;But we are not only interested in checking that a solution is correct, we want to find them !&lt;/p&gt;
&lt;p&gt;But with &amp;#8216;one weird trick&amp;#8217; we will magically transform it into a solver, namely the &lt;code&gt;-&amp;gt; .&lt;/code&gt; syntax. It was introduced in OCaml 4.03 for some other &lt;a href=&quot;http://caml.inria.fr/pub/docs/manual-ocaml/extn.html#sec241&quot;&gt;purpose&lt;/a&gt;. But we will now use its hidden power !&lt;/p&gt;
&lt;p&gt;This is the right hand side of a pattern. It explicitely states that a pattern is unreachable. For instance&lt;/p&gt;
&lt;pre class=&quot;brush: fsharp; title: ; notranslate&quot;&gt;
type _ t =
  | Int : int -&amp;gt; int t
  | Float : float -&amp;gt; float t

let add (type v) (a : v t) (b : v t) : v t =
  match a, b with
  | Int a, Int b -&amp;gt; Int (a + b)
  | Float a, Float b -&amp;gt; Float (a +. b)
  | _ -&amp;gt; .
&lt;/pre&gt;
&lt;p&gt;By writing it here you state that you don&amp;#8217;t expect any other pattern to verify the type constraints. This is effectively the case here. In general you won&amp;#8217;t need this as the exhaustivity checker will see it. But in some intricate situations it will need some hints to work a bit more. For more information see &lt;a href=&quot;http://export.arxiv.org/abs/1702.02281&quot;&gt;Jacques Garrigue / Le Normand&lt;/a&gt; &lt;a href=&quot;http://export.arxiv.org/abs/1702.02281&quot;&gt;article&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This may be a bit obscure, but this is what we now need. Indeed, we can ask the exhaustivity checker if there exist a value verifying the pattern and the type constraints. For instance to solve a problem, we ask the compiler to check if there is any value verifying a partial solution encoded as a pattern.&lt;/p&gt;
&lt;pre&gt; A _ C _
 _ D _ B
 _ A D _
 D _ B _&lt;/pre&gt;
&lt;pre class=&quot;brush: fsharp; title: ; notranslate&quot;&gt;
let test x =
match x with
| Grid
  (A, _, C, _,
   _, D, _, B,

   _, A, D, _,
   D, _, B, _) -&amp;gt; .
| _ -&amp;gt; ()

Error: This match case could not be refuted.
Here is an example of a value that would reach it:
Grid (A, B, C, D, C, D, A, B, B, A, D, C, D, C, B, A)
&lt;/pre&gt;
&lt;p&gt;The checker tells us that there is a solution verifying those constraints, and provides it.&lt;/p&gt;
&lt;p&gt;If there were no solution, there would have been no error.&lt;/p&gt;
&lt;pre class=&quot;brush: fsharp; title: ; notranslate&quot;&gt;
let test x =
match x with
| Grid
  (A, B, C, _,
   _, _, _, D,

   _, _, _, _,
   _, _, _, _) -&amp;gt; .
| _ -&amp;gt; ()

val test : grid -&amp;gt; unit =
&lt;/pre&gt;
&lt;p&gt;And that&amp;#8217;s it !&lt;/p&gt;
&lt;h3&gt;Wrapping it up&lt;/h3&gt;
&lt;p&gt;Of course that&amp;#8217;s a bit cheating since the program is not executable, but who cares really ?&lt;br /&gt;
If you want to use it, I made a small (ugly) &lt;a href=&quot;https://gist.github.com/chambart/15b18770d2368cc703a32f18fe12d179&quot;&gt;script&lt;/a&gt; generating those types. You can try it on bigger problems, but in fact it is a bit exponential. So you shouldn&amp;#8217;t really expect an answer too soon.&lt;/p&gt;
</content><category term="Blog"/><id>http://www.ocamlpro.com/?p=624</id><title type="text">EzSudoku</title><updated>2017-04-11T13:36:16-00:00</updated><author><name>OCamlPro</name></author></entry><entry><source><updated>2017-05-09T12:00:00-00:00</updated><link title="OCaml Weekly News" type="text/html" href="http://alan.petitepomme.net/cwn/" rel="related"/><link title="OCaml Weekly News" type="application/rss+xml" href="http://alan.petitepomme.net/cwn/cwn.rss" rel="self"/><id>http://alan.petitepomme.net/cwn/</id><title type="text">OCaml Weekly News</title><author><name>OCaml Weekly News</name></author></source><link href="http://alan.petitepomme.net/cwn/2017.04.11.html" rel="alternate"/><content xml:base="http://alan.petitepomme.net/cwn/cwn.rss" type="html">&lt;ol&gt;&lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.04.11.html#1&gt;REST APIs&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.04.11.html#2&gt;error messages in multiple languages ?&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.04.11.html#3&gt;Compile and link program who use Toploop&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.04.11.html#4&gt;Ocaml Github Pull Requests&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.04.11.html#5&gt;Other OCaml News&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;</content><id>http://alan.petitepomme.net/cwn/2017.04.11.html</id><title type="text">Weekly News</title><updated>2017-04-11T12:00:00-00:00</updated><author><name>OCaml Weekly News</name></author></entry><entry><source><updated>2017-04-05T17:30:30-00:00</updated><link title="Frama-C RSS News" type="text/html" href="http://frama-c.com/" rel="related"/><link title="Frama-C RSS News" type="application/rss+xml" href="http://frama-c.com/rss.xml" rel="self"/><id>http://frama-c.com/</id><title type="text">Frama-C RSS News</title><author><name>Frama-C</name></author></source><link href="http://frama-c.com/index.html" rel="alternate"/><id>http://frama-c.com/index.html#6f462e1ff2f08db53e6cbae0d3fa88a4</id><title type="text">Version 0.0.2 of the Frama-Clang plugin plugin is available for download.</title><updated>2017-04-05T17:30:30-00:00</updated><author><name>Frama-C</name></author></entry><entry><source><updated>2017-05-09T12:00:00-00:00</updated><link title="OCaml Weekly News" type="text/html" href="http://alan.petitepomme.net/cwn/" rel="related"/><link title="OCaml Weekly News" type="application/rss+xml" href="http://alan.petitepomme.net/cwn/cwn.rss" rel="self"/><id>http://alan.petitepomme.net/cwn/</id><title type="text">OCaml Weekly News</title><author><name>OCaml Weekly News</name></author></source><link href="http://alan.petitepomme.net/cwn/2017.04.04.html" rel="alternate"/><content xml:base="http://alan.petitepomme.net/cwn/cwn.rss" type="html">&lt;ol&gt;&lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.04.04.html#1&gt;first release of minivpt: a minimalist vantage-point tree implementation in OCaml&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.04.04.html#2&gt;CFP: ML Family Workshop 2017&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.04.04.html#3&gt;OCaml workshop 2017: call for presentations&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.04.04.html#4&gt;Ocaml Github Pull Requests&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.04.04.html#5&gt;Other OCaml News&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;</content><id>http://alan.petitepomme.net/cwn/2017.04.04.html</id><title type="text">Weekly News</title><updated>2017-04-04T12:00:00-00:00</updated><author><name>OCaml Weekly News</name></author></entry><entry><source><updated>2017-04-17T00:00:00-00:00</updated><link title="Drup's thingies" type="text/html" href="https://drup.github.io/" rel="related"/><link title="Drup's thingies" type="application/rss+xml" href="http://drup.github.io/feed-ocaml.xml" rel="self"/><id>https://drup.github.io/</id><title type="text">Drup's thingies</title><author><name>Gabriel Radanne</name></author></source><link href="https://drup.github.io/2017/04/01/pumping/" rel="alternate"/><content xml:base="http://drup.github.io/feed-ocaml.xml" type="html">
        
        
        
        &lt;p&gt;I’m happy to announce the release of &lt;a href=&quot;https://github.com/Drup/pumping&quot;&gt;Pumping&lt;/a&gt;,
a library to leverage the OCaml type system to recognize regular languages.&lt;/p&gt;


        
        </content><id>https://drup.github.io/2017/04/01/pumping/</id><title type="text">Ann: Pumping | Drup's thingies</title><updated>2017-04-01T00:00:00-00:00</updated><author><name>Gabriel Radanne</name></author></entry><entry><source><updated>2017-05-11T20:18:34-00:00</updated><subtitle xml:base="http://blog.shaynefletcher.org/feeds/posts/default/-/OCaml" type="html">&quot;Hooked&quot; on programming</subtitle><link type="application/atom+xml" href="http://www.blogger.com/feeds/5012565255225108517/posts/default/-/OCaml/-/OCaml?start-index=26&amp;max-results=25" rel="next"/><link href="http://pubsubhubbub.appspot.com/" rel="hub"/><link type="text/html" href="http://blog.shaynefletcher.org/search/label/OCaml" rel="alternate"/><link type="application/atom+xml" href="http://www.blogger.com/feeds/5012565255225108517/posts/default/-/OCaml" rel="self"/><link type="application/atom+xml" href="http://blog.shaynefletcher.org/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed"/><generator uri="http://www.blogger.com" version="7.00">Blogger</generator><category term="recursive descent"/><category term="ppx"/><category term="ppf"/><category term="left recursion"/><category term="grammars"/><category term="balanced binary search trees"/><category term="Windows 8.1"/><category term="Windows 7"/><category term="Variance"/><category term="Universal type"/><category term="Universal Gas Constant"/><category term="Tail recursion"/><category term="Subtyping"/><category term="Stack overflow"/><category term="Sorting"/><category term="Simulation"/><category term="Sieve of Eratosthenes"/><category term="Science"/><category term="Rings"/><category term="Recursion"/><category term="Priority queue"/><category term="Pretty-printing"/><category term="Poof"/><category term="Polynomials"/><category term="Polymorphic variants"/><category term="Permutation"/><category term="Pascal"/><category term="Numerical analysis"/><category term="Monty Hall"/><category term="Modules"/><category term="List comprehensions"/><category term="Leftist heap"/><category term="Labeled arguments"/><category term="Ideal Gas Law"/><category term="Horner's rule"/><category term="Functors"/><category term="Financial Modeling in Python"/><category term="Exponentiation by squaring"/><category term="Compression"/><category term="Combination"/><category term="Church-Turing thesis"/><category term="Church numerals"/><category term="Cartesian product"/><category term="Algorithmic complexity"/><category term="64-bit"/><category term="type-classes"/><category term="ocamlyacc"/><category term="ocamllex"/><category term="Y Combinator"/><category term="Taylor polynomials"/><category term="Streams"/><category term="Recursive lists"/><category term="Prolog"/><category term="Monads"/><category term="Dimensional analysis"/><category term="Algebra"/><category term="Regular expressions"/><category term="Powerset"/><category term="Statistics"/><category term="Lexical analysis"/><category term="Haskell"/><category term="Parsing"/><category term="data structures"/><category term="Symbolic computation"/><category term="Lambda calculus"/><category term="Felix"/><category term="Boost"/><category term="Python"/><category term="Algorithms"/><category term="C++"/><category term="Functional programming"/><category term="OCaml"/><id>tag:blogger.com,1999:blog-5012565255225108517</id><title type="text">Shayne Fletcher</title><author><email>noreply@blogger.com</email><name>Shayne Fletcher</name></author></source><published>2017-03-30T19:58:00-00:00</published><link title="Dealing with source code locations (in lexical and syntax analysis)" type="text/html" href="http://blog.shaynefletcher.org/2017/03/dealing-with-source-code-locations-in.html" rel="alternate"/><link type="application/atom+xml" href="http://www.blogger.com/feeds/5012565255225108517/posts/default/7147619713106104281" rel="self"/><link type="application/atom+xml" href="http://www.blogger.com/feeds/5012565255225108517/posts/default/7147619713106104281" rel="edit"/><content xml:base="http://blog.shaynefletcher.org/feeds/posts/default/-/OCaml" type="html">&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01//EN&quot;           &quot;http://www.w3.org/TR/html4/strict.dtd&quot;&gt;&lt;html&gt;  &lt;head&gt;    &lt;title&gt;Locations&lt;/title&gt;  &lt;/head&gt;  &lt;body&gt;     &lt;p&gt;Writing compilers and interpreters requires rigorous management     of source code locations harvested during syntax analysis and     associated error handling mechanisms that involve reporting those     locations along with details of errors they associate to.     &lt;/p&gt;     &lt;p&gt;    This article does a &quot;deep dive&quot; into the the &lt;code&gt;Location&lt;/code&gt;    module of the OCaml compiler. The original source can be found in     the &lt;code&gt;ocaml/parsing&lt;/code&gt; directory of an OCaml distribution     (copyright &lt;a href=&quot;https://en.wikipedia.org/wiki/Xavier_Leroy&quot;&gt;Xavier     Leroy&lt;/a&gt;).     &lt;/p&gt;     &lt;p&gt;    &lt;code&gt;Location&lt;/code&gt; is a &lt;font size=&quot;5&quot;&gt;masterclass&lt;/font&gt; in     using the standard library &lt;code&gt;Format&lt;/code&gt; module. If you have     had difficulties understanding &lt;code&gt;Format&lt;/code&gt; and what it     provides the OCaml programmer, then this is for     you. Furthermore, &lt;code&gt;Location&lt;/code&gt; contains invaluable idioms     for error reporting &amp; exception handling. Learn them here to be     able to apply them in your own programs.     &lt;/p&gt;     &lt;h2&gt;Describing locations&lt;/h2&gt;    &lt;p&gt;    A location corresponds to a range of characters in a source file.     &lt;code&gt;Location&lt;/code&gt; defines this type and a suite of functions     for the production of location values.     &lt;pre&gt;&lt;br /&gt;type t = { &lt;br /&gt;  loc_start : Lexing.position;&lt;br /&gt;  loc_end : Lexing.position;&lt;br /&gt;  loc_ghost : bool&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;val none : t&lt;br /&gt;val in_file : string &amp;rarr; t&lt;br /&gt;val init : Lexing.lexbuf &amp;rarr; string &amp;rarr; unit&lt;br /&gt;val curr : Lexing.lexbuf &amp;rarr; t&lt;br /&gt;&lt;br /&gt;val symbol_rloc : unit &amp;rarr; t&lt;br /&gt;val symbol_gloc : unit &amp;rarr; t&lt;br /&gt;val rhs_loc : int &amp;rarr; t&lt;br /&gt;&lt;br /&gt;type 'a loc = { &lt;br /&gt;  txt : 'a;&lt;br /&gt;  loc : t; &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;val mkloc : 'a &amp;rarr; t &amp;rarr; 'a loc&lt;br /&gt;val mknoloc : 'a &amp;rarr; 'a loc&lt;br /&gt;    &lt;/pre&gt;    &lt;/p&gt;     &lt;p&gt;    A value of the (standard library)     type &lt;code&gt;Lexing.position&lt;/code&gt; describes a point in a source     file.     &lt;pre&gt;&lt;br /&gt;    type position = {&lt;br /&gt;      pos_fname : string;&lt;br /&gt;      pos_lnum : int;&lt;br /&gt;      pos_bol : int;&lt;br /&gt;      pos_cnum : int&lt;br /&gt;    }&lt;br /&gt;    &lt;/pre&gt;    The fields of this record have the following meanings:     &lt;ul&gt;    &lt;li&gt;&lt;code&gt;pos_fname&lt;/code&gt; is the file name&lt;/li&gt;    &lt;li&gt;&lt;code&gt;pos_lnum&lt;/code&gt; is the line number&lt;/li&gt;    &lt;li&gt;&lt;code&gt;pos_bol&lt;/code&gt; is the offset of the beginning of the     line (the number of characters between the beginning of the lexbuf     and the beginning of the line)&lt;/li&gt;    &lt;li&gt;&lt;code&gt;pos_cnum&lt;/code&gt; is the offset of the position (number of     characters between the beginning of the lexbuf (details below) and     the position)&lt;/li&gt;    &lt;/ul&gt;    The difference between &lt;code&gt;pos_cnum&lt;/code&gt;    and &lt;code&gt;pos_bol&lt;/code&gt; is the character offset within the line     (i.e. the column number, assuming each character is one column     wide).     &lt;/p&gt;     &lt;p&gt;    A location in a source file is defined by two positions : where     the location starts and where the location ends.     &lt;pre&gt;&lt;br /&gt;type t = {&lt;br /&gt;  loc_start : position;&lt;br /&gt;  loc_end : position;&lt;br /&gt;  loc_ghost : bool&lt;br /&gt;}&lt;br /&gt;    &lt;/pre&gt;    The third field &lt;code&gt;loc_ghost&lt;/code&gt; is used to disambiguate     locations that do not appear explicitly in the source file. A     location will &lt;em&gt;not&lt;/em&gt; be marked as ghost if it contains a     piece of code that is syntactically valid and corresponds to an     AST node and will be marked as a ghost location otherwise.     &lt;/p&gt;     &lt;p&gt;    There is a specific value denoting a null position. It is     called &lt;code&gt;none&lt;/code&gt; and it is defined by the     function &lt;code&gt;in_file&lt;/code&gt;.     &lt;pre&gt;&lt;br /&gt;let in_file (name : string) : t =&lt;br /&gt;  let loc : position = {&lt;br /&gt;    pos_fname = name; (*The name of the file*)&lt;br /&gt;    pos_lnum = 1; (*The line number of the position*)&lt;br /&gt;    pos_bol = 0; (*Offset from the beginning of the lexbuf of the line*)&lt;br /&gt;    pos_cnum = -1; (*Offset of the position from the beginning of the lexbuf*)&lt;br /&gt;  } in&lt;br /&gt;  { loc_start = loc; loc_end = loc; loc_ghost = true }&lt;br /&gt;&lt;br /&gt;let none : t = in_file &quot;_none_&quot;&lt;br /&gt;    &lt;/pre&gt;    &lt;/p&gt;     &lt;p&gt;&lt;code&gt;Lexing.lexbuf&lt;/code&gt; is the (standard library) type of     lexer buffers. A lexer buffer is the argument passed to the     scanning functions defined by generated scanners (lexical     analyzers). The lexer buffer holds the current state of the     scanner plus a function to refill the buffer from the input.     &lt;pre&gt;&lt;br /&gt;type lexbuf = {&lt;br /&gt;  refill_buff : lexbuf &amp;rarr; unit;&lt;br /&gt;  mutable lex_buffer : bytes;&lt;br /&gt;  mutable lex_buffer_len : int;&lt;br /&gt;  mutable lex_abs_pos : int;&lt;br /&gt;  mutable lex_start_pos : int;&lt;br /&gt;  mutable lex_curr_pos : int;&lt;br /&gt;  mutable lex_last_pos : int;&lt;br /&gt;  mutable lex_last_action : int;&lt;br /&gt;  mutable lex_eof_reached : bool;&lt;br /&gt;  mutable lex_mem : int array;&lt;br /&gt;  mutable lex_start_p : position;&lt;br /&gt;  mutable lex_curr_p : position;&lt;br /&gt;}&lt;br /&gt;    &lt;/pre&gt;    At each token, the lexing engine will copy &lt;code&gt;lex_curr_p&lt;/code&gt;    to &lt;code&gt;lex_start_p&lt;/code&gt; then change the &lt;code&gt;pos_cnum&lt;/code&gt;    field of &lt;code&gt;lex_curr_p&lt;/code&gt; by updating it with the number of     characters read since the start of the &lt;code&gt;lexbuf&lt;/code&gt;. The     other fields are left unchanged by the the lexing engine. In order     to keep them accurate, they must be initialized before the first     use of the lexbuf and updated by the relevant lexer actions.     &lt;pre&gt;&lt;br /&gt;(*Set the file name and line number of the [lexbuf] to be the start&lt;br /&gt;   of the named file*)&lt;br /&gt;let init (lexbuf : Lexing.lexbuf) (fname : string) : unit =&lt;br /&gt;  let open Lexing in&lt;br /&gt;  lexbuf.lex_curr_p &amp;lt;- {&lt;br /&gt;    pos_fname = fname;&lt;br /&gt;    pos_lnum = 1;&lt;br /&gt;    pos_bol = 0;&lt;br /&gt;    pos_cnum = 0;&lt;br /&gt;  }&lt;br /&gt;    &lt;/pre&gt;    The location of the current token in a lexbuf is computed by the     function &lt;code&gt;curr&lt;/code&gt;.     &lt;pre&gt;&lt;br /&gt;(*Get the location of the current token from the [lexbuf]*)&lt;br /&gt;let curr (lexbuf : Lexing.lexbuf) : t = &lt;br /&gt;  let open Lexing in {&lt;br /&gt;    loc_start = lexbuf.lex_start_p;&lt;br /&gt;    loc_end = lexbuf.lex_curr_p;&lt;br /&gt;    loc_ghost = false;&lt;br /&gt;  }&lt;br /&gt;    &lt;/pre&gt;    &lt;/p&gt;     &lt;p&gt;    &lt;code&gt;Parsing&lt;/code&gt; is the run-time library for parsers generated     by &lt;code&gt;ocamlyacc&lt;/code&gt;. The functions &lt;code&gt;symbol_start&lt;/code&gt;    and &lt;code&gt;symbol_end&lt;/code&gt; are to be called in the action part of     a grammar rule (only). They return the offset of the string that     matches the left-hand-side of the rule : &lt;code&gt;symbol_start&lt;/code&gt;    returns the offset of the first character; &lt;code&gt;symbol_end&lt;/code&gt;    returns the offset &lt;em&gt;after&lt;/em&gt; the last character. The first     character in a file is at offset 0.     &lt;/p&gt;         &lt;p&gt;    &lt;code&gt;symbol_start_pos&lt;/code&gt; and &lt;code&gt;symbol_end_pos&lt;/code&gt; are     like &lt;code&gt;symbol_start&lt;/code&gt; and &lt;code&gt;symbol_end&lt;/code&gt; but     return &lt;code&gt;Lexing.position&lt;/code&gt; values instead of offsets.     &lt;pre&gt;&lt;br /&gt;(*Compute the span of the left-hand-side of the matched rule in the&lt;br /&gt;   program source*)&lt;br /&gt;let symbol_rloc () : t = {&lt;br /&gt;  loc_start = Parsing.symbol_start_pos ();&lt;br /&gt;  loc_end = Parsing.symbol_end_pos ();&lt;br /&gt;  loc_ghost = false&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;(*Same as [symbol_rloc] but designates the span as a ghost range*)&lt;br /&gt;let symbol_gloc () : t =  { &lt;br /&gt;  loc_start = Parsing.symbol_start_pos ();&lt;br /&gt;  loc_end = Parsing.symbol_end_pos ();&lt;br /&gt;  loc_ghost = true&lt;br /&gt;}&lt;br /&gt;    &lt;/pre&gt;    &lt;/p&gt;     &lt;p&gt;     The &lt;code&gt;Parsing&lt;/code&gt; functions &lt;code&gt;rhs_start&lt;/code&gt;     and &lt;code&gt;rhs_end&lt;/code&gt; are the same      as &lt;code&gt;symbol_start&lt;/code&gt; and &lt;code&gt;symbol_end&lt;/code&gt; but      return the offset of the string matching the &lt;code&gt;n&lt;/code&gt;-th      item on the right-hand-side of the rule where &lt;code&gt;n&lt;/code&gt; is      the integer parameter to &lt;code&gt;rhs_start&lt;/code&gt;     and &lt;code&gt;rhs_end&lt;/code&gt;. &lt;code&gt;n&lt;/code&gt; is 1 for the leftmost      item. &lt;code&gt;rhs_start_pos&lt;/code&gt; and &lt;code&gt;rhs_end_pos&lt;/code&gt;     return a position instead of an offset.      &lt;pre&gt;&lt;br /&gt;(*Compute the span of the [n]th item of the right-hand-side of the&lt;br /&gt;   matched rule*)&lt;br /&gt;let rhs_loc n = {&lt;br /&gt;  loc_start = Parsing.rhs_start_pos n;&lt;br /&gt;  loc_end = Parsing.rhs_end_pos n;&lt;br /&gt;  loc_ghost = false;&lt;br /&gt;}&lt;br /&gt;     &lt;/pre&gt;    &lt;/p&gt;     &lt;p&gt;The type &lt;code&gt;'a&lt;/code&gt; loc associates a value with a     location.     &lt;pre&gt;&lt;br /&gt;(*A type for the association of a value with a location*)&lt;br /&gt;type 'a loc = { &lt;br /&gt;  txt : 'a;&lt;br /&gt;  loc : t; &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;(*Create an ['a loc] value from an ['a] value and location*)&lt;br /&gt;let mkloc (txt : 'a) (loc : t) : 'a loc = { txt ; loc }&lt;br /&gt;&lt;br /&gt;(*Create an ['a loc] value bound to the distinguished location called&lt;br /&gt;   [none]*)&lt;br /&gt;let mknoloc (txt : 'a) : 'a loc = mkloc txt none&lt;br /&gt;    &lt;/pre&gt;    &lt;/p&gt;     &lt;h2&gt;Error reporting with locations&lt;/h2&gt;    &lt;p&gt;    &lt;code&gt;Location&lt;/code&gt; has a framework for error reporting across     modules concerned with locations (think lexer, parser,     type-checker, etc).     &lt;pre&gt;&lt;br /&gt;open Format&lt;br /&gt;&lt;br /&gt;type error =&lt;br /&gt;{&lt;br /&gt;  loc : t;&lt;br /&gt;  msg : string;&lt;br /&gt;  sub : error list;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;val error_of_printer : t &amp;rarr;  (formatter &amp;rarr; 'a &amp;rarr; unit) &amp;rarr; 'a &amp;rarr; error&lt;br /&gt;val errorf_prefixed : ?loc : t &amp;rarr; ?sub : error list &amp;rarr; ('a, Format.formatter, unit, error) format4 &amp;rarr; 'a&lt;br /&gt;    &lt;/pre&gt;    So, in the definition of the &lt;code&gt;error&lt;/code&gt;    record, &lt;code&gt;loc&lt;/code&gt; is a location in the source     code, &lt;code&gt;msg&lt;/code&gt; an explanation of the error     and &lt;code&gt;sub&lt;/code&gt; a list of related errors.  We deal here with     the error formatting functions. The utility     function &lt;code&gt;print_error_prefix&lt;/code&gt; simply writes an error     prefix to a formatter.     &lt;pre&gt;&lt;br /&gt;let error_prefix = &quot;Error&quot;&lt;br /&gt;&lt;br /&gt;let warning_prefix = &quot;Warning&quot;&lt;br /&gt;&lt;br /&gt;let print_error_prefix (ppf : formatter) () : unit =&lt;br /&gt;  fprintf ppf &quot;@{&amp;lt;error&amp;gt;%s@}:&quot; error_prefix;&lt;br /&gt;  ()&lt;br /&gt;    &lt;/pre&gt;    The syntax, &quot;&lt;code&gt;@{&amp;lt;error&amp;gt;%s}@&lt;/code&gt;&quot; associates the embedded text     with the named tag &quot;error&quot;.   &lt;/p&gt;   &lt;p&gt;  Next another utility, &lt;code&gt;pp_ksprintf&lt;/code&gt;.   &lt;pre&gt;&lt;br /&gt;let pp_ksprintf &lt;br /&gt;    ?(before : (formatter &amp;rarr; unit) option) &lt;br /&gt;    (k : string &amp;rarr; 'd)&lt;br /&gt;    (fmt : ('a, formatter, unit, 'd) format4) : 'a =&lt;br /&gt;  let buf = Buffer.create 64 in&lt;br /&gt;  let ppf = Format.formatter_of_buffer buf in&lt;br /&gt;  begin match before with&lt;br /&gt;    | None &amp;rarr; ()&lt;br /&gt;    | Some f &amp;rarr; f ppf&lt;br /&gt;  end;&lt;br /&gt;  kfprintf&lt;br /&gt;    (fun (_ : formatter) : 'd &amp;rarr;&lt;br /&gt;      pp_print_flush ppf ();&lt;br /&gt;      let msg = Buffer.contents buf in&lt;br /&gt;      k msg)&lt;br /&gt;    ppf fmt&lt;br /&gt;    &lt;/pre&gt;    It proceeds as follows. A buffer and a formatter over that buffer     is created. When presented with all of the arguments of the format     operations implied by the &lt;code&gt;fmt&lt;/code&gt; argument, if     the &lt;code&gt;before&lt;/code&gt; argument is non-empty, call it on the     formatter. Finally, call &lt;code&gt;kfprintf&lt;/code&gt; (from the standard     library &lt;code&gt;Format&lt;/code&gt; module) which performs the format     operations on the buffer before handing control to a function that     retrieves the contents of the now formatted buffer and passes them     to the user provided continuation &lt;code&gt;k&lt;/code&gt;.     &lt;/p&gt;     &lt;p&gt;With &lt;code&gt;pp_ksprintf&lt;/code&gt; at our disposal, one can write     the function &lt;code&gt;errorf_prefixed&lt;/code&gt;.     &lt;pre&gt;&lt;br /&gt;let errorf_prefixed &lt;br /&gt;    ?(loc:t = none) &lt;br /&gt;    ?(sub : error list = []) &lt;br /&gt;    (fmt : ('a, Format.formatter, unit, error) format4) : 'a =&lt;br /&gt;  let e : 'a =&lt;br /&gt;    pp_ksprintf&lt;br /&gt;      ~before:(fun ppf &amp;rarr; fprintf ppf &quot;%a &quot; print_error_prefix ())&lt;br /&gt;      (fun (msg : string) : error &amp;rarr; {loc; msg; sub})&lt;br /&gt;    fmt&lt;br /&gt;  in e&lt;br /&gt;    &lt;/pre&gt;    &lt;code&gt;errorf_prefixed&lt;/code&gt; computes a function. The function it     computes provides the means to produce &lt;code&gt;error&lt;/code&gt; values     by way of formatting operations to produce the &lt;code&gt;msg&lt;/code&gt;    field of the &lt;code&gt;error&lt;/code&gt; result value. The formatting     operations include prefixing the &lt;code&gt;msg&lt;/code&gt; field with     the &lt;code&gt;error_prefix&lt;/code&gt; string. The type of the arguments of     the computed function unifies with the type     variable &lt;code&gt;'a&lt;/code&gt;. In other words, the type of the computed     function is &lt;code&gt;'a &amp;rarr; error&lt;/code&gt;. For example, the type     of &lt;code&gt;errorf_prefixed &quot;%d %s&quot;&lt;/code&gt; is &lt;code&gt;int &amp;rarr; string &amp;rarr;     error&lt;/code&gt;.     &lt;/p&gt;     &lt;p&gt;    The groundwork laid with &lt;code&gt;errorf_prefixed&lt;/code&gt; above means     a polymorphic function &lt;code&gt;error_of_printer&lt;/code&gt; can now be     produced.     &lt;pre&gt;&lt;br /&gt;let error_of_printer &lt;br /&gt;    (loc : t) &lt;br /&gt;    (printer : formatter &amp;rarr; 'error_t &amp;rarr; unit) &lt;br /&gt;    (x : 'error_t) : error =&lt;br /&gt;  let mk_err : 'error_t &amp;rarr; error = &lt;br /&gt;    errorf_prefixed ~loc &quot;%a@?&quot; printer in&lt;br /&gt;  mk_err x&lt;br /&gt;      &lt;/pre&gt;    The idea is that &lt;code&gt;error_of_printer&lt;/code&gt; is provided a     function that can format a value of type &lt;code&gt;'error&lt;/code&gt;. This     function is composed with &lt;code&gt;errorf_prefixed&lt;/code&gt; thereby     producing a function of type &lt;code&gt;'error &amp;rarr; error&lt;/code&gt;. For     example, we can illustrate how this works by making an error of a     simple integer with code like the following:     &lt;pre&gt;&lt;br /&gt;# error_of_printer none (fun ppf x &amp;rarr; Format.fprintf ppf &quot;Code %d&quot; x) 3;;&lt;br /&gt;- : error =&lt;br /&gt;{loc =&lt;br /&gt;  {loc_start =&lt;br /&gt;    {pos_fname = &quot;_none_&quot;; pos_lnum = 1; pos_bol = 0; pos_cnum = -1};&lt;br /&gt;   loc_end = {pos_fname = &quot;_none_&quot;; pos_lnum = 1; pos_bol = 0; pos_cnum = -1};&lt;br /&gt;   loc_ghost = true};&lt;br /&gt; msg = &quot;Error: Code 3&quot;; sub = []}&lt;br /&gt;    &lt;/pre&gt;    &lt;/p&gt;    &lt;p&gt;So, that's &lt;code&gt;error_of_printer&lt;/code&gt;. The following utility     function is much simpler - it simply writes a given filename to a     formatter.     &lt;pre&gt;&lt;br /&gt;let print_filename (ppf : formatter) (file : string) : unit =&lt;br /&gt;  fprintf ppf &quot;%s&quot; file&lt;br /&gt;    &lt;/pre&gt;    Next, a set of constants for consistent messages that involve     locations and a function to get the file, line and column of a     position.     &lt;pre&gt;&lt;br /&gt;let (msg_file, msg_line, msg_chars, msg_to, msg_colon) =&lt;br /&gt;    (&quot;File \&quot;&quot;,        (*'msg file'*)&lt;br /&gt;     &quot;\&quot;, line &quot;,      (*'msg line'*)&lt;br /&gt;     &quot;, characters &quot;,  (*'msg chars'*)&lt;br /&gt;     &quot;-&quot;,              (*'msg to'*)&lt;br /&gt;     &quot;:&quot;)              (*'msg colon'*)&lt;br /&gt;&lt;br /&gt;let get_pos_info pos = (pos.pos_fname, pos.pos_lnum, pos.pos_cnum - pos.pos_bol)&lt;br /&gt;    &lt;/pre&gt;    Making use of the above we have now &lt;code&gt;print_loc&lt;/code&gt; : a     function to print a location on a formatter in terms of file, line     and character numbers.     &lt;pre&gt;&lt;br /&gt;let print_loc (ppf : formatter) (loc : t) : unit  =&lt;br /&gt;  let (file, line, startchar) = get_pos_info loc.loc_start in&lt;br /&gt;  let endchar = loc.loc_end.pos_cnum - loc.loc_start.pos_cnum + startchar in&lt;br /&gt;  if file = &quot;//toplevel//&quot; then&lt;br /&gt;    fprintf ppf &quot;Characters %i-%i&quot;&lt;br /&gt;      loc.loc_start.pos_cnum loc.loc_end.pos_cnum&lt;br /&gt;  else begin&lt;br /&gt;    fprintf ppf &quot;%s@{&amp;lt;loc&amp;gt;%a%s%i&quot; msg_file print_filename file msg_line line;&lt;br /&gt;    if startchar &amp;gt;= 0 then&lt;br /&gt;      fprintf ppf &quot;%s%i%s%i&quot; msg_chars startchar msg_to endchar;&lt;br /&gt;    fprintf ppf &quot;@}&quot;&lt;br /&gt;  end&lt;br /&gt;&lt;/pre&gt;Locations generally speaking come out in a     format along the lines of: &lt;code&gt;File &quot;&amp;lt;string&amp;gt;, line 1,     characters 0-10:&quot;&lt;/code&gt;&lt;pre&gt;&lt;br /&gt;let print (ppf : formatter) (loc : t) : unit =&lt;br /&gt;  (* The syntax, [@{&amp;lt;loc&amp;gt;%a@}] associates the embedded text with the&lt;br /&gt;     named tag 'loc'*)&lt;br /&gt;  fprintf ppf &quot;@{&amp;lt;loc&amp;gt;%a@}%s@.&quot; print_loc loc msg_colon&lt;br /&gt;    &lt;/pre&gt;    That last function, &lt;code&gt;print&lt;/code&gt; is just a small wrapper     over &lt;code&gt;print_loc&lt;/code&gt; that appends a colon to the location.     &lt;/p&gt;     &lt;h2&gt;Exception handling involving errors with locations&lt;/h2&gt;    &lt;p&gt;This section is concerned with the following section of     the &lt;code&gt;Location&lt;/code&gt;'s signature.     &lt;pre&gt;&lt;br /&gt;val register_error_of_exn : (exn &amp;rarr; error option) &amp;rarr; unit&lt;br /&gt;val error_of_exn : exn &amp;rarr; error option&lt;br /&gt;val error_reporter : (formatter &amp;rarr; error &amp;rarr; unit) ref&lt;br /&gt;val report_error : formatter &amp;rarr; error &amp;rarr; unit&lt;br /&gt;val report_exception : formatter &amp;rarr; exn &amp;rarr; unit&lt;br /&gt;    &lt;/pre&gt;    &lt;code&gt;Location&lt;/code&gt; contains a mutable list of exception     handlers where an exception handler is a function of     type &lt;code&gt;exn &amp;rarr; error option&lt;/code&gt;.     &lt;pre&gt;&lt;br /&gt;let error_of_exn : (exn &amp;rarr; error option) list ref = ref []&lt;br /&gt;    &lt;/pre&gt;    A function is provided that adds an exception handler to the above     list.     &lt;pre&gt;&lt;br /&gt;let register_error_of_exn f = error_of_exn := f :: !error_of_exn&lt;br /&gt;    &lt;/pre&gt;    The next function &lt;code&gt;error_of_exn&lt;/code&gt; (yes, it is the only     remaining function that manipulates the     list &lt;code&gt;error_exn&lt;/code&gt; previously defined directly) walks the     list looking for a handler returning the contents of the result of     the first such function that doesn't return a &lt;code&gt;None&lt;/code&gt;    value.     &lt;pre&gt;&lt;br /&gt;let error_of_exn exn =&lt;br /&gt;  let rec loop = function&lt;br /&gt;    | [] &amp;rarr; None&lt;br /&gt;    | f :: rest &amp;rarr;&lt;br /&gt;      match f exn with&lt;br /&gt;      | Some _ as r &amp;rarr; r&lt;br /&gt;      | None &amp;rarr; loop rest&lt;br /&gt;  in&lt;br /&gt;  loop !error_of_exn&lt;br /&gt;    &lt;/pre&gt;    &lt;/p&gt;    &lt;p&gt;We define now a &quot;default&quot; error reporting function. Given a     formatter and an error, write the error location, an explanation     of the error to the formatter and the same for any associated     &quot;sub&quot; errors.     &lt;pre&gt;&lt;br /&gt;let rec default_error_reporter &lt;br /&gt;    (ppf : formatter) ({loc; msg; sub} : error) : unit =&lt;br /&gt;  print ppf loc;&lt;br /&gt;  Format.pp_print_string ppf msg;&lt;br /&gt;  List.iter (Format.fprintf ppf &quot;@\n@[&amp;lt;2&amp;gt;%a@]&quot; default_error_reporter) sub&lt;br /&gt;    &lt;/pre&gt;    Now, &lt;code&gt;error_reporter&lt;/code&gt; itself is a reference cell with     default value &lt;code&gt;default_error_reporter&lt;/code&gt;.     &lt;pre&gt;&lt;br /&gt;let error_reporter = ref default_error_reporter&lt;br /&gt;    &lt;/pre&gt;    This next function, &lt;code&gt;print_updating_num_loc_lines&lt;/code&gt;    looks more complicated than it is but does demonstrate a rather     advanced usage of &lt;code&gt;Format&lt;/code&gt; by containing calls to the     functions &lt;code&gt;pp_get_formatter_out_functions&lt;/code&gt;,     &lt;code&gt;pp_set_formatter_out_functions&lt;/code&gt; to tempoarily replace     the default function for writing strings. The semantic of the     function is to print an error on a formatter incidentally     recording the number of lines required to do so.     &lt;pre&gt;&lt;br /&gt;(* A mutable line count*)&lt;br /&gt;let num_loc_lines : int ref = ref 0&lt;br /&gt;&lt;br /&gt;(*Prints an error on a formatter incidentally recording the number of&lt;br /&gt;  lines required to do so*)&lt;br /&gt;let print_updating_num_loc_lines &lt;br /&gt;    (ppf : formatter) &lt;br /&gt;    (f : formatter &amp;rarr; error &amp;rarr; unit) &lt;br /&gt;    (arg : error) : unit =&lt;br /&gt;  (*A record of functions of output primitives*)&lt;br /&gt;  let out_functions : formatter_out_functions&lt;br /&gt;      = pp_get_formatter_out_functions ppf () in&lt;br /&gt;  (*The strategoy is to temporarily replace the basic function for&lt;br /&gt;    writing a string with this one*)&lt;br /&gt;  let out_string (str : string) (start : int) (len : int) : unit =&lt;br /&gt;    (*A function for counting line breaks in [str]. [c] is the current&lt;br /&gt;      count, [i] is the current char under consideration*)&lt;br /&gt;    let rec count (i : int) (c : int) : int=&lt;br /&gt;      if i = start + len then c&lt;br /&gt;      else if String.get str i = '\n' then count (succ i) (succ c)&lt;br /&gt;      else count (succ i) c &lt;br /&gt;    in&lt;br /&gt;    (*Update the count*)&lt;br /&gt;    num_loc_lines := !num_loc_lines + count start 0;&lt;br /&gt;    (*Write the string to the formatter*)&lt;br /&gt;    out_functions.out_string str start len &lt;br /&gt;  in&lt;br /&gt;  (*Replace the standard string output primitive with the one just&lt;br /&gt;    defined *)&lt;br /&gt;  pp_set_formatter_out_functions ppf &lt;br /&gt;    {out_functions with out_string} ;&lt;br /&gt;  (*Write the error to the formatter*)&lt;br /&gt;  f ppf arg ;&lt;br /&gt;  pp_print_flush ppf ();&lt;br /&gt;  (*Restore the standard primitive*)&lt;br /&gt;  pp_set_formatter_out_functions ppf out_functions&lt;br /&gt;    &lt;/pre&gt;    The function &lt;code&gt;report_error&lt;/code&gt; uses the currently     installed error reporter to write an error report for a given     error and formatter incidentally updating a count indicating the     number of lines written.     &lt;pre&gt;&lt;br /&gt;let report_error (ppf : formatter) (err : error) : unit=&lt;br /&gt;  print_updating_num_loc_lines ppf !error_reporter err&lt;br /&gt;    &lt;/pre&gt;    &lt;/p&gt;    &lt;p&gt;This next function, &lt;code&gt;report_exception_rec&lt;/code&gt; tries a     number of times to find a handler for a given error and if     successful formats it. In the worst case a handler is never found     and the exception propogates.     &lt;pre&gt;&lt;br /&gt;let rec report_exception_rec (n : int) (ppf : formatter) (exn : exn) : unit =&lt;br /&gt;  (*Try to find a handler for the exception*)&lt;br /&gt;  try match error_of_exn exn with&lt;br /&gt;  | Some err &amp;rarr; &lt;br /&gt;    (*Format the resulting error using the current error reporter*)&lt;br /&gt;    fprintf ppf &quot;@[%a@]@.&quot; report_error err &lt;br /&gt;  (*The syntax @[%a@]@ writes function output in a box followed by a&lt;br /&gt;    'cut' break hint*)&lt;br /&gt;  | None &amp;rarr; raise exn (*A handler could not be found*)&lt;br /&gt;  with exn when n &gt; 0 &amp;rarr;&lt;br /&gt;    (*A handler wasn't found. Try again*)&lt;br /&gt;    report_exception_rec (n - 1) ppf exn&lt;br /&gt;    &lt;/pre&gt;    The last piece is &lt;code&gt;report_exception&lt;/code&gt;. It attempts to     write an error report for the given exception on the provided     formatter. The exception can be re-raised if no handler is found.     &lt;pre&gt;&lt;br /&gt;let report_exception (ppf : formatter) (exn : exn) : unit = &lt;br /&gt;  report_exception_rec 5 ppf exn&lt;br /&gt;    &lt;/pre&gt;    &lt;/p&gt;     &lt;h3&gt;Usage&lt;/h3&gt;     &lt;p&gt;In this section we see how an example of how the above     machinery is used. Consider defining a lexical analyzer as an     example. Suppose the scanner is defined by the     file &lt;code&gt;lexer.mll&lt;/code&gt; (the input file     to &lt;code&gt;ocamllex&lt;/code&gt;). We can imagine its header containing     code like the following.     &lt;pre&gt;&lt;br /&gt;     {&lt;br /&gt;        (*The cases of lexer errors*)&lt;br /&gt;        type error =&lt;br /&gt;          | Illegal_character of char&lt;br /&gt;          | Unterminated_comment of Location.t&lt;br /&gt;&lt;br /&gt;        (*The lexer exception type*)&lt;br /&gt;        exception Error of error * Location.t&lt;br /&gt;&lt;br /&gt;        (*This function takes a formatter and an instance of type&lt;br /&gt;          [error] and writes a message to the formatter explaining the&lt;br /&gt;          meaning. This is a &quot;printer&quot;*)&lt;br /&gt;        let report_error (ppf : Format.formatter) : error &amp;rarr; unit = function&lt;br /&gt;         | Illegal_character c &amp;rarr; &lt;br /&gt;            Format.fprintf ppf &quot;Illegal character (%s)&quot; (Char.escaped c)&lt;br /&gt;         | Unterminated_comment _ &amp;rarr; &lt;br /&gt;            Format.fprintf ppf &quot;Comment not terminated&quot;&lt;br /&gt;&lt;br /&gt;        (*Note that [report_error] is a function that unifies with&lt;br /&gt;          the [formatter &amp;rarr; 'a &amp;rarr; unit] parameter of&lt;br /&gt;          [error_of_printer]*)&lt;br /&gt;&lt;br /&gt;        (*Register an exception handler for the lexer exception type*)&lt;br /&gt;        let () =&lt;br /&gt;         Location.register_error_of_exn&lt;br /&gt;          (function&lt;br /&gt;           | Error (err, loc) &amp;rarr;&lt;br /&gt;              Some (Location.error_of_printer loc report_error err)&lt;br /&gt;           | _ &amp;rarr;  None&lt;br /&gt;          )&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;     /*...*/&lt;br /&gt;     rule token = ...&lt;br /&gt;    &lt;/pre&gt;    A function to handle errors with attached locations (in a REPL for     example) is expressible as an idiom as simple as something like     this.     &lt;pre&gt;&lt;br /&gt;let handle_interpreter_error ?(finally=(fun () &amp;rarr; ())) ex =&lt;br /&gt;  finally ();&lt;br /&gt;  Location.report_exception (Format.std_formatter) ex&lt;br /&gt;&lt;br /&gt;let safe_proc ?finally f =&lt;br /&gt;  try f ()&lt;br /&gt;  with exn &amp;rarr; handle_interpreter_error ?finally exn&lt;br /&gt;    &lt;/pre&gt;    &lt;/p&gt;    &lt;hr/&gt;  &lt;/body&gt;&lt;/html&gt;</content><category scheme="http://www.blogger.com/atom/ns#" term="Pretty-printing"/><category scheme="http://www.blogger.com/atom/ns#" term="Parsing"/><category scheme="http://www.blogger.com/atom/ns#" term="ocamlyacc"/><category scheme="http://www.blogger.com/atom/ns#" term="ocamllex"/><category scheme="http://www.blogger.com/atom/ns#" term="OCaml"/><category scheme="http://www.blogger.com/atom/ns#" term="Lexical analysis"/><id>tag:blogger.com,1999:blog-5012565255225108517.post-7147619713106104281</id><title type="text">Dealing with source code locations (in lexical and syntax analysis)</title><updated>2017-04-13T12:49:13-00:00</updated><author><email>noreply@blogger.com</email><uri>https://plus.google.com/104436573144909855029</uri><name>Shayne Fletcher</name></author></entry><entry><source><updated>2017-05-09T12:00:00-00:00</updated><link title="OCaml Weekly News" type="text/html" href="http://alan.petitepomme.net/cwn/" rel="related"/><link title="OCaml Weekly News" type="application/rss+xml" href="http://alan.petitepomme.net/cwn/cwn.rss" rel="self"/><id>http://alan.petitepomme.net/cwn/</id><title type="text">OCaml Weekly News</title><author><name>OCaml Weekly News</name></author></source><link href="http://alan.petitepomme.net/cwn/2017.03.28.html" rel="alternate"/><content xml:base="http://alan.petitepomme.net/cwn/cwn.rss" type="html">&lt;ol&gt;&lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.03.28.html#1&gt;OCaml on the benchmarks game&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.03.28.html#2&gt;Exceptions and Gc.&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.03.28.html#3&gt;Open 18-month Research Engineer Position on Frama-C/E-ACSL&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.03.28.html#4&gt;Transforming side-effects to a monad&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.03.28.html#5&gt;Loading .ml in memory to interact with them.&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.03.28.html#6&gt;React.js programming in OCaml?&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.03.28.html#7&gt;first release of minivpt: a minimalist vantage-point tree implementation in OCaml&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.03.28.html#8&gt;BuckleScript 1.6&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.03.28.html#9&gt;Ocaml Github Pull Requests&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.03.28.html#10&gt;Other OCaml News&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;</content><id>http://alan.petitepomme.net/cwn/2017.03.28.html</id><title type="text">Weekly News</title><updated>2017-03-28T12:00:00-00:00</updated><author><name>OCaml Weekly News</name></author></entry><entry><source><updated>2017-03-28T11:27:59-00:00</updated><link title="Mathematics and Computation" type="text/html" href="http://math.andrej.com" rel="related"/><link title="Mathematics and Computation" type="application/rss+xml" href="http://math.andrej.com/feed/" rel="self"/><generator>https://wordpress.org/?v=4.8-alpha-40048</generator><id>http://math.andrej.com</id><title type="text">Mathematics and Computation</title><author><name>Andrej Bauer</name></author></source><link href="http://math.andrej.com/2017/03/28/two-phd-positions-in-ljubljana-starting-october-2017/" rel="alternate"/><link href="http://math.andrej.com/2017/03/28/two-phd-positions-in-ljubljana-starting-october-2017/#respond" rel="related"/><content xml:base="http://math.andrej.com/feed/" type="html">&lt;p&gt;We are looking for two PhD students at the Faculty of Mathematics and Physics, University of Ljubljana. The programme starts in October 2017 and lasts three years. The positions will be fully funded (subject to approval by the funding agency). The candidates should have a Master&amp;#8217;s degree in mathematics or computer science. No knowledge of Slovene is required.&lt;/p&gt;
&lt;p&gt;The first PhD student will be advised by dr. Andrej Bauer. The topic of research is foundations of type theory. The candidate should have interest in mathematical aspects of type theory, and familiarity with proof assistants is desirable.&lt;/p&gt;
&lt;p&gt;The second PhD student will be advised by dr. Matija Pretnar. The topic of research is the theory of programming languages with a focus on computational effects. The candidate should have interest in both the mathematical foundations and practical implementation of programming languages.&lt;/p&gt;
&lt;p&gt;Candidates should send their applications as soon as possible, but no later than the end of April, to Andrej Bauer &lt;a href=&quot;&amp;#109;&amp;#97;&amp;#x69;&amp;#x6c;&amp;#116;&amp;#111;&amp;#58;&amp;#x61;&amp;#x6e;&amp;#100;&amp;#114;&amp;#x65;&amp;#x6a;.&amp;#98;&amp;#97;&amp;#x75;&amp;#x65;&amp;#114;&amp;#64;&amp;#x66;&amp;#x6d;f&amp;#46;&amp;#117;&amp;#x6e;&amp;#x69;&amp;#45;&amp;#108;&amp;#x6a;&amp;#x2e;s&amp;#105;&quot;&gt;&amp;#x61;&amp;#x6e;&amp;#100;&amp;#114;&amp;#x65;&amp;#x6a;.&amp;#98;&amp;#97;&amp;#x75;&amp;#x65;&amp;#114;&amp;#64;&amp;#x66;&amp;#x6d;f&amp;#46;&amp;#117;&amp;#x6e;&amp;#x69;&amp;#45;&amp;#108;&amp;#x6a;&amp;#x2e;s&amp;#105;&lt;/a&gt; or Matija Pretnar &lt;a href=&quot;&amp;#109;&amp;#97;&amp;#x69;&amp;#108;&amp;#x74;&amp;#111;&amp;#x3a;&amp;#109;&amp;#x61;&amp;#116;i&amp;#x6a;&amp;#97;&amp;#x2e;&amp;#112;&amp;#x72;&amp;#101;&amp;#x74;&amp;#110;&amp;#x61;&amp;#114;&amp;#64;&amp;#x66;&amp;#109;&amp;#x66;&amp;#46;&amp;#x75;&amp;#110;&amp;#x69;&amp;#45;l&amp;#x6a;&amp;#46;&amp;#x73;&amp;#105;&quot;&gt;&amp;#109;&amp;#x61;&amp;#116;i&amp;#x6a;&amp;#97;&amp;#x2e;&amp;#112;&amp;#x72;&amp;#101;&amp;#x74;&amp;#110;&amp;#x61;&amp;#114;&amp;#64;&amp;#x66;&amp;#109;&amp;#x66;&amp;#46;&amp;#x75;&amp;#110;&amp;#x69;&amp;#45;l&amp;#x6a;&amp;#46;&amp;#x73;&amp;#105;&lt;/a&gt;, depending on their primary interest. Please include a short CV, academic record, and a statement of interest.&lt;/p&gt;
</content><category term="Teaching"/><id>http://math.andrej.com/?p=1989</id><title type="text">Two PhD positions in Ljubljana starting October 2017</title><updated>2017-03-28T11:27:59-00:00</updated><author><name>Andrej Bauer</name></author></entry><entry><source><updated>2017-05-11T20:18:34-00:00</updated><subtitle xml:base="http://blog.shaynefletcher.org/feeds/posts/default/-/OCaml" type="html">&quot;Hooked&quot; on programming</subtitle><link type="application/atom+xml" href="http://www.blogger.com/feeds/5012565255225108517/posts/default/-/OCaml/-/OCaml?start-index=26&amp;max-results=25" rel="next"/><link href="http://pubsubhubbub.appspot.com/" rel="hub"/><link type="text/html" href="http://blog.shaynefletcher.org/search/label/OCaml" rel="alternate"/><link type="application/atom+xml" href="http://www.blogger.com/feeds/5012565255225108517/posts/default/-/OCaml" rel="self"/><link type="application/atom+xml" href="http://blog.shaynefletcher.org/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed"/><generator uri="http://www.blogger.com" version="7.00">Blogger</generator><category term="recursive descent"/><category term="ppx"/><category term="ppf"/><category term="left recursion"/><category term="grammars"/><category term="balanced binary search trees"/><category term="Windows 8.1"/><category term="Windows 7"/><category term="Variance"/><category term="Universal type"/><category term="Universal Gas Constant"/><category term="Tail recursion"/><category term="Subtyping"/><category term="Stack overflow"/><category term="Sorting"/><category term="Simulation"/><category term="Sieve of Eratosthenes"/><category term="Science"/><category term="Rings"/><category term="Recursion"/><category term="Priority queue"/><category term="Pretty-printing"/><category term="Poof"/><category term="Polynomials"/><category term="Polymorphic variants"/><category term="Permutation"/><category term="Pascal"/><category term="Numerical analysis"/><category term="Monty Hall"/><category term="Modules"/><category term="List comprehensions"/><category term="Leftist heap"/><category term="Labeled arguments"/><category term="Ideal Gas Law"/><category term="Horner's rule"/><category term="Functors"/><category term="Financial Modeling in Python"/><category term="Exponentiation by squaring"/><category term="Compression"/><category term="Combination"/><category term="Church-Turing thesis"/><category term="Church numerals"/><category term="Cartesian product"/><category term="Algorithmic complexity"/><category term="64-bit"/><category term="type-classes"/><category term="ocamlyacc"/><category term="ocamllex"/><category term="Y Combinator"/><category term="Taylor polynomials"/><category term="Streams"/><category term="Recursive lists"/><category term="Prolog"/><category term="Monads"/><category term="Dimensional analysis"/><category term="Algebra"/><category term="Regular expressions"/><category term="Powerset"/><category term="Statistics"/><category term="Lexical analysis"/><category term="Haskell"/><category term="Parsing"/><category term="data structures"/><category term="Symbolic computation"/><category term="Lambda calculus"/><category term="Felix"/><category term="Boost"/><category term="Python"/><category term="Algorithms"/><category term="C++"/><category term="Functional programming"/><category term="OCaml"/><id>tag:blogger.com,1999:blog-5012565255225108517</id><title type="text">Shayne Fletcher</title><author><email>noreply@blogger.com</email><name>Shayne Fletcher</name></author></source><published>2017-03-21T19:43:00-00:00</published><link title="Polynomials over rings" type="text/html" href="http://blog.shaynefletcher.org/2017/03/polynomials-over-rings.html" rel="alternate"/><link type="application/atom+xml" href="http://www.blogger.com/feeds/5012565255225108517/posts/default/2046775841421505981" rel="self"/><link type="application/atom+xml" href="http://www.blogger.com/feeds/5012565255225108517/posts/default/2046775841421505981" rel="edit"/><content xml:base="http://blog.shaynefletcher.org/feeds/posts/default/-/OCaml" type="html">&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01//EN&quot;           &quot;http://www.w3.org/TR/html4/strict.dtd&quot;&gt;&lt;html&gt;  &lt;head&gt;    &lt;script type=&quot;text/x-mathjax-config&quot;&gt;      MathJax.Hub.Config({       extensions: [&quot;tex2jax.js&quot;,&quot;TeX/AMSmath.js&quot;,&quot;TeX/AMSsymbols.js&quot;],       jax: [&quot;input/TeX&quot;, &quot;output/HTML-CSS&quot;],       tex2jax: {       inlineMath: [ ['$','$'], [&quot;\\(&quot;,&quot;\\)&quot;] ],       displayMath: [ ['$$','$$'], [&quot;\\[&quot;,&quot;\\]&quot;] ],       },       &quot;HTML-CSS&quot;: { availableFonts: [&quot;TeX&quot;] }       });     &lt;/script&gt;      &lt;script type=&quot;text/javascript&quot; src=&quot;http://cdn.mathjax.org/mathjax/latest/MathJax.js&quot;&gt;&lt;/script&gt;    &lt;title&gt;Polynomials over rings&lt;/title&gt;  &lt;/head&gt;  &lt;body&gt;    &lt;p&gt;This post provides a workout in generic programming using modules &amp;     functors.     &lt;/p&gt;    &lt;p&gt;The program presented here models     univariate &lt;a href=&quot;https://en.wikipedia.org/wiki/Polynomial&quot;&gt;polynomials&lt;/a&gt;    over &lt;a href=&quot;https://en.wikipedia.org/wiki/Ring_(mathematics)&quot;&gt;rings&lt;/a&gt;    based on an exercise in &quot;The Module Language&quot; chapter, of     &lt;a href=&quot;http://gallium.inria.fr/~remy/&quot;&gt;Didier Rémy's&lt;/a&gt;    book, &lt;a href=&quot;https://caml.inria.fr/pub/docs/u3-ocaml/index.html&quot;&gt;Using,     Understanding and Unraveling the OCaml Lanaguage&lt;/a&gt;.     &lt;/p&gt;     &lt;h3&gt;Arithmetics and rings&lt;/h3&gt;    &lt;p&gt;We begin with a type for modules implementing arithmetic.     &lt;pre&gt;&lt;br /&gt;    module type ARITH = sig&lt;br /&gt;      type t&lt;br /&gt;      val of_int : int -&gt; t            val to_int : t -&gt; int&lt;br /&gt;      val of_string : string -&gt; t      val to_string : t -&gt; string&lt;br /&gt;      val zero : t                     val one : t&lt;br /&gt;      val add : t -&gt; t -&gt; t            val sub : t -&gt; t -&gt; t&lt;br /&gt;      val mul : t -&gt; t -&gt; t            val div : t -&gt; t -&gt; t&lt;br /&gt;      val compare : t -&gt; t -&gt; int      val equal : t -&gt; t -&gt; bool&lt;br /&gt;    end;;&lt;br /&gt;    &lt;/pre&gt;    A ring is a set equipped with two binary operations that     generalize the arithmetic operations of addition and     multiplication.     &lt;pre&gt;&lt;br /&gt;    module type RING = sig&lt;br /&gt;      type t&lt;br /&gt;      type extern_t&lt;br /&gt;      val print : t -&gt; unit&lt;br /&gt;      val make : extern_t -&gt; t         val show : t -&gt; extern_t&lt;br /&gt;      val zero : t                     val one : t&lt;br /&gt;      val add : t -&gt; t -&gt; t            val mul : t -&gt; t -&gt; t&lt;br /&gt;      val equal : t -&gt; t -&gt; bool&lt;br /&gt;    end;;&lt;br /&gt;    &lt;/pre&gt;    We can build rings over arithmetics with functors. This particular     one fixes the external representation of the elements of the ring     to &lt;code&gt;int&lt;/code&gt;.     &lt;pre&gt;&lt;br /&gt;    module Ring (A : ARITH) :&lt;br /&gt;      RING  with type t = A.t and type extern_t = int =&lt;br /&gt;    struct&lt;br /&gt;      include A&lt;br /&gt;      type extern_t = int&lt;br /&gt;      let make = of_int                let show = to_int&lt;br /&gt;      let print x = print_int (show x)&lt;br /&gt;    end;;&lt;br /&gt;    &lt;/pre&gt;    Thus, here for example are rings over various specific arithmetic     modules.     &lt;pre&gt;&lt;br /&gt;    module Ring_int32 = Ring (Int32);;&lt;br /&gt;    module Ring_int64 = Ring (Int64);;&lt;br /&gt;    module Ring_nativeint = Ring (Nativeint);;&lt;br /&gt;    module Ring_int = Ring (&lt;br /&gt;      struct&lt;br /&gt;        type t = int&lt;br /&gt;        let of_int x = x                   let to_int x = x&lt;br /&gt;        let of_string = int_of_string      let to_string = string_of_int&lt;br /&gt;        let zero = 0                       let one = 1&lt;br /&gt;        let add = ( + )                    let sub = ( - )&lt;br /&gt;        let mul = ( * )                    let div = ( / )&lt;br /&gt;        let compare = Pervasives.compare   let equal = ( = )&lt;br /&gt;      end&lt;br /&gt;    );;&lt;br /&gt;    &lt;/pre&gt;    &lt;/p&gt;    &lt;h3&gt;Polynomials&lt;/h3&gt;    &lt;p&gt;We define now the type of polynomials.     &lt;pre&gt;&lt;br /&gt;    module type POLYNOMIAL = sig&lt;br /&gt;      type coeff (*Type of coefficients*)&lt;br /&gt;      type coeff_extern_t (*Type of coeff. external rep*)&lt;br /&gt;&lt;br /&gt;      (*Polynomials satisfy the ring interface*)&lt;br /&gt;      include RING (*Declares a type [t] and [extern_t]*)&lt;br /&gt;&lt;br /&gt;      (*Function to evaluate a polynomial at a point*)&lt;br /&gt;      val eval : t -&gt; coeff -&gt; coeff&lt;br /&gt;    end;;&lt;br /&gt;    &lt;/pre&gt;    Given a module implementing a ring, we can generate a module     implementing polynomials with coefficients drawn from the ring.     &lt;pre&gt;&lt;br /&gt;    module Polynomial (R : RING) :&lt;br /&gt;      POLYNOMIAL with type coeff = R.t&lt;br /&gt;      and type coeff_extern_t = R.extern_t&lt;br /&gt;      and type extern_t = (R.extern_t * int) list =&lt;br /&gt;    struct&lt;br /&gt;    &lt;br /&gt;      type coeff = R.t (*Coefficient type*)&lt;br /&gt;      type coeff_extern_t = R.extern_t (*External coeff. rep*)&lt;br /&gt;      type extern_t = (coeff_extern_t * int) list (*External polynomial rep*)&lt;br /&gt;    &lt;br /&gt;      (*List of coefficients and their powers*)&lt;br /&gt;      type t = (coeff * int) list (*Invariant : Ordered by powers,&lt;br /&gt;                                    lower order terms at the front*)&lt;br /&gt;&lt;br /&gt;      (* ... *)&lt;br /&gt;&lt;br /&gt;    end;;&lt;br /&gt;    &lt;/pre&gt;    As the comments indicate, the polynomial data structure is a list     of pairs of coefficients and powers, ordered so that lower powers     come before higher ones. Here's a simple printing utility to aid     visualization.     &lt;pre&gt;&lt;br /&gt;    let print p =&lt;br /&gt;      List.iter&lt;br /&gt;        (fun (c, k) -&gt; Printf.printf &quot;+ (&quot;;&lt;br /&gt;          R.print c;&lt;br /&gt;          Printf.printf &quot;)X^%d &quot; k)&lt;br /&gt;        p&lt;br /&gt;    &lt;/pre&gt;    In order that we get a canonical representation, null     coefficients are eliminated. In particular, the null monomial is     simply the empty list.     &lt;pre&gt;&lt;br /&gt;    let zero = []&lt;br /&gt;    &lt;/pre&gt;    The multiplicative identity &lt;code&gt;one&lt;/code&gt; is not really     necessary as it is just a particular monomial however, its     presence makes polynomials themselves satisfy the interface of     rings.     &lt;pre&gt;&lt;br /&gt;    let one = [R.one, 0]&lt;br /&gt;    &lt;/pre&gt;    This helper function constructs monomials.     &lt;pre&gt;&lt;br /&gt;    let monomial (a : coeff) (k : int) =&lt;br /&gt;      if k &amp;lt; 0 then&lt;br /&gt;        failwith &quot;monomial : negative powers not supported&quot;&lt;br /&gt;      else if R.equal a R.zero then [] else [a, k]&lt;br /&gt;    &lt;/pre&gt;    Next up, we define addition of polynomials by the following     function. Care is taken to ensure the representation invariant is     respected.     &lt;pre&gt;&lt;br /&gt;    let rec add u v =&lt;br /&gt;      match u, v with&lt;br /&gt;      | [], _ -&gt; v&lt;br /&gt;      | _, [] -&gt; u&lt;br /&gt;      | ((c1, k1) :: r1 as p1), ((c2, k2) :: r2 as p2) -&gt;&lt;br /&gt;        if k1 &amp;lt; k2 then&lt;br /&gt;          (c1, k1) :: (add r1 p2)&lt;br /&gt;        else if k1 = k2 then&lt;br /&gt;          let c = R.add c1 c2 in&lt;br /&gt;          if R.equal c R.zero then add r1 r2&lt;br /&gt;          else (c, k1) :: (add r1 r2)&lt;br /&gt;        else (c2, k2) :: (add p1 r2)&lt;br /&gt;    &lt;/pre&gt;    With &lt;code&gt;monomial&lt;/code&gt; and &lt;code&gt;add&lt;/code&gt; avaialable, we can     now write &lt;code&gt;make&lt;/code&gt; that computes a polynomial from an     external representation. We also give the inverse     function &lt;code&gt;show&lt;/code&gt; here too.     &lt;pre&gt;&lt;br /&gt;    let make l =&lt;br /&gt;      List.fold_left (fun acc (c, k) -&gt;&lt;br /&gt;        add (monomial (R.make c) k) acc) zero l&lt;br /&gt;&lt;br /&gt;    let show p =&lt;br /&gt;      List.fold_right (fun (c, k) acc -&gt; (R.show c, k) :: acc) p []&lt;br /&gt;    &lt;/pre&gt;    The module private function &lt;code&gt;times&lt;/code&gt; left-multiplies a     polynomial by a monomial.     &lt;pre&gt;&lt;br /&gt;    let rec times (c, k) = function&lt;br /&gt;      | [] -&gt; []&lt;br /&gt;      | (c1, k1) :: q -&gt;&lt;br /&gt;        let c2 = R.mul c c1 in&lt;br /&gt;        if R.equal c2 R.zero then times (c, k) q&lt;br /&gt;        else (c2, k + k1) :: times (c, k) q&lt;br /&gt;    &lt;/pre&gt;    Given the existence of &lt;code&gt;times&lt;/code&gt;, polynomial     multiplication can be expressed in a &quot;one-liner&quot;.     &lt;pre&gt;&lt;br /&gt;    let mul p = List.fold_left (fun r m -&gt; add r (times m p)) zero&lt;br /&gt;    &lt;/pre&gt;    Comparing two polynomials for equality is achieved with the     following predicate.     &lt;pre&gt;&lt;br /&gt;    let rec equal p1 p2 =&lt;br /&gt;      match p1, p2 with&lt;br /&gt;      | [], [] -&gt; true&lt;br /&gt;      | (c1, k1) :: q1, (c2, k2) :: q2 -&gt;&lt;br /&gt;        k1 = k2 &amp;&amp; R.equal c1 c2 &amp;&amp; equal q1 q2&lt;br /&gt;      | _ -&gt; false&lt;br /&gt;    &lt;/pre&gt;    In the course of evaluating polynomials for a specific value of     their indeterminate, we'll require a function for computing     powers. The following routine uses     the &lt;a href=&quot;https://en.wikipedia.org/wiki/Exponentiation_by_squaring&quot;&gt;exponentiation     by squaring&lt;/a&gt; technique.     &lt;pre&gt;&lt;br /&gt;    let rec pow c = function&lt;br /&gt;      | 0 -&gt; R.one&lt;br /&gt;      | 1 -&gt; c&lt;br /&gt;      | k -&gt;&lt;br /&gt;        let l = pow c (k lsr 1) in&lt;br /&gt;        let l2 = R.mul l l in&lt;br /&gt;        if k land 1 = 0 then l2 else R.mul c l2&lt;br /&gt;    &lt;/pre&gt;    Finally, the function &lt;code&gt;eval&lt;/code&gt; for evaluation of a     polynomial at a specific point. The implementation     uses &lt;a href=&quot;https://en.wikipedia.org/wiki/Horner's_method&quot;&gt;Horner's     rule&lt;/a&gt; for computationally efficient evaluation.     &lt;pre&gt;&lt;br /&gt;    let eval p c = match List.rev p with&lt;br /&gt;      | [] -&gt; R.zero&lt;br /&gt;      | (h :: t) -&gt;&lt;br /&gt;        let reduce (a, k) (b, l) =&lt;br /&gt;          let n = pow c (k - l) in&lt;br /&gt;          let t = R.add (R.mul a n) b in&lt;br /&gt;          (t, l)  in&lt;br /&gt;        let a, k = List.fold_left reduce h t in&lt;br /&gt;        R.mul (pow c k) a&lt;br /&gt;      &lt;/pre&gt;    &lt;/p&gt;    &lt;h3&gt;Testing and example usage&lt;/h3&gt;    &lt;p&gt;The following interactive session creates a polynomial with     integer coefficients module and uses it to confirm the equivalence     of $(1 + x)(1 - x)$ with $(1 - x^{2})$.     &lt;pre&gt;&lt;br /&gt;    # #use &quot;polynomial.ml&quot;;;&lt;br /&gt;    # module R = Ring_int;;&lt;br /&gt;    # module P = Polynomial (R);;&lt;br /&gt;    # let p = P.mul (P.make [(1, 0); (1, 1)]) (P.make [(1, 0); (-1, 1)]);;&lt;br /&gt;    # let q = P.make [(1, 0); (-1, 2)];;&lt;br /&gt;    # P.equal p q;;&lt;br /&gt;    - : bool = true&lt;br /&gt;    &lt;/pre&gt;    Polynomials in two variables, can be treated as univariate     polynomials with polynomial coefficients. For example, the     polynomial $(X + Y)$ can be regarded as $(1 \times X^{1})Y^{0} +     (1 \times X^{0})Y^{1}$. Similarly we can write $X - Y$ as $(1     \times X^{1})Y^{0} + (-1 \times X^{0}) Y^1$ and now check the     equivalence $(X + Y)(X - Y) = (X^{2} - Y^{2})$.     &lt;/p&gt;    &lt;pre&gt;&lt;br /&gt;    #module Y = Polynomial (P);;&lt;br /&gt;    &lt;br /&gt;    #(* (X + Y) *)&lt;br /&gt;    #let r = Y.make [&lt;br /&gt;    #  ([1, 1], 0); (*(1 X^1) Y^0*)&lt;br /&gt;    #  ([1, 0], 1)  (*(1 X^0) Y^1*)&lt;br /&gt;    #];;&lt;br /&gt;&lt;br /&gt;    #(* (X - Y) *)&lt;br /&gt;    #let s = Y.make [&lt;br /&gt;    #  ([1, 1], 0); (*(1 X^1) Y^0*)&lt;br /&gt;    #  ([-1, 0], 1) (*((-1) X^0) Y^1*)&lt;br /&gt;    #];;&lt;br /&gt;&lt;br /&gt;    #(* (X^2 - Y^2) *)&lt;br /&gt;    #let t = Y.make [&lt;br /&gt;    #  ([1, 2], 0);   (*(1 X^2) Y^0*)&lt;br /&gt;    #  ([-1, 0], 2)  (* (-1 X^0) Y^2*)&lt;br /&gt;    #];;&lt;br /&gt;&lt;br /&gt;    #Y.equal (Y.mul r s) t;;&lt;br /&gt;    - : bool = true&lt;br /&gt;    &lt;/pre&gt;    &lt;/p&gt;   &lt;hr/&gt;  &lt;/body&gt;&lt;/html&gt;</content><category scheme="http://www.blogger.com/atom/ns#" term="Rings"/><category scheme="http://www.blogger.com/atom/ns#" term="Polynomials"/><category scheme="http://www.blogger.com/atom/ns#" term="OCaml"/><category scheme="http://www.blogger.com/atom/ns#" term="Modules"/><category scheme="http://www.blogger.com/atom/ns#" term="Horner's rule"/><category scheme="http://www.blogger.com/atom/ns#" term="Functors"/><category scheme="http://www.blogger.com/atom/ns#" term="Exponentiation by squaring"/><id>tag:blogger.com,1999:blog-5012565255225108517.post-2046775841421505981</id><title type="text">Polynomials over rings</title><updated>2017-03-23T13:48:02-00:00</updated><author><email>noreply@blogger.com</email><uri>https://plus.google.com/104436573144909855029</uri><name>Shayne Fletcher</name></author></entry><entry><source><updated>2017-05-09T12:00:00-00:00</updated><link title="OCaml Weekly News" type="text/html" href="http://alan.petitepomme.net/cwn/" rel="related"/><link title="OCaml Weekly News" type="application/rss+xml" href="http://alan.petitepomme.net/cwn/cwn.rss" rel="self"/><id>http://alan.petitepomme.net/cwn/</id><title type="text">OCaml Weekly News</title><author><name>OCaml Weekly News</name></author></source><link href="http://alan.petitepomme.net/cwn/2017.03.21.html" rel="alternate"/><content xml:base="http://alan.petitepomme.net/cwn/cwn.rss" type="html">&lt;ol&gt;&lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.03.21.html#1&gt;New release of visitors&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.03.21.html#2&gt;Named pipe on Windows.&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.03.21.html#3&gt;Preview: B-tree library&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.03.21.html#4&gt;Jane Street development opam repository&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.03.21.html#5&gt;Exceptions and Gc.&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.03.21.html#6&gt;Ocaml Github Pull Requests&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.03.21.html#7&gt;Other OCaml News&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;</content><id>http://alan.petitepomme.net/cwn/2017.03.21.html</id><title type="text">Weekly News</title><updated>2017-03-21T12:00:00-00:00</updated><author><name>OCaml Weekly News</name></author></entry><entry><summary xml:base="https://blogs.janestreet.com/wp-atom.php" type="html">&lt;p&gt;From now and then, I found myself having to write some mechanical and repetitive code. The usual solution for this is to write a code generator; for instance in the form of a ppx rewriter in the case of OCaml code. This however comes with a cost: code generators are harder to review than plain code and it is a new syntax to learn for other developers. So when the repetitive pattern is local to a specific library or not widely used, it is often not worth the effort. Especially if the code in question is meant to be reviewed and maintained by several people.&lt;/p&gt; &lt;a href=&quot;https://blogs.janestreet.com/trivial-meta-programming-with-cinaps/&quot;&gt;&amp;#187; Continue Reading.&lt;/a&gt;</summary><source><updated>2017-05-11T19:02:45-00:00</updated><subtitle type="text">Jane Street' blogs (Systems and OCaml rolled into one)</subtitle><link type="application/atom+xml" href="https://blogs.janestreet.com/category/ocaml/feed/atom/" rel="self"/><link type="text/html" href="https://blogs.janestreet.com" rel="alternate"/><generator uri="https://wordpress.org/" version="4.7.4">WordPress</generator><id>https://blogs.janestreet.com/feed/atom/</id><title type="text">OCaml – Jane Street Tech Blogs</title><author><name>Jane Street</name></author></source><published>2017-03-20T20:39:29-00:00</published><link type="application/atom+xml" href="https://blogs.janestreet.com/trivial-meta-programming-with-cinaps/feed/atom/" rel="replies"/><link type="text/html" href="https://blogs.janestreet.com/trivial-meta-programming-with-cinaps/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=trivial-meta-programming-with-cinaps#comments" rel="replies"/><link type="text/html" href="https://blogs.janestreet.com/trivial-meta-programming-with-cinaps/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=trivial-meta-programming-with-cinaps" rel="alternate"/><content xml:base="https://blogs.janestreet.com/wp-atom.php" type="html">&lt;p&gt;From now and then, I found myself having to write some mechanical and repetitive code. The usual solution for this is to write a code generator; for instance in the form of a ppx rewriter in the case of OCaml code. This however comes with a cost: code generators are harder to review than plain code and it is a new syntax to learn for other developers. So when the repetitive pattern is local to a specific library or not widely used, it is often not worth the effort. Especially if the code in question is meant to be reviewed and maintained by several people.&lt;/p&gt;
&lt;p&gt;Then there is the possibility of using a macro pre-processor such as cpp or cppo which is the equivalent of cpp but for OCaml. This can help in some cases but this has a cost as well:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;macros generally make the code harder to read&lt;/li&gt;
&lt;li&gt;errors tends to be harder to understand since they don't point where you'd expect&lt;/li&gt;
&lt;li&gt;you can say goodbye to merlin&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In fact, when the repetitive pattern is specific to one particular case and of reasonable size, committing and reviewing the generated code is acceptable. That's the problem &lt;a href=&quot;https://github.com/janestreet/cinaps&quot;&gt;Cinaps&lt;/a&gt; tries to solve.&lt;/p&gt;
&lt;h1&gt;What is cinaps?&lt;/h1&gt;
&lt;p&gt;Cinaps is an application that reads input files and recognize special syntactic forms. Such forms are expected to embed some OCaml code printing something to stdout. What they print is compared against what follow these special forms. The rest works exactly the same as expectation tests.&lt;/p&gt;
&lt;p&gt;The special form is &lt;code&gt;(*$ &amp;lt;ocaml-code&amp;gt; *)&lt;/code&gt; for ml source files, &lt;code&gt;/*$ &amp;lt;ocaml-code&amp;gt; */&lt;/code&gt; for C source files and &lt;code&gt;#|$ &amp;lt;ocaml-code&amp;gt; |#&lt;/code&gt; for S-expression files.&lt;/p&gt;
&lt;p&gt;For instance:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ cat file.ml
let x = 1
(*$ print_newline ();
    List.iter (fun s -&amp;gt; Printf.printf &quot;let ( %s ) = Pervasives.( %s )\n&quot; s s)
      [&quot;+&quot;; &quot;-&quot;; &quot;*&quot;; &quot;/&quot;] *)
(*$*)
let y = 2

$ cinaps file.ml
---file.ml
+++file.ml.corrected
File &quot;file.ml&quot;, line 5, characters 0-1:
  let x = 1
  (*$ print_newline ();
      List.iter (fun s -&amp;gt; Printf.printf &quot;let ( %s ) = Pervasives.( %s )\n&quot; s s)
        [&quot;+&quot;; &quot;-&quot;; &quot;*&quot;; &quot;/&quot;] *)
+|let ( + ) = Pervasives.( + )
+|let ( - ) = Pervasives.( - )
+|let ( * ) = Pervasives.( * )
+|let ( / ) = Pervasives.( / )
  (*$*)
  let y = 2

$ echo $?
1
$ cp file.ml.corrected file.ml
$ cinaps file.ml
$ echo $?
0
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Real example&lt;/h1&gt;
&lt;p&gt;What follows is a real example where using Cinaps made the code much easier to write and maintain. However, I changed the names for this blog post since this code is not released publicly. Note also that this example shows one way we usually write C bindings at Jane Street. It is not meant as a model of how to write C bindings, and the excellent &lt;a href=&quot;https://github.com/ocamllabs/ocaml-ctypes&quot;&gt;ctypes&lt;/a&gt; library should be the default choice in most cases. However, this code pre-dates ctypes and migrating it would be quite a lot of work.&lt;/p&gt;
&lt;p&gt;The example itself is part of a C binding that I wrote a few years ago. While doing so I used &lt;code&gt;Core.Flags&lt;/code&gt; in order to represent a few C enumerations on the OCaml side. &lt;code&gt;Core.Flags&lt;/code&gt; is a module providing &lt;a href=&quot;https://github.com/janestreet/core_kernel/blob/master/src/flags_intf.ml&quot;&gt;a nice abstraction for representing C flags&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The OCaml code looks like what you'd expect from code using &lt;code&gt;Core.Flags&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;ocaml&quot;&gt;&lt;ol&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;module&lt;/span&gt; Open_flags = &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;struct&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;external&lt;/span&gt; get_rdonly   : unit -&amp;gt; Int63.&lt;span style=&quot;color: #060;&quot;&gt;t&lt;/span&gt; = &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;mylib_O_RDONLY&amp;quot;&lt;/span&gt;   &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt;@@noalloc&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;external&lt;/span&gt; get_wronly   : unit -&amp;gt; Int63.&lt;span style=&quot;color: #060;&quot;&gt;t&lt;/span&gt; = &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;mylib_O_WRONLY&amp;quot;&lt;/span&gt;   &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt;@@noalloc&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;external&lt;/span&gt; get_rdwr     : unit -&amp;gt; Int63.&lt;span style=&quot;color: #060;&quot;&gt;t&lt;/span&gt; = &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;mylib_O_RDWR&amp;quot;&lt;/span&gt;     &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt;@@noalloc&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;external&lt;/span&gt; get_nonblock : unit -&amp;gt; Int63.&lt;span style=&quot;color: #060;&quot;&gt;t&lt;/span&gt; = &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;mylib_O_NONBLOCK&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt;@@noalloc&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;external&lt;/span&gt; get_append   : unit -&amp;gt; Int63.&lt;span style=&quot;color: #060;&quot;&gt;t&lt;/span&gt; = &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;mylib_O_APPEND&amp;quot;&lt;/span&gt;   &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt;@@noalloc&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;external&lt;/span&gt; get_creat    : unit -&amp;gt; Int63.&lt;span style=&quot;color: #060;&quot;&gt;t&lt;/span&gt; = &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;mylib_O_CREAT&amp;quot;&lt;/span&gt;    &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt;@@noalloc&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;external&lt;/span&gt; get_trunc    : unit -&amp;gt; Int63.&lt;span style=&quot;color: #060;&quot;&gt;t&lt;/span&gt; = &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;mylib_O_TRUNC&amp;quot;&lt;/span&gt;    &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt;@@noalloc&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;external&lt;/span&gt; get_excl     : unit -&amp;gt; Int63.&lt;span style=&quot;color: #060;&quot;&gt;t&lt;/span&gt; = &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;mylib_O_EXCL&amp;quot;&lt;/span&gt;     &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt;@@noalloc&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;external&lt;/span&gt; get_noctty   : unit -&amp;gt; Int63.&lt;span style=&quot;color: #060;&quot;&gt;t&lt;/span&gt; = &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;mylib_O_NOCTTY&amp;quot;&lt;/span&gt;   &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt;@@noalloc&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;external&lt;/span&gt; get_dsync    : unit -&amp;gt; Int63.&lt;span style=&quot;color: #060;&quot;&gt;t&lt;/span&gt; = &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;mylib_O_DSYNC&amp;quot;&lt;/span&gt;    &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt;@@noalloc&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;external&lt;/span&gt; get_sync     : unit -&amp;gt; Int63.&lt;span style=&quot;color: #060;&quot;&gt;t&lt;/span&gt; = &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;mylib_O_SYNC&amp;quot;&lt;/span&gt;     &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt;@@noalloc&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;external&lt;/span&gt; get_rsync    : unit -&amp;gt; Int63.&lt;span style=&quot;color: #060;&quot;&gt;t&lt;/span&gt; = &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;mylib_O_RSYNC&amp;quot;&lt;/span&gt;    &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt;@@noalloc&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; rdonly   = get_rdonly   &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; wronly   = get_wronly   &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; rdwr     = get_rdwr     &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; nonblock = get_nonblock &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; append   = get_append   &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; creat    = get_creat    &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; trunc    = get_trunc    &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; excl     = get_excl     &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; noctty   = get_noctty   &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; dsync    = get_dsync    &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; sync     = get_sync     &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; rsync    = get_rsync    &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;include&lt;/span&gt; Flags.&lt;span style=&quot;color: #060;&quot;&gt;Make&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;struct&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;      &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; known =&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt; rdonly   , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;rdonly&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; wronly   , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;wronly&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; rdwr     , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;rdwr&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; nonblock , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;nonblock&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; append   , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;append&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; creat    , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;creat&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; trunc    , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;trunc&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; excl     , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;excl&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; noctty   , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;noctty&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; dsync    , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;dsync&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; sync     , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;sync&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; rsync    , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;rsync&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;      &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; remove_zero_flags = &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;false&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;      &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; allow_intersecting = &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;false&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;      &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; should_print_error = &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;    &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/pre&gt;
&lt;p&gt;And there are about 3 modules like this in this file, plus the corresponding stubs in the C file. Writing this code initially was no fun, and adding new flags now that the C library has evolved is still no fun.&lt;/p&gt;
&lt;p&gt;The rest of this section explains how to make it more fun with cinaps.&lt;/p&gt;
&lt;h2&gt;Setting up and using cinaps&lt;/h2&gt;
&lt;p&gt;First I add a rule in the build system to call &lt;code&gt;cinaps&lt;/code&gt; appropriately. I use a few settings specific to our jenga based builds and it is currently not possible to replicate this outside of Jane Street, but assuming you have a &lt;code&gt;Makefile&lt;/code&gt;, you can write:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.PHONY: cinaps
cinaps:
    cinaps -i src/*.ml src/*.c
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now whenever you call &lt;code&gt;make cinaps&lt;/code&gt;, all the files will be updated in place. You can then do &lt;code&gt;git diff&lt;/code&gt; to see what changed.&lt;/p&gt;
&lt;p&gt;Then I write a file &lt;code&gt;src/cinaps_helpers&lt;/code&gt;. It is plain OCaml source file, however it is not suffixed with .ml so that it is not confused with a regular module of the library. It contains the various bits that are common between the ml/C files in the library:&lt;/p&gt;
&lt;pre class=&quot;ocaml&quot;&gt;&lt;ol&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #5d478b; font-style: italic;&quot;&gt;(* -*- tuareg -*- *)&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; stub_prefix = &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;mylib_&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; stub name = stub_prefix ^ name&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; open_flags =&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt; &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;O_RDONLY&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  ; &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;O_WRONLY&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  ; &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;O_RDWR&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  ; &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;O_NONBLOCK&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  ; &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;O_APPEND&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  ; &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;O_CREAT&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  ; &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;O_TRUNC&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  ; &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;O_EXCL&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  ; &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;O_NOCTTY&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  ; &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;O_DSYNC&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  ; &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;O_SYNC&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  ; &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;O_RSYNC&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; other_flags =&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt; ...&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; yet_other_flags =&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt; ...&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; all_flags = open_flags @ other_flags @ yet_other_flags&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;open&lt;/span&gt; StdLabels&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;open&lt;/span&gt; Printf&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; pr fmt = printf &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#40;&lt;/span&gt;fmt ^^ &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;\n&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; flags_module module_name flags ~prefix ~allow_intersection =&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &amp;lt;code &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;to&lt;/span&gt; print an Open_flags like module&amp;gt;&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/pre&gt;
&lt;p&gt;Now, in my original .ml file, I can write:&lt;/p&gt;
&lt;pre class=&quot;ocaml&quot;&gt;&lt;ol&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #5d478b; font-style: italic;&quot;&gt;(*$ #use &amp;quot;cinaps_helpers&amp;quot; $*)&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #5d478b; font-style: italic;&quot;&gt;(*$ flags_module &amp;quot;Open_flags&amp;quot; open_flags ~prefix:&amp;quot;O_&amp;quot; ~allow_intersecting:false *)&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;module&lt;/span&gt; Open_flags = &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;struct&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;external&lt;/span&gt; get_rdonly   : unit -&amp;gt; Int63.&lt;span style=&quot;color: #060;&quot;&gt;t&lt;/span&gt; = &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;mylib_O_RDONLY&amp;quot;&lt;/span&gt;   &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt;@@noalloc&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;external&lt;/span&gt; get_wronly   : unit -&amp;gt; Int63.&lt;span style=&quot;color: #060;&quot;&gt;t&lt;/span&gt; = &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;mylib_O_WRONLY&amp;quot;&lt;/span&gt;   &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt;@@noalloc&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;external&lt;/span&gt; get_rdwr     : unit -&amp;gt; Int63.&lt;span style=&quot;color: #060;&quot;&gt;t&lt;/span&gt; = &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;mylib_O_RDWR&amp;quot;&lt;/span&gt;     &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt;@@noalloc&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;external&lt;/span&gt; get_nonblock : unit -&amp;gt; Int63.&lt;span style=&quot;color: #060;&quot;&gt;t&lt;/span&gt; = &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;mylib_O_NONBLOCK&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt;@@noalloc&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;external&lt;/span&gt; get_append   : unit -&amp;gt; Int63.&lt;span style=&quot;color: #060;&quot;&gt;t&lt;/span&gt; = &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;mylib_O_APPEND&amp;quot;&lt;/span&gt;   &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt;@@noalloc&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;external&lt;/span&gt; get_creat    : unit -&amp;gt; Int63.&lt;span style=&quot;color: #060;&quot;&gt;t&lt;/span&gt; = &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;mylib_O_CREAT&amp;quot;&lt;/span&gt;    &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt;@@noalloc&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;external&lt;/span&gt; get_trunc    : unit -&amp;gt; Int63.&lt;span style=&quot;color: #060;&quot;&gt;t&lt;/span&gt; = &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;mylib_O_TRUNC&amp;quot;&lt;/span&gt;    &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt;@@noalloc&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;external&lt;/span&gt; get_excl     : unit -&amp;gt; Int63.&lt;span style=&quot;color: #060;&quot;&gt;t&lt;/span&gt; = &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;mylib_O_EXCL&amp;quot;&lt;/span&gt;     &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt;@@noalloc&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;external&lt;/span&gt; get_noctty   : unit -&amp;gt; Int63.&lt;span style=&quot;color: #060;&quot;&gt;t&lt;/span&gt; = &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;mylib_O_NOCTTY&amp;quot;&lt;/span&gt;   &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt;@@noalloc&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;external&lt;/span&gt; get_dsync    : unit -&amp;gt; Int63.&lt;span style=&quot;color: #060;&quot;&gt;t&lt;/span&gt; = &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;mylib_O_DSYNC&amp;quot;&lt;/span&gt;    &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt;@@noalloc&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;external&lt;/span&gt; get_sync     : unit -&amp;gt; Int63.&lt;span style=&quot;color: #060;&quot;&gt;t&lt;/span&gt; = &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;mylib_O_SYNC&amp;quot;&lt;/span&gt;     &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt;@@noalloc&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;external&lt;/span&gt; get_rsync    : unit -&amp;gt; Int63.&lt;span style=&quot;color: #060;&quot;&gt;t&lt;/span&gt; = &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;mylib_O_RSYNC&amp;quot;&lt;/span&gt;    &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt;@@noalloc&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; rdonly   = get_rdonly   &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; wronly   = get_wronly   &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; rdwr     = get_rdwr     &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; nonblock = get_nonblock &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; append   = get_append   &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; creat    = get_creat    &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; trunc    = get_trunc    &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; excl     = get_excl     &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; noctty   = get_noctty   &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; dsync    = get_dsync    &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; sync     = get_sync     &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; rsync    = get_rsync    &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;include&lt;/span&gt; Flags.&lt;span style=&quot;color: #060;&quot;&gt;Make&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;struct&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;      &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; known =&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt; rdonly   , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;rdonly&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; wronly   , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;wronly&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; rdwr     , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;rdwr&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; nonblock , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;nonblock&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; append   , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;append&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; creat    , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;creat&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; trunc    , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;trunc&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; excl     , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;excl&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; noctty   , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;noctty&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; dsync    , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;dsync&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; sync     , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;sync&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; rsync    , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;rsync&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;      &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; remove_zero_flags = &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;false&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;      &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; allow_intersecting = &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;false&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;      &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; should_print_error = &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;    &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #5d478b; font-style: italic;&quot;&gt;(*$*)&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/pre&gt;
&lt;p&gt;And cinaps will check that the text between the &lt;code&gt;(*$ ... *)&lt;/code&gt; and &lt;code&gt;(*$*)&lt;/code&gt; forms is what is printed by &lt;code&gt;flags_module &quot;Open_flags&quot; ...&lt;/code&gt;. I write something similar in the .c file. Note the initial &lt;code&gt;(*$ ... $*)&lt;/code&gt; form, which is not expected to print anything and is only used for its other side effects.&lt;/p&gt;
&lt;p&gt;Adding new flags become trivial: add it to the list in &lt;code&gt;src/cinaps_helper&lt;/code&gt; and execute &lt;code&gt;make cinaps&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Pushing the system&lt;/h2&gt;
&lt;p&gt;Now I decide that I don't like the fact that all my constant flags are initialized at runtime and I want them to be static constant on the ml side. A simple way to do this is to write a C program that include the right headers and output a .ml file defining these constants. I use cynaps to write this C file as well:&lt;/p&gt;
&lt;pre class=&quot;c&quot;&gt;&lt;ol&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #808080; font-style: italic;&quot;&gt;/*$ #use &amp;quot;cinaps_helpers&amp;quot; $*/&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #339933;&quot;&gt;#include &amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #339933;&quot;&gt;#include &amp;lt;sys/types.h&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #339933;&quot;&gt;#include &amp;lt;sys/stat.h&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #339933;&quot;&gt;#include &amp;lt;fcntl.h&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #993333;&quot;&gt;int&lt;/span&gt; main&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;a href=&quot;http://www.opengroup.org/onlinepubs/009695399/functions/printf.html&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;printf&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&amp;quot;open Core&lt;span style=&quot;color: #000099; font-weight: bold;&quot;&gt;\n&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;a href=&quot;http://www.opengroup.org/onlinepubs/009695399/functions/printf.html&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;printf&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&amp;quot;let mk = Int63.of_int_exn&lt;span style=&quot;color: #000099; font-weight: bold;&quot;&gt;\n&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #808080; font-style: italic;&quot;&gt;/*$&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #808080; font-style: italic;&quot;&gt;&amp;nbsp;   printf &amp;quot;\n&amp;quot;;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #808080; font-style: italic;&quot;&gt;&amp;nbsp;   let len = longest all_flags in&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #808080; font-style: italic;&quot;&gt;&amp;nbsp;   List.iter all_flags ~f:(fun f -&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #808080; font-style: italic;&quot;&gt;&amp;nbsp;     pr {|  printf(&amp;quot;let _%-*s = mk %%d\n&amp;quot;, %-*s);|} len f len f );&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #808080; font-style: italic;&quot;&gt;&amp;nbsp;   printf &amp;quot;  &amp;quot; */&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;a href=&quot;http://www.opengroup.org/onlinepubs/009695399/functions/printf.html&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;printf&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&amp;quot;let _O_RDONLY   = mk %d&lt;span style=&quot;color: #000099; font-weight: bold;&quot;&gt;\n&lt;/span&gt;&amp;quot;&lt;/span&gt;, O_RDONLY  &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;a href=&quot;http://www.opengroup.org/onlinepubs/009695399/functions/printf.html&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;printf&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&amp;quot;let _O_WRONLY   = mk %d&lt;span style=&quot;color: #000099; font-weight: bold;&quot;&gt;\n&lt;/span&gt;&amp;quot;&lt;/span&gt;, O_WRONLY  &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;a href=&quot;http://www.opengroup.org/onlinepubs/009695399/functions/printf.html&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;printf&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&amp;quot;let _O_RDWR     = mk %d&lt;span style=&quot;color: #000099; font-weight: bold;&quot;&gt;\n&lt;/span&gt;&amp;quot;&lt;/span&gt;, O_RDWR    &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;a href=&quot;http://www.opengroup.org/onlinepubs/009695399/functions/printf.html&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;printf&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&amp;quot;let _O_NONBLOCK = mk %d&lt;span style=&quot;color: #000099; font-weight: bold;&quot;&gt;\n&lt;/span&gt;&amp;quot;&lt;/span&gt;, O_NONBLOCK&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;a href=&quot;http://www.opengroup.org/onlinepubs/009695399/functions/printf.html&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;printf&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&amp;quot;let _O_APPEND   = mk %d&lt;span style=&quot;color: #000099; font-weight: bold;&quot;&gt;\n&lt;/span&gt;&amp;quot;&lt;/span&gt;, O_APPEND  &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;a href=&quot;http://www.opengroup.org/onlinepubs/009695399/functions/printf.html&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;printf&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&amp;quot;let _O_CREAT    = mk %d&lt;span style=&quot;color: #000099; font-weight: bold;&quot;&gt;\n&lt;/span&gt;&amp;quot;&lt;/span&gt;, O_CREAT   &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;a href=&quot;http://www.opengroup.org/onlinepubs/009695399/functions/printf.html&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;printf&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&amp;quot;let _O_TRUNC    = mk %d&lt;span style=&quot;color: #000099; font-weight: bold;&quot;&gt;\n&lt;/span&gt;&amp;quot;&lt;/span&gt;, O_TRUNC   &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;a href=&quot;http://www.opengroup.org/onlinepubs/009695399/functions/printf.html&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;printf&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&amp;quot;let _O_EXCL     = mk %d&lt;span style=&quot;color: #000099; font-weight: bold;&quot;&gt;\n&lt;/span&gt;&amp;quot;&lt;/span&gt;, O_EXCL    &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;a href=&quot;http://www.opengroup.org/onlinepubs/009695399/functions/printf.html&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;printf&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&amp;quot;let _O_NOCTTY   = mk %d&lt;span style=&quot;color: #000099; font-weight: bold;&quot;&gt;\n&lt;/span&gt;&amp;quot;&lt;/span&gt;, O_NOCTTY  &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;a href=&quot;http://www.opengroup.org/onlinepubs/009695399/functions/printf.html&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;printf&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&amp;quot;let _O_DSYNC    = mk %d&lt;span style=&quot;color: #000099; font-weight: bold;&quot;&gt;\n&lt;/span&gt;&amp;quot;&lt;/span&gt;, O_DSYNC   &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;a href=&quot;http://www.opengroup.org/onlinepubs/009695399/functions/printf.html&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;printf&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&amp;quot;let _O_SYNC     = mk %d&lt;span style=&quot;color: #000099; font-weight: bold;&quot;&gt;\n&lt;/span&gt;&amp;quot;&lt;/span&gt;, O_SYNC    &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;a href=&quot;http://www.opengroup.org/onlinepubs/009695399/functions/printf.html&quot;&gt;&lt;span style=&quot;color: #000066;&quot;&gt;printf&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&amp;quot;let _O_RSYNC    = mk %d&lt;span style=&quot;color: #000099; font-weight: bold;&quot;&gt;\n&lt;/span&gt;&amp;quot;&lt;/span&gt;, O_RSYNC   &lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #808080; font-style: italic;&quot;&gt;/*$*/&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #b1b100;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #cc66cc;&quot;&gt;0&lt;/span&gt;;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #66cc66;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/pre&gt;
&lt;p&gt;Updating the various flag modules in the the ml code is as simple as editing &lt;code&gt;src/cinaps_helpers&lt;/code&gt; and doing &lt;code&gt;make cinaps&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;ocaml&quot;&gt;&lt;ol&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #5d478b; font-style: italic;&quot;&gt;(*$ flags_module &amp;quot;Open_flags&amp;quot; open_flags ~prefix:&amp;quot;O_&amp;quot; ~allow_intersecting:false *)&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;module&lt;/span&gt; Open_flags = &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;struct&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; rdonly   = Consts._O_RDONLY&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; wronly   = Consts._O_WRONLY&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; rdwr     = Consts._O_RDWR&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; nonblock = Consts._O_NONBLOCK&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; append   = Consts._O_APPEND&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; creat    = Consts._O_CREAT&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; trunc    = Consts._O_TRUNC&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; excl     = Consts._O_EXCL&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; noctty   = Consts._O_NOCTTY&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; dsync    = Consts._O_DSYNC&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; sync     = Consts._O_SYNC&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; rsync    = Consts._O_RSYNC&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;include&lt;/span&gt; Flags.&lt;span style=&quot;color: #060;&quot;&gt;Make&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;struct&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;      &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; known =&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#91;&lt;/span&gt; Consts._O_RDONLY   , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;rdonly&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; Consts._O_WRONLY   , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;wronly&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; Consts._O_RDWR     , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;rdwr&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; Consts._O_NONBLOCK , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;nonblock&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; Consts._O_APPEND   , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;append&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; Consts._O_CREAT    , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;creat&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; Consts._O_TRUNC    , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;trunc&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; Consts._O_EXCL     , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;excl&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; Consts._O_NOCTTY   , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;noctty&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; Consts._O_DSYNC    , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;dsync&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; Consts._O_SYNC     , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;sync&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        ; Consts._O_RSYNC    , &lt;span style=&quot;color: #3cb371;&quot;&gt;&amp;quot;rsync&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;      &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; remove_zero_flags = &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;false&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;      &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; allow_intersecting = &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;false&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;      &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; should_print_error = &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;    &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #5d478b; font-style: italic;&quot;&gt;(*$*)&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/pre&gt;
&lt;h2&gt;Tweak: indenting the generated code&lt;/h2&gt;
&lt;p&gt;You can either write cinaps code that produce properly indented code, or you can use the styler option:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.PHONY: cinaps
cinaps:
    cinaps -styler ocp-indent -i src/*.ml src/*.c
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;History behind the name&lt;/h1&gt;
&lt;p&gt;I initially wrote this tool while I did some work on the &lt;a href=&quot;https://github.com/let-def/ocaml-migrate-parsetree&quot;&gt;ocaml-migrate-parsetree&lt;/a&gt; project. ocaml-migrate-parsetree was started by Alain Frisch and continued by Frederic Bour and aims at providing a solid and stable base for authors of ppx rewriters or other tools using the OCaml frontend. I helped a bit during development and did some testing on a large scale while rebasing our ppx infrastructure on top it.&lt;/p&gt;
&lt;p&gt;Due to its nature, this project contains a lot of repetitive code that cannot be factorized other than by using some kind of meta-programming. Initially we had a small pre-preprocessor that was interpreting a made-up syntax and was working like cpp does. The syntax was yet another DSL and the generated code was generated on the fly. This made the .ml and .mli files harder to understand since you had to decode this DSL in order to understand what the code was.&lt;/p&gt;
&lt;p&gt;Cinaps replaced this tool and the name was chosen to emphasize that it is not a preprocessor. It means &quot;Cinaps Is Not A Preprocessing System&quot;.&lt;/p&gt;
&lt;h1&gt;Status&lt;/h1&gt;
&lt;p&gt;Cinaps is published on github and is part of the upcoming v0.9 Jane Street release. The version that is published doesn't yet support the C/S-expression syntaxes but once the stable release has gone through, an updated version of Cinaps supporting these syntaxes will be released.&lt;/p&gt;
</content><category scheme="https://blogs.janestreet.com" term="OCaml"/><id>https://blogs.janestreet.com/?p=1711</id><title xml:base="https://blogs.janestreet.com/wp-atom.php" type="html">Trivial meta-programming with cinaps</title><updated>2017-03-20T20:39:29-00:00</updated><author><name>Jeremie Dimino</name></author></entry><entry><source><updated>2017-05-11T13:20:05-00:00</updated><logo>http://www.ocamlpro.com/wp-content/uploads/2016/02/cropped-favicon-32x32.png</logo><link title="OCamlPro" type="text/html" href="http://www.ocamlpro.com" rel="related"/><link title="OCamlPro" type="application/rss+xml" href="http://www.ocamlpro.com/feed/" rel="self"/><generator>https://wordpress.org/?v=4.7.4</generator><id>http://www.ocamlpro.com</id><title type="text">OCamlPro</title><author><name>OCamlPro</name></author></source><link href="http://www.ocamlpro.com/2017/03/16/new-opam-features-opam-build/" rel="alternate"/><link href="http://www.ocamlpro.com/2017/03/16/new-opam-features-opam-build/#comments" rel="related"/><content xml:base="http://www.ocamlpro.com/feed/" type="html">&lt;p&gt;The new opam 2.0 release, currently in beta, introduces several new features. This post gets into some detail on the new &lt;code&gt;opam build&lt;/code&gt; command, its purpose, its use, and some implementation aspects.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;opam build&lt;/code&gt; is run from the source tree of a project, and does not rely on a pre-existing opam installation.&lt;/strong&gt; As such, it adds a new option besides the existing workflows based on managing shared OCaml installations in the form of switches.&lt;/p&gt;
&lt;h3 id=&quot;Whatdoesitdo&quot;&gt;What does it do ?&lt;/h3&gt;
&lt;p&gt;Typically, this is used in a fresh git clone of some OCaml project. Like when pinning the package, opam will find and leverage package definitions found in the source, in the form of &lt;code&gt;opam&lt;/code&gt; files.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;if opam hasn&amp;#8217;t been initialised (no &lt;code&gt;~/.opam&lt;/code&gt;), this is taken care of.&lt;/li&gt;
&lt;li&gt;if no switch is otherwise explicitely selected, a &lt;em&gt;local switch&lt;/em&gt; is used, and&lt;br /&gt;
created if necessary (&lt;em&gt;i.e.&lt;/em&gt; in &lt;code&gt;./_opam/&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;the metadata for the current project is registered, and the package installed&lt;br /&gt;
after its dependencies, as opam usually does&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is particularly useful for &lt;strong&gt;distributing projects&lt;/strong&gt; to people not used to opam and the OCaml ecosystem: the setup steps are automatically taken care of, and a single &lt;code&gt;opam build&lt;/code&gt; invocation can take care of resolving the dependency chains for your package.&lt;/p&gt;
&lt;p&gt;If building the project directly is preferred, adding &lt;code&gt;--deps-only&lt;/code&gt; is a good way to get the dependencies ready for the project:&lt;/p&gt;
&lt;pre class=&quot;brush: bash; title: ; notranslate&quot;&gt;
  $ opam build --deps-only
  $ eval $(opam config env)
  $ ./configure; make; etc.
&lt;/pre&gt;
&lt;p&gt;Note that if you just want to handle project-local opam files, &lt;code&gt;opam build&lt;/code&gt; can also be used in your existing switches: just specify &lt;code&gt;--no-autoinit&lt;/code&gt;, &lt;code&gt;--switch&lt;/code&gt; or make sure the &lt;code&gt;OPAMSWITCH&lt;/code&gt; variable is set. &lt;em&gt;E.g.&lt;/em&gt; &lt;code&gt;opam build --no-autoinit --deps-only&lt;/code&gt; is a convenient way to get the dependencies for the local project ready in your current switch.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;Additionalfunctions&quot;&gt;Additional functions&lt;/h3&gt;
&lt;h4 id=&quot;Installation&quot;&gt;Installation&lt;/h4&gt;
&lt;p&gt;The installation of the packages happens as usual to the prefix corresponding to the switch used (&lt;code&gt;&amp;lt;project-root&amp;gt;/_opam/&lt;/code&gt; for a local switch). But it is possible, with &lt;code&gt;--install-prefix&lt;/code&gt;, to further install the package to the system:&lt;/p&gt;
&lt;pre class=&quot;brush: bash; title: ; notranslate&quot;&gt;
opam build --install-prefix ~/local
&lt;/pre&gt;
&lt;p&gt;will install the results of the package found in the current directory below ~/local.&lt;/p&gt;
&lt;p&gt;The dependencies of the package won&amp;#8217;t be installed, so this is intended for programs, assuming they are relocatable, and not for libraries.&lt;/p&gt;
&lt;h4 id=&quot;Choosingcustomrepositories&quot;&gt;Choosing custom repositories&lt;/h4&gt;
&lt;p&gt;The user can pre-select the repositories to use on the creation of the local switch with:&lt;/p&gt;
&lt;pre class=&quot;brush: bash; title: ; notranslate&quot;&gt;
  opam build --repositories &amp;lt;repos&amp;gt;
&lt;/pre&gt;
&lt;p&gt;where &lt;code&gt;&amp;lt;repos&amp;gt;&lt;/code&gt; is a comma-separated list of repositories, specified either as &lt;code&gt;name=URL&lt;/code&gt;, or &lt;code&gt;name&lt;/code&gt; if already configured on the system.&lt;/p&gt;
&lt;h4 id=&quot;Multiplepackages&quot;&gt;Multiple packages&lt;/h4&gt;
&lt;p&gt;Multiple packages are commonly found to share a single repository. In this case, &lt;code&gt;opam build&lt;/code&gt; registers and builds all of them, respecting cross-dependencies. The opam files to use can also be explicitely selected on the command-line. In this case, specific opam files must be named &lt;code&gt;&amp;lt;package-name&amp;gt;.opam&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;Implementationdetails&quot;&gt;Implementation details&lt;/h3&gt;
&lt;p&gt;The choice of the compiler, on automatic initialisation, is either explicit, using the &lt;code&gt;--compiler&lt;/code&gt; option, or automatic. In the latter case, the default selection is used (see &lt;code&gt;opam init --help&lt;/code&gt;, section &amp;#8220;CONFIGURATION FILE&amp;#8221; for details), but a compiler compatible with the local packages found is searched from that. This allows, for example, to choose a system compiler when available and compatible, avoiding a recompilation of OCaml.&lt;/p&gt;
&lt;p&gt;When using &lt;code&gt;--install-prefix&lt;/code&gt;, the normal installation is done, then the tracking of package-installed files, introduced in opam 2.0, is used to extract the installed files from the switch and copy them to the prefix.&lt;/p&gt;
&lt;p&gt;The packages installed through &lt;code&gt;opam build&lt;/code&gt; are not registered in any repository, and this is not an implicit use of &lt;code&gt;opam pin&lt;/code&gt;: the rationale is that packages installed this way will also be updated by repeating &lt;code&gt;opam build&lt;/code&gt;. This means that when using other commands, &lt;em&gt;e.g.&lt;/em&gt; &lt;code&gt;opam upgrade&lt;/code&gt;, opam won&amp;#8217;t try to keep the packages to their local, source version, and will either revert them to their repository definition, or remove them, if they need recompilation.&lt;/p&gt;
&lt;h3 id=&quot;Plannedextensions&quot;&gt;Planned extensions&lt;/h3&gt;
&lt;p&gt;This is still in beta: there are still rough edges, please experiment and give feedback! It is still possible that the command syntax and semantics change significantly before release.&lt;/p&gt;
&lt;p&gt;Another use-case that we are striving to improve is sharing of development setups (share sets of pinned packages, depend on specific remotes or git hashes, etc.). We have &lt;a href=&quot;https://github.com/ocaml/opam/issues/2762&quot;&gt;many &lt;/a&gt;&lt;a href=&quot;https://github.com/ocaml/opam/issues/2495&quot;&gt;ideas&lt;/a&gt; to &lt;a href=&quot;https://github.com/ocaml/opam/issues/1734&quot;&gt;improve&lt;/a&gt; on this, but &lt;code&gt;opam build &lt;/code&gt;is not, as of today, a direct solution to this. In particular, installing this way still relies on the default opam repository; a way to define specific options for the switch that is implicitely created on &lt;code&gt;opam build&lt;/code&gt; is in the works.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;NOTE: this article is cross-posted on &lt;a href=&quot;https://opam.ocaml.org/blog/&quot;&gt;opam.ocaml.org&lt;/a&gt; and &lt;a href=&quot;http://www.ocamlpro.com/category/blog/&quot;&gt;ocamlpro.com&lt;/a&gt;. Please head to the latter for the comments!&lt;/p&gt;&lt;/blockquote&gt;
</content><category term="opam build"/><id>http://www.ocamlpro.com/?p=571</id><title type="text">New opam features: “opam build”</title><updated>2017-03-16T09:51:26-00:00</updated><author><name>OCamlPro</name></author></entry><entry><summary xml:base="https://blogs.janestreet.com/wp-atom.php" type="html">&lt;p&gt;I'm happy to announce our next &lt;a href=&quot;https://events.janestreet.com/home/tech-talks/&quot;&gt;public tech talk&lt;/a&gt;, called &lt;strong&gt;Seven Implementations of Incremental&lt;/strong&gt;, on Wednesday, April 5th, presented by yours truly. You can register &lt;a href=&quot;https://docs.google.com/forms/d/e/1FAIpQLSdtly4y-jYcLUVH8BJS-uKoiaKrQlRXSIWZeczw3tgwTx_6HA/viewform?c=0&amp;#38;w=1&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The talk covers the history of &lt;a href=&quot;https://github.com/janestreet/incremental&quot;&gt;Incremental&lt;/a&gt;, a library for building efficient online algorithms.  The need to update computations incrementally is pretty common, and we've found Incremental to be useful in creating such computations in a number of different domains, from constructing efficient financial calculations to writing responsive, data-rich web UIs.&lt;/p&gt;
&lt;p&gt;The ideas behind Incremental aren't new with us; there is a lot of prior art, most notably the work from &lt;a href=&quot;http://www.umut-acar.org/self-adjusting-computation&quot;&gt;Umut Acar's work&lt;/a&gt; on &lt;em&gt;self-adjusting computations&lt;/em&gt;, on which Incremental is most directly modeled.&lt;/p&gt; &lt;a href=&quot;https://blogs.janestreet.com/one-more-talk-two-more-videos/&quot;&gt;&amp;#187; Continue Reading.&lt;/a&gt;</summary><source><updated>2017-05-11T19:02:45-00:00</updated><subtitle type="text">Jane Street' blogs (Systems and OCaml rolled into one)</subtitle><link type="application/atom+xml" href="https://blogs.janestreet.com/category/ocaml/feed/atom/" rel="self"/><link type="text/html" href="https://blogs.janestreet.com" rel="alternate"/><generator uri="https://wordpress.org/" version="4.7.4">WordPress</generator><id>https://blogs.janestreet.com/feed/atom/</id><title type="text">OCaml – Jane Street Tech Blogs</title><author><name>Jane Street</name></author></source><published>2017-03-15T18:10:02-00:00</published><link type="application/atom+xml" href="https://blogs.janestreet.com/one-more-talk-two-more-videos/feed/atom/" rel="replies"/><link type="text/html" href="https://blogs.janestreet.com/one-more-talk-two-more-videos/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=one-more-talk-two-more-videos#comments" rel="replies"/><link type="text/html" href="https://blogs.janestreet.com/one-more-talk-two-more-videos/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=one-more-talk-two-more-videos" rel="alternate"/><content xml:base="https://blogs.janestreet.com/wp-atom.php" type="html">&lt;p&gt;I'm happy to announce our next &lt;a href=&quot;https://events.janestreet.com/home/tech-talks/&quot;&gt;public tech talk&lt;/a&gt;, called &lt;strong&gt;Seven Implementations of Incremental&lt;/strong&gt;, on Wednesday, April 5th, presented by yours truly. You can register &lt;a href=&quot;https://docs.google.com/forms/d/e/1FAIpQLSdtly4y-jYcLUVH8BJS-uKoiaKrQlRXSIWZeczw3tgwTx_6HA/viewform?c=0&amp;amp;w=1&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The talk covers the history of &lt;a href=&quot;https://github.com/janestreet/incremental&quot;&gt;Incremental&lt;/a&gt;, a library for building efficient online algorithms.  The need to update computations incrementally is pretty common, and we've found Incremental to be useful in creating such computations in a number of different domains, from constructing efficient financial calculations to writing responsive, data-rich web UIs.&lt;/p&gt;
&lt;p&gt;The ideas behind Incremental aren't new with us; there is a lot of prior art, most notably the work from &lt;a href=&quot;http://www.umut-acar.org/self-adjusting-computation&quot;&gt;Umut Acar's work&lt;/a&gt; on &lt;em&gt;self-adjusting computations&lt;/em&gt;, on which Incremental is most directly modeled.&lt;/p&gt;
&lt;p&gt;But there's a big gap between the academic version of an idea and a production ready instantiation, and this talk is about crossing that gap. It discusses the 7 different implementations we went through and the various mistakes we made along the way towards the current one we use in production.&lt;/p&gt;
&lt;p&gt;So join us. I hope you enjoy seeing what we learned about building this kind of system, as well as hearing about the hilarious pratfalls along the way.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;On another note, we have finally posted videos from our two previous talks, including Brian Nigito's talk on the &lt;a href=&quot;https://www.youtube.com/watch?v=b1e4t2k2KJY&amp;amp;t=6s&quot;&gt;architecture of the modern exchange&lt;/a&gt;, and Arjun Guha's talk on &lt;a href=&quot;https://www.youtube.com/watch?v=sjJxirqwXSE&quot;&gt;taming Puppet&lt;/a&gt;. And, of course, you can subscribe to our &lt;a href=&quot;https://www.youtube.com/channel/UCDsVC_ewpcEW_AQcO-H-RDQ&quot;&gt;channel&lt;/a&gt; while you're there.&lt;/p&gt;
</content><category scheme="https://blogs.janestreet.com" term="OCaml"/><id>https://blogs.janestreet.com/?p=1702</id><title xml:base="https://blogs.janestreet.com/wp-atom.php" type="html">One more talk, two more videos</title><updated>2017-03-15T18:10:02-00:00</updated><author><name>Yaron Minsky</name></author></entry><entry><source><updated>2017-05-09T12:00:00-00:00</updated><link title="OCaml Weekly News" type="text/html" href="http://alan.petitepomme.net/cwn/" rel="related"/><link title="OCaml Weekly News" type="application/rss+xml" href="http://alan.petitepomme.net/cwn/cwn.rss" rel="self"/><id>http://alan.petitepomme.net/cwn/</id><title type="text">OCaml Weekly News</title><author><name>OCaml Weekly News</name></author></source><link href="http://alan.petitepomme.net/cwn/2017.03.14.html" rel="alternate"/><content xml:base="http://alan.petitepomme.net/cwn/cwn.rss" type="html">&lt;ol&gt;&lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.03.14.html#1&gt;libbin_prot, php-bin_prot, ppx_bin_prot_interop&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.03.14.html#2&gt;Jbuilder 1.0+beta1&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.03.14.html#3&gt;ocamlbuild 0.11.0&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.03.14.html#4&gt;New release of visitors&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.03.14.html#5&gt;Ocaml Github Pull Requests&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.03.14.html#6&gt;Other OCaml News&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;</content><id>http://alan.petitepomme.net/cwn/2017.03.14.html</id><title type="text">Weekly News</title><updated>2017-03-14T12:00:00-00:00</updated><author><name>OCaml Weekly News</name></author></entry><entry><source><updated>2017-03-14T08:00:00-00:00</updated><logo>http://gallium.inria.fr/blog/</logo><link title="Gagallium" type="text/html" href="http://gallium.inria.fr/blog/index.rss" rel="related"/><link title="Gagallium" type="application/rss+xml" href="http://gallium.inria.fr/blog/index.rss" rel="self"/><generator>Stog</generator><id>http://gallium.inria.fr/blog/index.rss</id><title type="text">Gagallium</title><author><name>GaGallium</name></author></source><link href="http://gallium.inria.fr/blog/from-visitors-to-iterators/index.html" rel="alternate"/><content xml:base="http://gallium.inria.fr/blog/index.rss" type="html">
&lt;p&gt;I have been asked whether
an automatically-generated visitor,
as produced by the &lt;a href=&quot;https://gitlab.inria.fr/fpottier/visitors&quot;&gt;visitors&lt;/a&gt;
syntax extension for OCaml,
can be used to construct an iterator.&lt;/p&gt;

&lt;p&gt;It turns out that this can be done
in a simple and efficient manner.
(Up to a constant factor, the time complexity of this solution is optimal.)
As the problem is interesting and
its solution is somewhat nonobvious,
I am describing them here.&lt;/p&gt;




&lt;p&gt;To play with this code in an OCaml toplevel, first install &lt;code&gt;visitors&lt;/code&gt; via the command &lt;code&gt;opam install visitors&lt;/code&gt;. Then, launch &lt;code&gt;ocaml&lt;/code&gt; and type this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#use &amp;quot;topfind&amp;quot;;;
#require &amp;quot;visitors.ppx&amp;quot;;;
#require &amp;quot;visitors.runtime&amp;quot;;;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;problem-statement&quot;&gt;Problem Statement&lt;/h2&gt;
&lt;p&gt;Suppose we have an arbitrary data structure that contains elements of type &lt;code&gt;'a&lt;/code&gt;. Here, it is a binary tree, but it could be anything:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot;&gt;&lt;pre class=&quot;sourceCode ocaml&quot;&gt;&lt;code class=&quot;sourceCode ocaml&quot;&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; 'a sometree =
  | Leaf
  | Node &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt; 'a sometree * 'a * 'a sometree&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We would like to enumerate the elements of this data structure. More precisely, we would like to construct an iterator, that is, an on-demand producer of elements. Here is a simple definition of a stateful iterator:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot;&gt;&lt;pre class=&quot;sourceCode ocaml&quot;&gt;&lt;code class=&quot;sourceCode ocaml&quot;&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; 'a iterator =
  &lt;span class=&quot;dt&quot;&gt;unit&lt;/span&gt; -&amp;gt; 'a &lt;span class=&quot;dt&quot;&gt;option&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The question is, can we construct an iterator for the type &lt;code&gt;'a sometree&lt;/code&gt;, based on an automatically-generated visitor, so that the construction is entirely independent of the type &lt;code&gt;'a sometree&lt;/code&gt;?&lt;/p&gt;
&lt;h2 id=&quot;cascades&quot;&gt;Cascades&lt;/h2&gt;
&lt;p&gt;For starters, let us define cascades, which are a more pleasant kind of iterators. A cascade is a persistent (stateless) iterator. It can be thought of as a delayed list, that is, a list whose elements are computed only on demand.&lt;/p&gt;
&lt;p&gt;Cascades could (should) be part of a separate library. As the time of writing (March, 2017), there is in fact &lt;a href=&quot;https://github.com/ocaml/ocaml/pull/1002&quot;&gt;a proposal&lt;/a&gt; to add them to OCaml's standard library.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot;&gt;&lt;pre class=&quot;sourceCode ocaml&quot;&gt;&lt;code class=&quot;sourceCode ocaml&quot;&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; 'a cascade =
  &lt;span class=&quot;dt&quot;&gt;unit&lt;/span&gt; -&amp;gt; 'a head

&lt;span class=&quot;kw&quot;&gt;and&lt;/span&gt; 'a head =
  | Nil
  | Cons &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt; 'a * 'a cascade&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A delayed computation is represented as a function of type &lt;code&gt;unit -&amp;gt; _&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The cascade constructors are as follows:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot;&gt;&lt;pre class=&quot;sourceCode ocaml&quot;&gt;&lt;code class=&quot;sourceCode ocaml&quot;&gt;&lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; nil : 'a cascade =
  &lt;span class=&quot;kw&quot;&gt;fun&lt;/span&gt; () -&amp;gt; Nil

&lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; cons (x : 'a) (xs : 'a cascade) : 'a cascade =
  &lt;span class=&quot;kw&quot;&gt;fun&lt;/span&gt; () -&amp;gt; Cons (x, xs)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Forcing a cascade reveals its head:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot;&gt;&lt;pre class=&quot;sourceCode ocaml&quot;&gt;&lt;code class=&quot;sourceCode ocaml&quot;&gt;&lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; force xs =
  xs()&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A cascade can be easily converted to a stateful iterator:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot;&gt;&lt;pre class=&quot;sourceCode ocaml&quot;&gt;&lt;code class=&quot;sourceCode ocaml&quot;&gt;&lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; cascade_to_iterator (xs : 'a cascade) : 'a iterator =
  &lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; s = &lt;span class=&quot;dt&quot;&gt;ref&lt;/span&gt; xs &lt;span class=&quot;kw&quot;&gt;in&lt;/span&gt;
  &lt;span class=&quot;kw&quot;&gt;fun&lt;/span&gt; () -&amp;gt;
    &lt;span class=&quot;kw&quot;&gt;match&lt;/span&gt; force !s &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt;
    | Nil -&amp;gt;
        s := nil;
        &lt;span class=&quot;dt&quot;&gt;None&lt;/span&gt;
    | Cons (x, xs) -&amp;gt;
        s := xs;
        &lt;span class=&quot;dt&quot;&gt;Some&lt;/span&gt; x&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In the above code, writing &lt;code&gt;nil&lt;/code&gt; into &lt;code&gt;s&lt;/code&gt; may seem superfluous, but is in fact necessary to guarantee that the computation that led to a &lt;code&gt;Nil&lt;/code&gt; outcome is not repeated in the future.&lt;/p&gt;
&lt;p&gt;Because cascades are close cousins of lists, they are easy to work with. Constructing a cascade for a tree-like data structure is straightforward, whereas directly constructing a stateful iterator would be more involved.&lt;/p&gt;
&lt;h2 id=&quot;back-to-the-problem&quot;&gt;Back to the problem&lt;/h2&gt;
&lt;p&gt;Now, can we use some kind of visitor to turn a tree of type &lt;code&gt;'a sometree&lt;/code&gt; into a cascade of type &lt;code&gt;'a cascade&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;At first sight, this does not seem very easy, because of two issues:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;a visitor usually traverses a tree in an eager manner, whereas we need the traversal to make progress only as cascade elements are demanded;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;a visitor performs a bottom-up computation, without a left-to-right bias (assuming mutable state is not used), whereas a cascade enumerates elements in a left-to-right manner. (Or in a right-to-left manner. As will be apparent below, both directions are possible.)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The trick is to use another intermediate step. Instead of turning a tree directly into a cascade, we first transform it into a generic tree-like structure: a &lt;em&gt;delayed tree&lt;/em&gt;. The first issue above is solved because, by introducing delays into the new tree, we allow its construction to be carried out on demand. The second issue is solved because this tree-to-tree transformation can be carried out in a purely bottom-up manner by a &lt;code&gt;reduce&lt;/code&gt; visitor. Then, finally, it is straightforward to transform a delayed tree into a cascade.&lt;/p&gt;
&lt;h2 id=&quot;from-delayed-trees-to-cascades-and-iterators&quot;&gt;From Delayed Trees to Cascades and Iterators&lt;/h2&gt;
&lt;p&gt;A delayed tree contains ordinary nodes of arity 0, 1, and 2. Furthermore, it contains &lt;code&gt;DTDelay&lt;/code&gt; nodes, of arity 1, whose child is delayed, that is, computed only on demand.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot;&gt;&lt;pre class=&quot;sourceCode ocaml&quot;&gt;&lt;code class=&quot;sourceCode ocaml&quot;&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; 'a delayed_tree =
  | DTZero
  | DTOne &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt; 'a
  | DTTwo &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt; 'a delayed_tree * 'a delayed_tree
  | DTDelay &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;unit&lt;/span&gt; -&amp;gt; 'a delayed_tree)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A delayed tree is converted to a cascade as follows. As is often the case, when building a cascade, one must take a continuation &lt;code&gt;k&lt;/code&gt; as an argument, so as to avoid naive and costly cascade concatenation operations. Thus, the specification of the function call &lt;code&gt;delayed_tree_to_cascade dt k&lt;/code&gt; is to construct a cascade whose elements are the elements of the delayed tree &lt;code&gt;dt&lt;/code&gt; (listed from left to right), followed with the elements of the cascade &lt;code&gt;k&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot;&gt;&lt;pre class=&quot;sourceCode ocaml&quot;&gt;&lt;code class=&quot;sourceCode ocaml&quot;&gt;&lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;rec&lt;/span&gt; delayed_tree_to_cascade (dt : 'a delayed_tree) (k : 'a cascade)
: 'a cascade =
  &lt;span class=&quot;kw&quot;&gt;fun&lt;/span&gt; () -&amp;gt; delayed_tree_to_head dt k

&lt;span class=&quot;kw&quot;&gt;and&lt;/span&gt; delayed_tree_to_head (dt : 'a delayed_tree) (k : 'a cascade) : 'a head =
  &lt;span class=&quot;kw&quot;&gt;match&lt;/span&gt; dt &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt;
  | DTZero -&amp;gt;
      force k
  | DTOne x -&amp;gt;
      Cons (x, k)
  | DTTwo (dt1, dt2) -&amp;gt;
      delayed_tree_to_head dt1 (delayed_tree_to_cascade dt2 k)
  | DTDelay dt -&amp;gt;
      delayed_tree_to_head (force dt) k

&lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; delayed_tree_to_cascade (dt : 'a delayed_tree) : 'a cascade =
  delayed_tree_to_cascade dt nil

&lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; delayed_tree_to_iterator (dt : 'a delayed_tree) : 'a iterator =
  cascade_to_iterator (delayed_tree_to_cascade dt)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In the above code, we have chosen to perform a left-to-right traversal of the delayed tree, but could just as well have chosen a right-to-left traversal.&lt;/p&gt;
&lt;p&gt;It is possible to make the delayed tree data structure implicit in the code; this is explained &lt;a href=&quot;#variant-getting-rid-of-explicit-delayed-trees&quot;&gt;further on&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;constructing-delayed-trees&quot;&gt;Constructing Delayed Trees&lt;/h2&gt;
&lt;p&gt;The type &lt;code&gt;'a delay&lt;/code&gt; is a synonym for &lt;code&gt;'a&lt;/code&gt;. We will use it as a decoration, in a type definition, to indicate that a call to the method &lt;code&gt;visit_delay&lt;/code&gt; is desired.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot;&gt;&lt;pre class=&quot;sourceCode ocaml&quot;&gt;&lt;code class=&quot;sourceCode ocaml&quot;&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; 'a delay = 'a&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We now set up four constructor functions or constructor methods, which construct delayed trees, and which we will use in a &lt;code&gt;reduce&lt;/code&gt; visitor.&lt;/p&gt;
&lt;p&gt;Delayed trees form a monoid, in the sense that we concatenate them using &lt;code&gt;DTTwo&lt;/code&gt;, and the neutral element is &lt;code&gt;DTZero&lt;/code&gt;. We package these two data constructors in the methods &lt;code&gt;zero&lt;/code&gt; and &lt;code&gt;plus&lt;/code&gt;, which are automatically called in an automatically-generated &lt;code&gt;reduce&lt;/code&gt; visitor.&lt;/p&gt;
&lt;p&gt;The visitor method &lt;code&gt;visit_delay&lt;/code&gt; delays the visit of a subtree by constructing and returning a &lt;code&gt;DTDelay&lt;/code&gt; node, which carries a delayed recursive call to a visitor.&lt;/p&gt;
&lt;p&gt;The visitor function &lt;code&gt;yield&lt;/code&gt; will be invoked at elements of type &lt;code&gt;'a&lt;/code&gt;. It constructs a one-element delayed tree.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot;&gt;&lt;pre class=&quot;sourceCode ocaml&quot;&gt;&lt;code class=&quot;sourceCode ocaml&quot;&gt;&lt;span class=&quot;kw&quot;&gt;class&lt;/span&gt; ['self] delayed_tree_monoid = &lt;span class=&quot;kw&quot;&gt;object&lt;/span&gt; (_ : 'self)

  &lt;span class=&quot;kw&quot;&gt;method&lt;/span&gt; zero =
    DTZero

  &lt;span class=&quot;kw&quot;&gt;method&lt;/span&gt; plus s1 s2 =
    &lt;span class=&quot;kw&quot;&gt;match&lt;/span&gt; s1, s2 &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt;
    | DTZero, s
    | s, DTZero -&amp;gt;
        s
    | _, _ -&amp;gt;
        DTTwo (s1, s2)

  &lt;span class=&quot;kw&quot;&gt;method&lt;/span&gt; visit_delay: 'env 'a .
    ('env -&amp;gt; 'a -&amp;gt; 'b delayed_tree) -&amp;gt;
    'env -&amp;gt; 'a delay -&amp;gt; 'b delayed_tree
  = &lt;span class=&quot;kw&quot;&gt;fun&lt;/span&gt; visit_'a env x -&amp;gt;
      DTDelay (&lt;span class=&quot;kw&quot;&gt;fun&lt;/span&gt; () -&amp;gt; visit_'a env x)

&lt;span class=&quot;kw&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; yield _env x =
  DTOne x&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In the method &lt;code&gt;plus&lt;/code&gt;, above, treating &lt;code&gt;DTZero&lt;/code&gt; specially is not mandatory. It is an optimization, which helps allocate fewer nodes.&lt;/p&gt;
&lt;h2 id=&quot;generating-a-visitor&quot;&gt;Generating a Visitor&lt;/h2&gt;
&lt;p&gt;It is now time to generate a &lt;code&gt;reduce&lt;/code&gt; visitor for the type &lt;code&gt;'a sometree&lt;/code&gt;. This is the only part of the code which is specific of &lt;code&gt;sometree&lt;/code&gt;. Everything else is generic.&lt;/p&gt;
&lt;p&gt;We must insert &lt;em&gt;delays&lt;/em&gt; into the structure of the type &lt;code&gt;'a sometree&lt;/code&gt; so as to indicate where &lt;code&gt;visit_delay&lt;/code&gt; should be called and (therefore) where &lt;code&gt;DTDelay&lt;/code&gt; nodes should be allocated. To do this, we write a copy of the definition of the type &lt;code&gt;'a sometree&lt;/code&gt;, with extra uses of &lt;code&gt;delay&lt;/code&gt; in it. The new type is actually considered equal to &lt;code&gt;'a sometree&lt;/code&gt; by OCaml. Its role is purely to carry a &lt;code&gt;@@deriving visitors&lt;/code&gt; annotation.&lt;/p&gt;
&lt;p&gt;In the data constructor &lt;code&gt;Node&lt;/code&gt;, the left-hand &lt;code&gt;delay&lt;/code&gt; is in fact superfluous. With or without it, our iterators will eagerly descend along the leftmost branch of a tree, anyway.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot;&gt;&lt;pre class=&quot;sourceCode ocaml&quot;&gt;&lt;code class=&quot;sourceCode ocaml&quot;&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; 'a mytree = 'a sometree =
  | Leaf
  | Node &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt; 'a mytree delay * 'a * 'a mytree delay

&lt;span class=&quot;kw&quot;&gt;and&lt;/span&gt; 'a mytree_delay =
  'a mytree delay

[@@deriving visitors { variety = &lt;span class=&quot;st&quot;&gt;&amp;quot;reduce&amp;quot;&lt;/span&gt;; polymorphic = &lt;span class=&quot;kw&quot;&gt;true&lt;/span&gt;;
                       concrete = &lt;span class=&quot;kw&quot;&gt;true&lt;/span&gt;; ancestors = [&lt;span class=&quot;st&quot;&gt;&amp;quot;delayed_tree_monoid&amp;quot;&lt;/span&gt;] }]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This approach is pleasant insofar as one controls exactly where delays are inserted. However, it requires copying the type definition, which may be unpleasant. Another approach is described &lt;a href=&quot;#variant-avoiding-duplication-of-the-type-definition&quot;&gt;further on&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;using-the-generated-visitor&quot;&gt;Using the Generated Visitor&lt;/h2&gt;
&lt;p&gt;For demonstration purposes, let us make our visitor verbose. In production, one should remove &lt;code&gt;verbose_reduce&lt;/code&gt; and use &lt;code&gt;reduce&lt;/code&gt; instead.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot;&gt;&lt;pre class=&quot;sourceCode ocaml&quot;&gt;&lt;code class=&quot;sourceCode ocaml&quot;&gt;&lt;span class=&quot;kw&quot;&gt;class&lt;/span&gt; ['self] verbose_reduce = &lt;span class=&quot;kw&quot;&gt;object&lt;/span&gt; (_ : 'self)
  &lt;span class=&quot;kw&quot;&gt;inherit&lt;/span&gt; [_] reduce &lt;span class=&quot;kw&quot;&gt;as&lt;/span&gt; super
  &lt;span class=&quot;kw&quot;&gt;method&lt;/span&gt;! visit_Leaf visit_'a env =
    &lt;span class=&quot;dt&quot;&gt;Printf&lt;/span&gt;.printf &lt;span class=&quot;st&quot;&gt;&amp;quot;Visiting a leaf.&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;%!&amp;quot;&lt;/span&gt;;
    super#visit_Leaf visit_'a env
  &lt;span class=&quot;kw&quot;&gt;method&lt;/span&gt;! visit_Node visit_'a env t1 x t2 =
    &lt;span class=&quot;dt&quot;&gt;Printf&lt;/span&gt;.printf &lt;span class=&quot;st&quot;&gt;&amp;quot;Visiting a node.&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;%!&amp;quot;&lt;/span&gt;;
    super#visit_Node visit_'a env t1 x t2
&lt;span class=&quot;kw&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The problem is solved! There remains to write a couple lines of glue code:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot;&gt;&lt;pre class=&quot;sourceCode ocaml&quot;&gt;&lt;code class=&quot;sourceCode ocaml&quot;&gt;&lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; sometree_to_delayed_tree (t : 'a sometree) =
  &lt;span class=&quot;kw&quot;&gt;new&lt;/span&gt; verbose_reduce # visit_mytree_delay yield () t

&lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; sometree_to_iterator (t : 'a sometree) : 'a iterator =
  delayed_tree_to_iterator (sometree_to_delayed_tree t)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We use &lt;code&gt;visit_mytree_delay&lt;/code&gt; above, even though &lt;code&gt;visit_mytree&lt;/code&gt; would work just as well, so as to ensure that we get a delayed tree whose root is a &lt;code&gt;DTDelay&lt;/code&gt; node. Thus, absolutely no work is performed when the iterator is created; iteration begins only when the first element is demanded.&lt;/p&gt;
&lt;h2 id=&quot;demo&quot;&gt;Demo&lt;/h2&gt;
&lt;p&gt;A little demo helps see what is going on.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot;&gt;&lt;pre class=&quot;sourceCode ocaml&quot;&gt;&lt;code class=&quot;sourceCode ocaml&quot;&gt;&lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; t : &lt;span class=&quot;dt&quot;&gt;int&lt;/span&gt; sometree =
  Node (Node (Leaf, &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;, Leaf), &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;, Node (Leaf, &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;, Leaf))

&lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; i : &lt;span class=&quot;dt&quot;&gt;int&lt;/span&gt; iterator =
  sometree_to_iterator t&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here is a transcript of an OCaml toplevel session:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  # i();;
  Visiting a node.
  Visiting a node.
  Visiting a leaf.
  - : int option = Some 1
  # i();;
  Visiting a leaf.
  - : int option = Some 2
  # i();;
  Visiting a node.
  Visiting a leaf.
  - : int option = Some 3
  # i();;
  Visiting a leaf.
  - : int option = None
  # i();;
  - : int option = None&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;variant-avoiding-duplication-of-the-type-definition&quot;&gt;Variant: Avoiding Duplication of the Type Definition&lt;/h2&gt;
&lt;p&gt;Earlier, we have generated a visitor for the existing type &lt;code&gt;'a sometree&lt;/code&gt; in &lt;em&gt;a posteriori&lt;/em&gt; style. We have manually created an isomorphic copy of the type &lt;code&gt;'a sometree&lt;/code&gt;, which we have named &lt;code&gt;'a mytree&lt;/code&gt;, and have annotated this copy with &lt;code&gt;[@@deriving visitors { ... }]&lt;/code&gt;. Furthermore, we have taken this opportunity to insert &lt;code&gt;delay&lt;/code&gt; type constructors into the type, so as to influence the generated visitor.&lt;/p&gt;
&lt;p&gt;This style is relatively pleasant because it is declarative and lets us control exactly where delays are inserted. However, it requires duplicating the definition of the type &lt;code&gt;'a sometree&lt;/code&gt;, which may be unpleasant (if the definition is large) or impossible (if the definition is hidden behind an abstraction barrier).&lt;/p&gt;
&lt;p&gt;Another approach is to generate a visitor in &lt;em&gt;a priori&lt;/em&gt; style. When the type &lt;code&gt;'a sometree&lt;/code&gt; is first defined, a &lt;code&gt;reduce&lt;/code&gt; visitor can be immediately generated for it, as follows:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot;&gt;&lt;pre class=&quot;sourceCode ocaml&quot;&gt;&lt;code class=&quot;sourceCode ocaml&quot;&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; 'a sometree =
  | Leaf
  | Node &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt; 'a sometree * 'a * 'a sometree

[@@deriving visitors { variety = &lt;span class=&quot;st&quot;&gt;&amp;quot;reduce&amp;quot;&lt;/span&gt;; polymorphic = &lt;span class=&quot;kw&quot;&gt;true&lt;/span&gt;;
                       name = &lt;span class=&quot;st&quot;&gt;&amp;quot;sometree_reduce&amp;quot;&lt;/span&gt; }]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;At this point, we pretend that we do not know yet what this visitor will be used for, so we do not annotate the type definition with &lt;code&gt;delay&lt;/code&gt;, and do not use &lt;code&gt;delayed_tree_monoid&lt;/code&gt; as a base class. We get a visitor class, named &lt;code&gt;sometree_reduce&lt;/code&gt;. This class has two virtual methods, &lt;code&gt;zero&lt;/code&gt; and &lt;code&gt;plus&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then, we create a subclass, named &lt;code&gt;reduce&lt;/code&gt;, which we tailor to our needs. We mix the generated class &lt;code&gt;sometree_reduce&lt;/code&gt; with the class &lt;code&gt;delayed_tree_monoid&lt;/code&gt;, and insert a delay at every tree node by overriding the method &lt;code&gt;visit_sometree&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot;&gt;&lt;pre class=&quot;sourceCode ocaml&quot;&gt;&lt;code class=&quot;sourceCode ocaml&quot;&gt;&lt;span class=&quot;kw&quot;&gt;class&lt;/span&gt; ['self] reduce = &lt;span class=&quot;kw&quot;&gt;object&lt;/span&gt; (self : 'self)
  &lt;span class=&quot;kw&quot;&gt;inherit&lt;/span&gt; [_] sometree_reduce &lt;span class=&quot;kw&quot;&gt;as&lt;/span&gt; super
  &lt;span class=&quot;kw&quot;&gt;inherit&lt;/span&gt; [_] delayed_tree_monoid
  &lt;span class=&quot;kw&quot;&gt;method&lt;/span&gt;! visit_sometree visit_'a env t =
    self#visit_delay (super#visit_sometree visit_'a) env t
&lt;span class=&quot;kw&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The rest of the code is unchanged (except the method &lt;code&gt;visit_mytree_delay&lt;/code&gt; no longer exists; one calls &lt;code&gt;visit_sometree&lt;/code&gt; instead).&lt;/p&gt;
&lt;h2 id=&quot;variant-getting-rid-of-explicit-delayed-trees&quot;&gt;Variant: Getting Rid of Explicit Delayed Trees&lt;/h2&gt;
&lt;p&gt;I like to present delayed trees as an explicit data structure, because this helps understand what is going on. However, if desired, it is possible to hide them by &lt;em&gt;refunctionalization&lt;/em&gt; (the opposite of &lt;em&gt;defunctionalization&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;Above, the function &lt;code&gt;delayed_tree_to_cascade&lt;/code&gt; was written with the help of an auxiliary function, &lt;code&gt;delayed_tree_to_head&lt;/code&gt;. We could also have written it directly, as follows:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot;&gt;&lt;pre class=&quot;sourceCode ocaml&quot;&gt;&lt;code class=&quot;sourceCode ocaml&quot;&gt;&lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;rec&lt;/span&gt; delayed_tree_to_cascade (dt : 'a delayed_tree) (k : 'a cascade)
: 'a cascade =
  &lt;span class=&quot;kw&quot;&gt;match&lt;/span&gt; dt &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt;
  | DTZero -&amp;gt;
      k
  | DTOne x -&amp;gt;
      cons x k
  | DTTwo (dt1, dt2) -&amp;gt;
      delayed_tree_to_cascade dt1 (delayed_tree_to_cascade dt2 k)
  | DTDelay dt -&amp;gt;
      &lt;span class=&quot;kw&quot;&gt;fun&lt;/span&gt; () -&amp;gt; delayed_tree_to_cascade (force dt) k ()&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this form, the only function that is ever applied to a delayed tree is &lt;code&gt;delayed_tree_to_cascade&lt;/code&gt;. Therefore, wherever we construct a delayed tree &lt;code&gt;t&lt;/code&gt;, we could instead directly build a closure whose behavior is equivalent to &lt;code&gt;delayed_tree_to_cascade t&lt;/code&gt;. This is &lt;em&gt;refunctionalization&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The data structure of delayed trees seems to disappears. The type &lt;code&gt;'a delayed_tree&lt;/code&gt; can be defined as a synonym for a &lt;code&gt;'a cascade -&amp;gt; 'a cascade&lt;/code&gt;. I usually refer to this type as &lt;code&gt;'a producer&lt;/code&gt;: it is the type of a function that concatenates elements in front of the cascade that it receives as an argument.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot;&gt;&lt;pre class=&quot;sourceCode ocaml&quot;&gt;&lt;code class=&quot;sourceCode ocaml&quot;&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; 'a producer =
  'a cascade -&amp;gt; 'a cascade

&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; 'a delayed_tree =
  'a producer&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The four data constructors are defined as follows:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot;&gt;&lt;pre class=&quot;sourceCode ocaml&quot;&gt;&lt;code class=&quot;sourceCode ocaml&quot;&gt;&lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; _DTZero k =
  k

&lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; _DTOne x k =
  cons x k

&lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; _DTTwo dt1 dt2 k =
  dt1 (dt2 k)

&lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; _DTDelay dt k =
  &lt;span class=&quot;kw&quot;&gt;fun&lt;/span&gt; () -&amp;gt; force dt k ()&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The reader can check that the types of these data constructors are the same as in the previous version of the code. For instance, &lt;code&gt;_DTDelay&lt;/code&gt; has type &lt;code&gt;(unit -&amp;gt; 'a delayed_tree) -&amp;gt; 'a delayed_tree&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The root function &lt;code&gt;delayed_tree_to_cascade&lt;/code&gt; (without a continuation argument) is defined as follows:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot;&gt;&lt;pre class=&quot;sourceCode ocaml&quot;&gt;&lt;code class=&quot;sourceCode ocaml&quot;&gt;&lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; delayed_tree_to_cascade (dt : 'a delayed_tree) : 'a cascade =
  dt nil&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The delayed tree monoid uses the new versions of the four data constructors:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot;&gt;&lt;pre class=&quot;sourceCode ocaml&quot;&gt;&lt;code class=&quot;sourceCode ocaml&quot;&gt;&lt;span class=&quot;kw&quot;&gt;class&lt;/span&gt; ['self] delayed_tree_monoid = &lt;span class=&quot;kw&quot;&gt;object&lt;/span&gt; (_ : 'self)

  &lt;span class=&quot;kw&quot;&gt;method&lt;/span&gt; zero =
    _DTZero

  &lt;span class=&quot;kw&quot;&gt;method&lt;/span&gt; plus =
    _DTTwo

  &lt;span class=&quot;kw&quot;&gt;method&lt;/span&gt; visit_delay: 'env 'a .
    ('env -&amp;gt; 'a -&amp;gt; 'b delayed_tree) -&amp;gt;
    'env -&amp;gt; 'a delay -&amp;gt; 'b delayed_tree
  = &lt;span class=&quot;kw&quot;&gt;fun&lt;/span&gt; visit_'a env x -&amp;gt;
      _DTDelay (&lt;span class=&quot;kw&quot;&gt;fun&lt;/span&gt; () -&amp;gt; visit_'a env x)

&lt;span class=&quot;kw&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; yield _env x =
  _DTOne x&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The four functions &lt;code&gt;_DTZero&lt;/code&gt;, &lt;code&gt;_DTOne&lt;/code&gt;, &lt;code&gt;_DTTwo&lt;/code&gt;, and &lt;code&gt;_DTDelay&lt;/code&gt; could be inlined, if desired, so as to make the above code seem even more concise.&lt;/p&gt;
&lt;p&gt;The rest of the code is unchanged.&lt;/p&gt;
&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements&lt;/h2&gt;
&lt;p&gt;KC Sivaramakrishnan asked whether a visitor can be used to construct an iterator. Gabriel Scherer pointed out that the delayed tree data structure can be hidden by refunctionalization.&lt;/p&gt;

</content><id>http://gallium.inria.fr/blog/from-visitors-to-iterators/index.html</id><title type="text">From visitors to iterators</title><updated>2017-03-14T08:00:00-00:00</updated><author><name>François Pottier</name></author></entry><entry><source><updated>2017-05-11T20:18:34-00:00</updated><subtitle xml:base="http://blog.shaynefletcher.org/feeds/posts/default/-/OCaml" type="html">&quot;Hooked&quot; on programming</subtitle><link type="application/atom+xml" href="http://www.blogger.com/feeds/5012565255225108517/posts/default/-/OCaml/-/OCaml?start-index=26&amp;max-results=25" rel="next"/><link href="http://pubsubhubbub.appspot.com/" rel="hub"/><link type="text/html" href="http://blog.shaynefletcher.org/search/label/OCaml" rel="alternate"/><link type="application/atom+xml" href="http://www.blogger.com/feeds/5012565255225108517/posts/default/-/OCaml" rel="self"/><link type="application/atom+xml" href="http://blog.shaynefletcher.org/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed"/><generator uri="http://www.blogger.com" version="7.00">Blogger</generator><category term="recursive descent"/><category term="ppx"/><category term="ppf"/><category term="left recursion"/><category term="grammars"/><category term="balanced binary search trees"/><category term="Windows 8.1"/><category term="Windows 7"/><category term="Variance"/><category term="Universal type"/><category term="Universal Gas Constant"/><category term="Tail recursion"/><category term="Subtyping"/><category term="Stack overflow"/><category term="Sorting"/><category term="Simulation"/><category term="Sieve of Eratosthenes"/><category term="Science"/><category term="Rings"/><category term="Recursion"/><category term="Priority queue"/><category term="Pretty-printing"/><category term="Poof"/><category term="Polynomials"/><category term="Polymorphic variants"/><category term="Permutation"/><category term="Pascal"/><category term="Numerical analysis"/><category term="Monty Hall"/><category term="Modules"/><category term="List comprehensions"/><category term="Leftist heap"/><category term="Labeled arguments"/><category term="Ideal Gas Law"/><category term="Horner's rule"/><category term="Functors"/><category term="Financial Modeling in Python"/><category term="Exponentiation by squaring"/><category term="Compression"/><category term="Combination"/><category term="Church-Turing thesis"/><category term="Church numerals"/><category term="Cartesian product"/><category term="Algorithmic complexity"/><category term="64-bit"/><category term="type-classes"/><category term="ocamlyacc"/><category term="ocamllex"/><category term="Y Combinator"/><category term="Taylor polynomials"/><category term="Streams"/><category term="Recursive lists"/><category term="Prolog"/><category term="Monads"/><category term="Dimensional analysis"/><category term="Algebra"/><category term="Regular expressions"/><category term="Powerset"/><category term="Statistics"/><category term="Lexical analysis"/><category term="Haskell"/><category term="Parsing"/><category term="data structures"/><category term="Symbolic computation"/><category term="Lambda calculus"/><category term="Felix"/><category term="Boost"/><category term="Python"/><category term="Algorithms"/><category term="C++"/><category term="Functional programming"/><category term="OCaml"/><id>tag:blogger.com,1999:blog-5012565255225108517</id><title type="text">Shayne Fletcher</title><author><email>noreply@blogger.com</email><name>Shayne Fletcher</name></author></source><published>2017-03-10T18:06:00-00:00</published><link title="Universal type" type="text/html" href="http://blog.shaynefletcher.org/2017/03/universal-type.html" rel="alternate"/><link type="application/atom+xml" href="http://www.blogger.com/feeds/5012565255225108517/posts/default/7149115100532400726" rel="self"/><link type="application/atom+xml" href="http://www.blogger.com/feeds/5012565255225108517/posts/default/7149115100532400726" rel="edit"/><content xml:base="http://blog.shaynefletcher.org/feeds/posts/default/-/OCaml" type="html">    &lt;h2&gt;Universal type&lt;/h2&gt;    &lt;p&gt;A universal type is a type into which all other types can be     embedded. A module implementing such a type here will satisfy the     following signature.       &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;module type UNIVERSAL = sig&lt;br /&gt;  type t&lt;br /&gt;  val embed : unit &amp;rarr; (&amp;alpha; &amp;rarr; t) * (t &amp;rarr; &amp;alpha; option)&lt;br /&gt;end;;&lt;br /&gt;      &lt;/pre&gt;      The &lt;code&gt;type t&lt;/code&gt; is the universal type and each call       to &lt;code&gt;embed&lt;/code&gt; returns a pair of functions : an injection       function for embedding a value into the universal type and, a       projection function for extracting the value from its embedding       in the universal type. The following code demonstrates intended       usage.       &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;module type TEST = sig&lt;br /&gt;  val run : unit &amp;rarr; unit&lt;br /&gt;end;;&lt;br /&gt;&lt;br /&gt;module type UNIVERSAL_TEST = functor (U : UNIVERSAL) &amp;rarr; TEST;;&lt;br /&gt;&lt;br /&gt;module Basic_usage : UNIVERSAL_TEST = &lt;br /&gt;  functor (U : UNIVERSAL) &amp;rarr; struct&lt;br /&gt;    let run () =&lt;br /&gt;      let ((of_int : int &amp;rarr; U.t)&lt;br /&gt;         , (to_int : U.t &amp;rarr; int option)) = U.embed () in&lt;br /&gt;      let ((of_string : string &amp;rarr; U.t)&lt;br /&gt;         , (to_string : U.t &amp;rarr; string option)) = U.embed () in&lt;br /&gt;&lt;br /&gt;      let r : U.t ref = ref (of_int 13) in&lt;br /&gt;&lt;br /&gt;      begin&lt;br /&gt;        assert (to_int !r = Some 13);&lt;br /&gt;        assert (to_string !r = None);&lt;br /&gt;&lt;br /&gt;        r := of_string &quot;foo&quot;;&lt;br /&gt;&lt;br /&gt;        assert (to_string !r = Some &quot;foo&quot;);&lt;br /&gt;        assert (to_int !r = None);&lt;br /&gt;      end&lt;br /&gt;  end;;&lt;br /&gt;      &lt;/pre&gt;    &lt;/p&gt;    &lt;p&gt;One possible implementation is via the use of exceptions     together with local modules. The core idea exploits the fact that     the primitive type &lt;code&gt;exn&lt;/code&gt; is an open extensible     sum. Here's the complete implementation. We'll break it down     later.     &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;module Universal_exn : UNIVERSAL = struct&lt;br /&gt;&lt;br /&gt;  type t = exn&lt;br /&gt;&lt;br /&gt;  module type ANY = sig&lt;br /&gt;    type c&lt;br /&gt;    exception E of c&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  type &amp;alpha; any = (module ANY with type c = &amp;alpha;)&lt;br /&gt;&lt;br /&gt;  let mk : unit &amp;rarr; &amp;alpha; any =&lt;br /&gt;    fun (type s) () &amp;rarr;&lt;br /&gt;      (module struct&lt;br /&gt;        type c = s&lt;br /&gt;        exception E of c&lt;br /&gt;      end : ANY with type c = s)&lt;br /&gt;&lt;br /&gt;  let inj (type s) (p : s any) (x : s) : t =&lt;br /&gt;    let module Any = (val p : ANY with type c = s) in&lt;br /&gt;    Any.E x&lt;br /&gt;&lt;br /&gt;  let proj (type s) (p : s any) (y : t) : s option =&lt;br /&gt;    let module Any = (val p : ANY with type c = s) in&lt;br /&gt;    match y with&lt;br /&gt;    | Any.E x &amp;rarr; Some x&lt;br /&gt;    | _ as e &amp;rarr;  None&lt;br /&gt;&lt;br /&gt;  let embed () = let p = mk () in inj p, proj p&lt;br /&gt;&lt;br /&gt;end;;&lt;br /&gt;    &lt;/pre&gt;    Before delving into an explanation of the program, one can verify     it satisfies the basic test.    &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;# module Test_basic = Mk_universal_test(Universal_exn);;&lt;br /&gt;# Test_basic.run ();;&lt;br /&gt;- : unit = ()&lt;br /&gt;   &lt;/pre&gt;   &lt;/p&gt;   &lt;p&gt;The definition of the universal type &lt;code&gt;t&lt;/code&gt; is an alias    to the predefined type &lt;code&gt;exn&lt;/code&gt;.    &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;type t = exn&lt;br /&gt;   &lt;/pre&gt;   A module type &lt;code&gt;ANY&lt;/code&gt; is introduced. Modules that    implement this signature define an abstract type &lt;code&gt;c&lt;/code&gt; and    introduce an &lt;code&gt;exn&lt;/code&gt; constructor &lt;code&gt;E of c&lt;/code&gt;.    &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;module type ANY = sig&lt;br /&gt;  type c&lt;br /&gt;  exception E of c&lt;br /&gt;end&lt;br /&gt;   &lt;/pre&gt;   An alias for the type of a module value satisfying this signature    comes next. Using aliases of this kind are helpful in reducing    &quot;syntactic verbosity&quot; in code accepting and returning module values.    &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;type &amp;alpha; any = (module ANY with type c = &amp;alpha;)&lt;br /&gt;   &lt;/pre&gt;   Next follow a set of functions that are private to the    implementation of the module. The first of these    is &lt;code&gt;mk&lt;/code&gt;.    &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;let mk : unit &amp;rarr; &amp;alpha; any =&lt;br /&gt;  fun (type s) () &amp;rarr;&lt;br /&gt;    (module struct&lt;br /&gt;      type c = s&lt;br /&gt;      exception E of c&lt;br /&gt;    end : ANY with type c = s)&lt;br /&gt;   &lt;/pre&gt;   This function &lt;code&gt;mk&lt;/code&gt; takes the &lt;code&gt;unit&lt;/code&gt; argument    and each invocation computes a new module instance which is packed    as a first class value and returned. The locally abstract    type &lt;code&gt;s&lt;/code&gt; connects to the &lt;code&gt;&amp;alpha;&lt;/code&gt; in the    return type.    &lt;/p&gt;   &lt;p&gt;   The next function to be defined is &lt;code&gt;inj&lt;/code&gt; which computes    a universal type value from its argument.    &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;let inj (type s) (p : s any) (x : s) : t =&lt;br /&gt;  let module Any = (val p : ANY with type c = s) in&lt;br /&gt;  Any.E x&lt;br /&gt;   &lt;/pre&gt;    As was the case for &lt;code&gt;mk&lt;/code&gt;, a locally abstract type is     used in the definition of &lt;code&gt;inj&lt;/code&gt; and observe how that     type ensures a coherence between the module     parameter &lt;code&gt;p&lt;/code&gt; and the type of the parameter to be     embedded &lt;code&gt;x&lt;/code&gt;.    &lt;/p&gt;   &lt;p&gt;   The projection function &lt;code&gt;proj&lt;/code&gt; comes next and also uses    a locally abstract type ensuring coherence among its parameters.    &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;let proj (type s) (p : s any) (y : t) : s option =&lt;br /&gt;  let module Any = (val p : ANY with type c = s) in&lt;br /&gt;  match y with&lt;br /&gt;  | Any.E x &amp;rarr; Some x&lt;br /&gt;  | _ as e &amp;rarr;  None&lt;br /&gt;   &lt;/pre&gt;   The body of &lt;code&gt;proj&lt;/code&gt; unpacks the module value parameter into    a module named &lt;code&gt;Any&lt;/code&gt; and then attempts to    match &lt;code&gt;y&lt;/code&gt; against the constructor defined    by &lt;code&gt;Any&lt;/code&gt;. Recall, at the end of the day, &lt;code&gt;y&lt;/code&gt;   is of type &lt;code&gt;exn&lt;/code&gt;. The match contains two cases : the    first matching the constructor &lt;code&gt;Any.E x&lt;/code&gt;   with &lt;code&gt;x&lt;/code&gt; having type &lt;code&gt;s&lt;/code&gt;, the second anything    else (that is, &lt;code&gt;proj&lt;/code&gt; is total).    &lt;/p&gt;   &lt;p&gt;Finally we come to the public function &lt;code&gt;embed&lt;/code&gt;.    &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;let embed () = let p = mk () in inj p, proj p&lt;br /&gt;   &lt;/pre&gt;   &lt;code&gt;embed&lt;/code&gt; calls &lt;code&gt;mk&lt;/code&gt; to produce a new    embedding &lt;code&gt;p&lt;/code&gt; and returns the pair of partial    applications &lt;code&gt;(inj p, proj p)&lt;/code&gt;.    &lt;/p&gt;   &lt;p&gt;Our examination of the implementation is concluded. There are    however various implications of the implementation we are now in a    position to understand that are not immediately obvious from the    specification. As a first example, consider the inferred type of a    call to &lt;code&gt;embed&lt;/code&gt;.    &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;# module U = Universal_exn;;&lt;br /&gt;# let inj, proj = U.embed ();;&lt;br /&gt;val inj : '_a &amp;rarr; U.t = &lt;fun&gt;&lt;br /&gt;val proj : U.t &amp;rarr; '_a option = &lt;fun&gt;&lt;br /&gt;   &lt;/pre&gt;   &lt;b&gt;Property 1 : &lt;/b&gt;&lt;code&gt;embed&lt;/code&gt; produces weakly polymorphic    functions.    &lt;br/&gt;   &lt;br/&gt;   Consider the following scenario:    &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;# let of_int, to_int = U.embed ();;&lt;br /&gt;# let of_string, to_string = U.embed ();;&lt;br /&gt;   &lt;/pre&gt;   At this point all    of &lt;code&gt;of_int&lt;/code&gt;, &lt;code&gt;to_int&lt;/code&gt;, &lt;code&gt;of_string&lt;/code&gt;   and &lt;code&gt;to_string&lt;/code&gt; are weakly polymorphic.    &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;# let r : U.t ref = ref (of_int 13);;&lt;br /&gt;   &lt;/pre&gt;   The call to &lt;code&gt;of_int&lt;/code&gt; fixes it's type to &lt;code&gt;int &amp;rarr;    U.t&lt;/code&gt; and that of &lt;code&gt;to_int&lt;/code&gt; to &lt;code&gt;U.t &amp;rarr; int    option&lt;/code&gt;. The types of &lt;code&gt;of_string&lt;/code&gt;   and &lt;code&gt;to_string&lt;/code&gt; remain unfixed.    &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;# to_string !r = Some 13;;&lt;br /&gt;- : bool = false&lt;br /&gt;   &lt;/pre&gt;   The programmer has mistakenly used a projection function from a    different embedding.    &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;# r := of_string &quot;foo&quot;;;&lt;br /&gt;Error: This expression has type string but an expression was expected of&lt;br /&gt;type int&lt;br /&gt;   &lt;/pre&gt;   The erroneous usage of &lt;code&gt;to_string&lt;/code&gt; incidentally fixed    the type of &lt;code&gt;of_string&lt;/code&gt; to &lt;code&gt;int &amp;rarr; U.t&lt;/code&gt;! One    can imagine errors of this kind being difficult to diagnose.    &lt;/p&gt;   &lt;p&gt;   &lt;b&gt;Property 2 :&lt;/b&gt; Injection/projection functions of different    embeddings may not be mixed.    &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;# let ((of_int : int &amp;rarr; U.t), (to_int : U.t &amp;rarr; int option)) = U.embed ();;&lt;br /&gt;# let ((of_int' : int &amp;rarr; U.t), (to_int' : U.t &amp;rarr; int option)) = U.embed ();;&lt;br /&gt;   &lt;/pre&gt;   Two embeddings have been created, the programmer has fixed the    types of the injection/projection functions &lt;i&gt;a priori&lt;/i&gt;   (presumably as a defense against the problems of the preceding    example).    &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;# let r : U.t ref = ref (of_int 13);;&lt;br /&gt;# to_int !r = Some 13;;&lt;br /&gt;- : bool = true&lt;br /&gt;   &lt;/pre&gt;   The first embedding is used to inject an integer. That integer can    be extracted using the projection function of that embedding.    &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;#  to_int' !r = Some 13;;&lt;br /&gt;- : bool = false&lt;br /&gt;   &lt;/pre&gt;   We cannot extract the integer from the universal type value using    the projection function from the other embedding despite all of the    types involved being the same. One can imagine that also as being    quite the source of bugs and confusion to the unknowing programmer.    &lt;/p&gt;   &lt;p&gt;   The constraint of property 2 is beyond the ability of the type    system to enforce. About the best one can do is to enhance the    specification of the type with documentation.     &lt;pre class=&quot;prettyprint ml&quot;&gt;&lt;br /&gt;module type UNIV = sig&lt;br /&gt;  type t&lt;br /&gt;&lt;br /&gt;  val embed : unit &amp;rarr; (&amp;alpha; &amp;rarr; t) * (t &amp;rarr; &amp;alpha; option)&lt;br /&gt; &lt;br /&gt;  (* A pair [(inj, proj)] returned by [embed] works together in that&lt;br /&gt;     [proj u] will return [Some v] if and only if [u] was created by&lt;br /&gt;     [inj v]. If [u] was created by a different function then [proj u] &lt;br /&gt;     will return [None]. *)&lt;br /&gt;&lt;br /&gt;end;;&lt;br /&gt;    &lt;/pre&gt;   &lt;hr/&gt;</content><category scheme="http://www.blogger.com/atom/ns#" term="Universal type"/><category scheme="http://www.blogger.com/atom/ns#" term="OCaml"/><id>tag:blogger.com,1999:blog-5012565255225108517.post-7149115100532400726</id><title type="text">Universal type</title><updated>2017-03-10T18:06:54-00:00</updated><author><email>noreply@blogger.com</email><uri>https://plus.google.com/104436573144909855029</uri><name>Shayne Fletcher</name></author></entry><entry><source><updated>2017-05-11T20:18:34-00:00</updated><subtitle xml:base="http://blog.shaynefletcher.org/feeds/posts/default/-/OCaml" type="html">&quot;Hooked&quot; on programming</subtitle><link type="application/atom+xml" href="http://www.blogger.com/feeds/5012565255225108517/posts/default/-/OCaml/-/OCaml?start-index=26&amp;max-results=25" rel="next"/><link href="http://pubsubhubbub.appspot.com/" rel="hub"/><link type="text/html" href="http://blog.shaynefletcher.org/search/label/OCaml" rel="alternate"/><link type="application/atom+xml" href="http://www.blogger.com/feeds/5012565255225108517/posts/default/-/OCaml" rel="self"/><link type="application/atom+xml" href="http://blog.shaynefletcher.org/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed"/><generator uri="http://www.blogger.com" version="7.00">Blogger</generator><category term="recursive descent"/><category term="ppx"/><category term="ppf"/><category term="left recursion"/><category term="grammars"/><category term="balanced binary search trees"/><category term="Windows 8.1"/><category term="Windows 7"/><category term="Variance"/><category term="Universal type"/><category term="Universal Gas Constant"/><category term="Tail recursion"/><category term="Subtyping"/><category term="Stack overflow"/><category term="Sorting"/><category term="Simulation"/><category term="Sieve of Eratosthenes"/><category term="Science"/><category term="Rings"/><category term="Recursion"/><category term="Priority queue"/><category term="Pretty-printing"/><category term="Poof"/><category term="Polynomials"/><category term="Polymorphic variants"/><category term="Permutation"/><category term="Pascal"/><category term="Numerical analysis"/><category term="Monty Hall"/><category term="Modules"/><category term="List comprehensions"/><category term="Leftist heap"/><category term="Labeled arguments"/><category term="Ideal Gas Law"/><category term="Horner's rule"/><category term="Functors"/><category term="Financial Modeling in Python"/><category term="Exponentiation by squaring"/><category term="Compression"/><category term="Combination"/><category term="Church-Turing thesis"/><category term="Church numerals"/><category term="Cartesian product"/><category term="Algorithmic complexity"/><category term="64-bit"/><category term="type-classes"/><category term="ocamlyacc"/><category term="ocamllex"/><category term="Y Combinator"/><category term="Taylor polynomials"/><category term="Streams"/><category term="Recursive lists"/><category term="Prolog"/><category term="Monads"/><category term="Dimensional analysis"/><category term="Algebra"/><category term="Regular expressions"/><category term="Powerset"/><category term="Statistics"/><category term="Lexical analysis"/><category term="Haskell"/><category term="Parsing"/><category term="data structures"/><category term="Symbolic computation"/><category term="Lambda calculus"/><category term="Felix"/><category term="Boost"/><category term="Python"/><category term="Algorithms"/><category term="C++"/><category term="Functional programming"/><category term="OCaml"/><id>tag:blogger.com,1999:blog-5012565255225108517</id><title type="text">Shayne Fletcher</title><author><email>noreply@blogger.com</email><name>Shayne Fletcher</name></author></source><published>2017-03-07T20:05:00-00:00</published><link title="Polymorphic variants : Subtyping and variance" type="text/html" href="http://blog.shaynefletcher.org/2017/03/polymorphic-variants-subtyping-and.html" rel="alternate"/><link type="application/atom+xml" href="http://www.blogger.com/feeds/5012565255225108517/posts/default/8479980294446732706" rel="self"/><link type="application/atom+xml" href="http://www.blogger.com/feeds/5012565255225108517/posts/default/8479980294446732706" rel="edit"/><content xml:base="http://blog.shaynefletcher.org/feeds/posts/default/-/OCaml" type="html">&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01//EN&quot;           &quot;http://www.w3.org/TR/html4/strict.dtd&quot;&gt;&lt;html&gt;  &lt;head&gt;    &lt;script type=&quot;text/x-mathjax-config&quot;&gt;      MathJax.Hub.Config({       extensions: [&quot;tex2jax.js&quot;,&quot;TeX/AMSmath.js&quot;,&quot;TeX/AMSsymbols.js&quot;],       jax: [&quot;input/TeX&quot;, &quot;output/HTML-CSS&quot;],       tex2jax: {       inlineMath: [ ['$','$'], [&quot;\\(&quot;,&quot;\\)&quot;] ],       displayMath: [ ['$$','$$'], [&quot;\\[&quot;,&quot;\\]&quot;] ],       },       &quot;HTML-CSS&quot;: { availableFonts: [&quot;TeX&quot;] }       });     &lt;/script&gt;      &lt;script type=&quot;text/javascript&quot; src=&quot;http://cdn.mathjax.org/mathjax/latest/MathJax.js&quot;&gt;&lt;/script&gt;    &lt;title&gt;Polymorphic variants : subtyping and variance&lt;/title&gt;  &lt;/head&gt;  &lt;body&gt;    &lt;h2&gt;Polymorphic variants : Subtyping and variance&lt;/h2&gt;    &lt;p&gt;    Here are some expressions in the top-level involving polymorphic     variant types.     &lt;pre&gt;&lt;br /&gt;    # let x = [ `On; `Off ];;&lt;br /&gt;    val x : [&amp;gt; `Off | `On ] list = [ `On; `Off ]&lt;br /&gt;    &lt;/pre&gt;    The notation &lt;code&gt;[&amp;gt; `Off | `On ]&lt;/code&gt; represents a type     that &lt;b&gt;at least&lt;/b&gt; contains the constructors &lt;code&gt;`Off&lt;/code&gt;    and &lt;code&gt;`On&lt;/code&gt;. Of course, there are an unlimited number of     such types so &lt;code&gt;[&amp;gt; `Off | `On ]&lt;/code&gt; is a set in fact.     &lt;/p&gt;    &lt;p&gt;    &lt;pre&gt;&lt;br /&gt;    # let n = `Number 1;;&lt;br /&gt;    val n : [&amp;gt; `Number of int ] = `Number 1&lt;br /&gt;    &lt;/pre&gt;    The value &lt;code&gt;n&lt;/code&gt; is of a type that &lt;b&gt;at least&lt;/b&gt;    contains the constructor &lt;code&gt;`Number of int&lt;/code&gt;.     &lt;/p&gt;    &lt;p&gt;    &lt;pre&gt;&lt;br /&gt;    # let f = function | `On &amp;rarr; 1 | `Off &amp;rarr; 0 | `Number n &amp;rarr; n;;&lt;br /&gt;    val f : [&amp;lt; `Number of int | `Off | `On ] &amp;rarr; int = &amp;lt;fun&amp;gt;&lt;br /&gt;    &lt;/pre&gt;    The function &lt;code&gt;f&lt;/code&gt; accomodates exactly three cases     corresponding to the     constructors &lt;code&gt;`Off&lt;/code&gt;, &lt;code&gt;`On&lt;/code&gt; and &lt;code&gt;`Number     of int&lt;/code&gt;. This informs us that &lt;code&gt;[&amp;lt; `Number of int |     `Off | `On ]&lt;/code&gt; is of a type that &lt;b&gt;at most&lt;/b&gt; has the     constructors &lt;code&gt;`Off&lt;/code&gt;, &lt;code&gt;`On&lt;/code&gt; and &lt;code&gt;`Number     of int&lt;/code&gt;.     &lt;/p&gt;    &lt;p&gt;    The expression &lt;code&gt;(&lt;/code&gt;$expr$&lt;code&gt;    :&gt; &lt;/code&gt;$typexpr$&lt;code&gt;)&lt;/code&gt; coerces the expression $expr$ to     type $typexpr$. The expression &lt;code&gt;(&lt;/code&gt;$expr$ &lt;code&gt;:&lt;/code&gt;    $typ_{1}$ &lt;code&gt;:&amp;gt;&lt;/code&gt; $typ_{2}$ &lt;code&gt;)&lt;/code&gt; coerces the     exprssion $expr$ from $typ_{1}$ to $typ_{2}$. It is only possible     to coerce an expression $expr$ from type $typ_{1}$ to type     $typ_{2}$, if the type of $expr$ is an instance of $typ_{1}$ and     $typ_{1}$ is a subtype of $typ_{2}$.     &lt;/p&gt;    &lt;p&gt;    &lt;pre&gt;&lt;br /&gt;    # let f x = (x :&gt; [ `A | `B ]);;&lt;br /&gt;    val f : [&amp;lt; `A | `B ] &amp;rarr; [ `A | `B ] = &amp;lt;fun&amp;gt;&lt;br /&gt;    &lt;/pre&gt;    We see &lt;code&gt;x&lt;/code&gt; needs to be coercible to type &lt;code&gt;[ `A |      `B ]&lt;/code&gt;. So, we read &lt;code&gt;[&amp;lt; `A | `B ]&lt;/code&gt; as a type      that at most contains the constructors &lt;code&gt;`A&lt;/code&gt;     and &lt;code&gt;`B&lt;/code&gt;. &lt;code&gt;[ `A ]&lt;/code&gt;, &lt;code&gt;[ `B ]&lt;/code&gt;     and &lt;code&gt;[ `A | `B ]&lt;/code&gt; are the subtypes of &lt;code&gt;[ `A | `B      ]&lt;/code&gt;. It follows then that &lt;code&gt;[&amp;lt; `A | `B ]&lt;/code&gt; is      the set of subtypes of &lt;code&gt;[ `A | `B ]&lt;/code&gt;.     &lt;/p&gt;    &lt;p&gt;    &lt;pre&gt;&lt;br /&gt;    # let f x = (x :&gt; [ `A | `B ] * [ `C | `D ]);;&lt;br /&gt;    val f : [&amp;lt; `A | `B ] * [&amp;lt; `C | `D ] &amp;rarr; [ `A | `B ] * [ `C | `D ] = &amp;lt;fun&amp;gt;&lt;br /&gt;    &lt;/pre&gt;    We see &lt;code&gt;x&lt;/code&gt; needs to be coercible to &lt;code&gt;[ `A | `B ] *     [ `C | `D ]&lt;/code&gt;. This coercion can only proceed     if &lt;code&gt;x&lt;/code&gt; designates a pair with first component a subtype     of &lt;code&gt;[ `A | `B ]&lt;/code&gt; and second component a subtype     of &lt;code&gt;[ `C | `D ]&lt;/code&gt;. So we see, &lt;code&gt;[&amp;lt; `A | `B ] *     [&amp;lt; `C | `D ]&lt;/code&gt; is the set of subtypes of &lt;code&gt;[ `A | `B ]     * [ `C | `D ]&lt;/code&gt;.     &lt;/p&gt;    &lt;p&gt;    &lt;pre&gt;&lt;br /&gt;    # let f x = (x  :&gt; [ `A ] &amp;rarr; [ `C | `D ]);;&lt;br /&gt;    val f : ([&amp;gt; `A ] &amp;rarr; [&amp;lt; `C | `D ]) &amp;rarr; [ `A ] &amp;rarr; [ `C | `D ] = &amp;lt;fun&amp;gt;&lt;br /&gt;    &lt;/pre&gt;    We see &lt;code&gt;x&lt;/code&gt; needs to be coercible to &lt;code&gt;[ `A ] &amp;rarr; [     `C | `D ]&lt;/code&gt;. This coercion can only proceed if &lt;code&gt;x&lt;/code&gt;    designates an arrow where the argument is of a type that at least     contains the constructor &lt;code&gt;`A&lt;/code&gt;. That is &lt;code&gt;[ `A     ]&lt;/code&gt;, &lt;code&gt;[ `A | ... ]&lt;/code&gt; where the &quot;&lt;code&gt;...&lt;/code&gt;&quot;     represent more constructors. From this we see that &lt;code&gt;[&amp;gt;     `A]&lt;/code&gt; is the set of supertypes of &lt;code&gt;[ `A ]&lt;/code&gt;. The     return value of &lt;code&gt;x&lt;/code &gt; (by logic we've already     established) is a subtype of &lt;code&gt;[ `C | `D     ]&lt;/code&gt;. So, &lt;code&gt;[&amp;gt; `A ] &amp;rarr; [&amp;lt; `C | `D ]&lt;/code&gt; is the     set of subtypes of &lt;code&gt;[ `A ] &amp;rarr; [ `C | `D ]&lt;/code&gt;.     &lt;/p&gt;    &lt;p&gt;The transformation represented by &lt;code&gt;f&lt;/code&gt; above, has     coerced an arrow &lt;code&gt;x&lt;/code&gt; to a new arrow. The type of the     argument of &lt;code&gt;x&lt;/code&gt; is &lt;code&gt;[&amp;gt; `A ]&lt;/code&gt; and the     type of the argument of the resulting arrow is &lt;code&gt;[ `A     ]&lt;/code&gt;. That is, for the argument, the transformation between     types has taken a supertype to a subtype. The argument type is     said to be in a &quot;contravariant&quot; position. On the other hand, the     result type of &lt;code&gt;x&lt;/code&gt; is &lt;code&gt;[&amp;lt; `C | `D ]&lt;/code&gt; and     the arrow that is produced from it, &lt;code&gt;f x&lt;/code&gt;, has result     type &lt;code&gt;[ `C | `D ]&lt;/code&gt;. That is, the coercion for the     result type has taken a subtype to a supertype : the result type     in &lt;code&gt;x&lt;/code&gt; is said to be in &quot;covariant&quot; position.     &lt;/p&gt;    &lt;p&gt;    In the following, the type &lt;code&gt;&amp;alpha; t&lt;/code&gt; is abstract.     &lt;pre&gt;&lt;br /&gt;    # type &amp;alpha; t;;&lt;br /&gt;    # let f (x : [ `A ] t) = (x :&amp;gt; [ `A | `B ] t);;&lt;br /&gt;    Error: Type [ `A ] t is not a subtype of [ `A | `B ] t &lt;br /&gt;    &lt;/pre&gt;    Indeed, &lt;code&gt;[ `A ]&lt;/code&gt; is a subtype of &lt;code&gt;[ `A | `B     ]&lt;/code&gt; but that, &lt;i&gt;a priori&lt;/i&gt;, does not say anything about     the subtyping relationship between &lt;code&gt;[ `A ] t&lt;/code&gt;    and &lt;code&gt;[ `A | `B ] t&lt;/code&gt;. For this coercion to be legal, the     parameter &lt;code&gt;&amp;alpha;&lt;/code&gt; must be given a covariant     annotation:     &lt;pre&gt;&lt;br /&gt;    # type +&amp;alpha; t;;&lt;br /&gt;    # let f (x : [ `A ] t) = (x :&gt; [ `A | `B ] t);;&lt;br /&gt;    val f : [ `A ] t &amp;rarr; [ `A | `B ] t = &amp;lt;fun&amp;gt;&lt;br /&gt;    &lt;/pre&gt;    The declaration &lt;code&gt;type +&amp;alpha; t&lt;/code&gt; declares that the     abstract type is covariant in its parameter : if the type $\tau$     is a subtype of $\sigma$, then $\tau\;t$ is a subtype of     $\sigma\;t$. Here, $\tau = $&lt;code&gt;[ `A ]&lt;/code&gt;, $\sigma =     $&lt;code&gt;[ `A | `B ]&lt;/code&gt;, $\tau$ is a subtype of $\sigma$     and &lt;code&gt;[ `A ] t&lt;/code&gt; is a subtype of &lt;code&gt;[ `A | `B]     t&lt;/code&gt;.     &lt;/p&gt;    &lt;p&gt;    Here is a similar example, but this time, in the other direction.     &lt;pre&gt;&lt;br /&gt;    # type &amp;alpha; t;;&lt;br /&gt;    # let f (x : [ `A | `B ] t) = (x :&amp;gt; [ `A ] t);;&lt;br /&gt;    Error: This expression cannot be coerced to type [ `A ] t&lt;br /&gt;    &lt;/pre&gt;    The type variable can be annotated as contravariant however, and     the coercion function typechecks.     &lt;pre&gt;&lt;br /&gt;    # type -&amp;alpha; t;;&lt;br /&gt;    # let f (x : [`A | `B] t) = (x :&amp;gt; [ `A ] t);;&lt;br /&gt;    val f : [ `A | `B ] t &amp;rarr; [ `A ] t = &amp;lt;fun&amp;gt;&lt;br /&gt;    &lt;/pre&gt;    The declaration &lt;code&gt;type -&amp;alpha; t&lt;/code&gt; declares that the abstract     type &lt;code&gt;t&lt;/code&gt; is contravariant in its parameter : if $\tau$     is a subtype of $\sigma$ then $\sigma\;t$ is a subtype of     $\tau\;t$. In this example, $\tau = $&lt;code&gt;[ `A ]&lt;/code&gt; and     $\sigma = $&lt;code&gt;[`A | `B]&lt;/code&gt;, $\tau$ is a subtype of $\sigma$     and     &lt;code&gt;[ `A | `B ] t&lt;/code&gt; is a subtype of &lt;code&gt;[ `A ] t&lt;/code&gt;.     &lt;/p&gt;    &lt;p&gt;    In the following, &lt;code&gt;type &amp;alpha; t&lt;/code&gt; is &lt;b&gt;not&lt;/b&gt;    abstract and variance can be inferred.     &lt;pre&gt;&lt;br /&gt;    # type &amp;alpha; t = {x : &amp;alpha;} ;;&lt;br /&gt;    # let f x = (x : [`A] t :&gt; [`A | `B] t);;&lt;br /&gt;    val f : [ `A ] t &amp;rarr; [ `A | `B ] t = &amp;lt;fun&amp;gt;&lt;br /&gt;    &lt;/pre&gt;    Introducing a constraint however inhibits variance inference.     &lt;pre&gt;&lt;br /&gt;    # type &amp;alpha; t = {x : &amp;alpha;} constraint &amp;alpha; = [&amp;lt; `A | `B ];;&lt;br /&gt;    # let f x = (x : [ `A ] t :&gt; [ `A | `B ] t);;&lt;br /&gt;    Error: Type [ `A ] t is not a subtype of [ `A | `B ] t &lt;br /&gt;    &lt;/pre&gt;    This situation can be overcome by introducing a covariance     annotation.     &lt;pre&gt;&lt;br /&gt;    # type +&amp;alpha; t = {x : &amp;alpha;} constraint &amp;alpha; = [&amp;lt; `A | `B ];;&lt;br /&gt;    # let f x = (x : [ `A ] t :&gt; [ `A | `B ] t);;&lt;br /&gt;    val f : [ `A ] t &amp;rarr; [ `A | `B ] t = &amp;lt;fun&amp;gt;&lt;br /&gt;    &lt;/pre&gt;    In the following example, &lt;code&gt;&amp;alpha;&lt;/code&gt; does not     participate in the definition of &lt;code&gt;type &amp;alpha; t&lt;/code&gt;.     &lt;pre&gt;&lt;br /&gt;    # type &amp;alpha; t = {x : int};;&lt;br /&gt;    # let f x = (x : [ `A ] t :&gt; [ `B ] t);;&lt;br /&gt;    val f : [ `A ] t &amp;rarr; [ `B ] t = &amp;lt;fun&amp;gt;&lt;br /&gt;    &lt;/pre&gt;    In this case, any conversion between &lt;code&gt;&amp;delta; t&lt;/code&gt;    and &lt;code&gt;&amp;epsilon; t&lt;/code&gt; is legal : the     types &lt;code&gt;&amp;delta;&lt;/code&gt; and &lt;code&gt;&amp;epsilon;&lt;/code&gt; are not     required to have a subtyping relation between them.     &lt;/p&gt;   &lt;hr/&gt;  &lt;/body&gt;&lt;/html&gt;</content><category scheme="http://www.blogger.com/atom/ns#" term="Variance"/><category scheme="http://www.blogger.com/atom/ns#" term="Subtyping"/><category scheme="http://www.blogger.com/atom/ns#" term="Polymorphic variants"/><category scheme="http://www.blogger.com/atom/ns#" term="OCaml"/><id>tag:blogger.com,1999:blog-5012565255225108517.post-8479980294446732706</id><title type="text">Polymorphic variants : Subtyping and variance</title><updated>2017-03-08T15:37:43-00:00</updated><author><email>noreply@blogger.com</email><uri>https://plus.google.com/104436573144909855029</uri><name>Shayne Fletcher</name></author></entry><entry><source><updated>2017-05-09T12:00:00-00:00</updated><link title="OCaml Weekly News" type="text/html" href="http://alan.petitepomme.net/cwn/" rel="related"/><link title="OCaml Weekly News" type="application/rss+xml" href="http://alan.petitepomme.net/cwn/cwn.rss" rel="self"/><id>http://alan.petitepomme.net/cwn/</id><title type="text">OCaml Weekly News</title><author><name>OCaml Weekly News</name></author></source><link href="http://alan.petitepomme.net/cwn/2017.03.07.html" rel="alternate"/><content xml:base="http://alan.petitepomme.net/cwn/cwn.rss" type="html">&lt;ol&gt;&lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.03.07.html#1&gt;BuckleScript 1.5 - First class support for Reason syntax&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.03.07.html#2&gt;Menhir incremental api with ocamlbuild&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.03.07.html#3&gt;Cmdliner 1.0.0&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.03.07.html#4&gt;researcher permanent position at ONERA, Toulouse&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.03.07.html#5&gt;Ocaml Github Pull Requests&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.03.07.html#6&gt;Other OCaml News&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;</content><id>http://alan.petitepomme.net/cwn/2017.03.07.html</id><title type="text">Weekly News</title><updated>2017-03-07T12:00:00-00:00</updated><author><name>OCaml Weekly News</name></author></entry><entry><source><updated>2017-05-07T11:34:10-00:00</updated><link href="http://kcsrk.info/" rel="alternate"/><link href="http://kcsrk.info/atom.xml" rel="self"/><id>http://kcsrk.info</id><title type="text">OCaml feed from KC Sivaramakrishnan</title><author><email>sk826@cl.cam.ac.uk</email><name>KC Sivaramakrishnan</name></author></source><link href="http://kcsrk.info/ocaml/opam/topkg/carcass/2017/03/05/building-and-publishing-an-OCaml-package/" rel="alternate"/><content xml:base="http://kcsrk.info/atom-ocaml.xml" type="html">&lt;p&gt;One of the key indicators of maturity of a language ecosystem is the ease of
building, managing and publishing software packages in that language. OCaml
platform has made steady progress in the last few years to this end. While
&lt;a href=&quot;https://opam.ocaml.org/&quot;&gt;OPAM&lt;/a&gt; simplified package (and compiler) management,
the developing and publishing packages remained a constant pain point. This
situation has remarkably improved recently with the
&lt;a href=&quot;http://erratique.ch/software/topkg&quot;&gt;Topkg&lt;/a&gt; and
&lt;a href=&quot;https://github.com/dbuenzli/carcass&quot;&gt;Carcass&lt;/a&gt;. This post provides a short
overview of my workflow for building and publishing an OCaml package using Topkg
and Carcass.&lt;/p&gt;

&lt;!--more--&gt;

&lt;p&gt;Topkg is packager for distributing OCaml software. It provides an API for
describing rules for package builds and installs. Topkg-care provides the
command line tool &lt;code class=&quot;highlighter-rouge&quot;&gt;topkg&lt;/code&gt; with support for creating and linting the
distribution, publishing the distribution and its documentation on WWW, and
making the package available through OPAM. Carcass is a library and a command
line tool for defining and generating the directory structure for the OCaml
package. At the time of writing this post, carcass was unreleased.&lt;/p&gt;

&lt;h2 id=&quot;workflow&quot;&gt;Workflow&lt;/h2&gt;

&lt;p&gt;I recently released a package for &lt;a href=&quot;https://github.com/kayceesrk/mergeable-vector&quot;&gt;mergeable
vectors&lt;/a&gt; based on operational
transformation. The following describes my workflow to build and publish the
package.&lt;/p&gt;

&lt;h3 id=&quot;setup&quot;&gt;Setup&lt;/h3&gt;

&lt;p&gt;Install &lt;code class=&quot;highlighter-rouge&quot;&gt;topkg-care&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;carcass&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ opam install topkg-care opam-publish
$ opam pin add -kgit carcass https://github.com/dbuenzli/carcass
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h3 id=&quot;develop&quot;&gt;Develop&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Create the directory structure
    &lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  $ carcass body topkg/pkg mergeable_vector
&lt;/code&gt;&lt;/pre&gt;
    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Init
    &lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  $ cd mergeable_vector &amp;amp;&amp;amp; git init &amp;amp;&amp;amp; git add . &amp;amp;&amp;amp; git commit -m &quot;First commit.&quot;
  $ git remote add origin https://github.com/kayceesrk/mergeable-vector
  $ git push --set-upstream origin master
&lt;/code&gt;&lt;/pre&gt;
    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Develop: The &lt;code class=&quot;highlighter-rouge&quot;&gt;mergeable_vector/src&lt;/code&gt; directory has the source files. I use
&lt;a href=&quot;https://github.com/kayceesrk/mergeable-vector/blob/master/Makefile&quot;&gt;this Makefile&lt;/a&gt;
at the root of the package.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;Test the package locally with OPAM
    &lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  $ opam pin add mergeable_vector .
&lt;/code&gt;&lt;/pre&gt;
    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;publish&quot;&gt;Publish&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Update the
&lt;a href=&quot;https://github.com/kayceesrk/mergeable-vector/blob/master/CHANGES.md&quot;&gt;CHANGES&lt;/a&gt; file for the new release.&lt;/li&gt;
  &lt;li&gt;Tag the release
    &lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  $ topkg tag 0.1.0
&lt;/code&gt;&lt;/pre&gt;
    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Build the distribution
    &lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  $ topkg distrib
&lt;/code&gt;&lt;/pre&gt;
    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Publish the distribution
    &lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  $ topkg publish distrib
&lt;/code&gt;&lt;/pre&gt;
    &lt;/div&gt;
    &lt;p&gt;This makes a new release on &lt;a href=&quot;https://github.com/kayceesrk/mergeable-vector/releases&quot;&gt;Github&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;Publish the doc
    &lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  $ topkg publish doc
&lt;/code&gt;&lt;/pre&gt;
    &lt;/div&gt;
    &lt;p&gt;This publishes the documentation on &lt;a href=&quot;http://kayceesrk.github.io/mergeable-vector/doc/&quot;&gt;Github&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;Make an OPAM package info and submit it to OPAM repository at &lt;a href=&quot;https://opam.ocaml.org/&quot;&gt;opam.ocaml.org&lt;/a&gt;.
    &lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  $ topkg opam pkg
  $ topkg opam submit
&lt;/code&gt;&lt;/pre&gt;
    &lt;/div&gt;
    &lt;p&gt;This creates a Github &lt;a href=&quot;https://github.com/ocaml/opam-repository/pull/8623&quot;&gt;PR&lt;/a&gt;
to the &lt;a href=&quot;https://github.com/ocaml/opam-repository&quot;&gt;opam-repository&lt;/a&gt;. Once the
PR is merged, the package becomes available to the users.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</content><id>http://kcsrk.info/ocaml/opam/topkg/carcass/2017/03/05/building-and-publishing-an-OCaml-package</id><title type="text">Building and Publishing an OCaml Package: Q1 2017</title><updated>2017-03-05T13:56:00-00:00</updated><author><email>sk826@cl.cam.ac.uk</email><name>KC Sivaramakrishnan</name></author></entry><entry><summary xml:base="https://blogs.janestreet.com/wp-atom.php" type="html">&lt;p&gt;Are you thinking about &lt;a href=&quot;https://www.janestreet.com/join-jane-street/apply/&quot;&gt;applying&lt;/a&gt; to Jane Street for a developer role? Or already have a phone interview scheduled but unsure what to expect? Read on as we walk through an example phone interview with you.&lt;/p&gt;
&lt;p&gt;We want to give you some insight into what a typical Jane Street phone interview looks like and give you a chance to prepare. We're going to take a look at a question we call &quot;&lt;em&gt;Memo&lt;/em&gt;&quot; which we used to ask regularly (but of course don't ask anymore so no need to memorize anything on this page!). As such this post is meant to be a specific case analysis. If you haven't yet seen it, we recommend reading &lt;a href=&quot;https://blogs.janestreet.com/interviewing-at-jane-street/&quot;&gt;this blog post&lt;/a&gt; for a general overview what we are looking for in candidates.&lt;/p&gt; &lt;a href=&quot;https://blogs.janestreet.com/what-a-jane-street-dev-interview-is-like/&quot;&gt;&amp;#187; Continue Reading.&lt;/a&gt;</summary><source><updated>2017-05-11T19:02:45-00:00</updated><subtitle type="text">Jane Street' blogs (Systems and OCaml rolled into one)</subtitle><link type="application/atom+xml" href="https://blogs.janestreet.com/category/ocaml/feed/atom/" rel="self"/><link type="text/html" href="https://blogs.janestreet.com" rel="alternate"/><generator uri="https://wordpress.org/" version="4.7.4">WordPress</generator><id>https://blogs.janestreet.com/feed/atom/</id><title type="text">OCaml – Jane Street Tech Blogs</title><author><name>Jane Street</name></author></source><published>2017-02-28T17:00:08-00:00</published><link type="application/atom+xml" href="https://blogs.janestreet.com/what-a-jane-street-dev-interview-is-like/feed/atom/" rel="replies"/><link type="text/html" href="https://blogs.janestreet.com/what-a-jane-street-dev-interview-is-like/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=what-a-jane-street-dev-interview-is-like#comments" rel="replies"/><link type="text/html" href="https://blogs.janestreet.com/what-a-jane-street-dev-interview-is-like/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=what-a-jane-street-dev-interview-is-like" rel="alternate"/><content xml:base="https://blogs.janestreet.com/wp-atom.php" type="html">&lt;p&gt;Are you thinking about &lt;a href=&quot;https://www.janestreet.com/join-jane-street/apply/&quot;&gt;applying&lt;/a&gt; to Jane Street for a developer role? Or already have a phone interview scheduled but unsure what to expect? Read on as we walk through an example phone interview with you.&lt;/p&gt;
&lt;p&gt;We want to give you some insight into what a typical Jane Street phone interview looks like and give you a chance to prepare. We're going to take a look at a question we call &quot;&lt;em&gt;Memo&lt;/em&gt;&quot; which we used to ask regularly (but of course don't ask anymore so no need to memorize anything on this page!). As such this post is meant to be a specific case analysis. If you haven't yet seen it, we recommend reading &lt;a href=&quot;https://blogs.janestreet.com/interviewing-at-jane-street/&quot;&gt;this blog post&lt;/a&gt; for a general overview what we are looking for in candidates.&lt;/p&gt;
&lt;h2&gt;Getting started&lt;/h2&gt;
&lt;p&gt;To allow us to work on the question together, we'll use a shared online editor. We'll provide you with the link to use (either before hand or during the interview).&lt;/p&gt;
&lt;p&gt;We expect you to write code in a real programming language in the interview, not pseudo-code. You can use any programming language you'd like, but we strongly recommend you use the one you're most familiar with and will let you solve the problem in the best way (it's fine to change your mind as you're exploring the problem!). You should be comfortable with basic data structures and APIs in the language of your choice.&lt;/p&gt;
&lt;p&gt;Note, there are no bonus points for using a functional language like OCaml. Please don't use OCaml just because you think it will make us happy. We want to see you at your best, so you should use the language you're most comfortable with. If OCaml isn't your strongest language, then don't use it.&lt;/p&gt;
&lt;p&gt;If during the interview you realize you have seen a question before, then please let us know and we can do a different question. As you'll see in this post, knowing a question in advance greatly reduces what we can learn about you!&lt;/p&gt;
&lt;h2&gt;Part 1 - Basic coding&lt;/h2&gt;
&lt;p&gt;Have you heard about memoization? Can you carefully describe what it is? If you haven't heard about it, don't worry. We'll bring you up to speed. (A good introduction is on &lt;a href=&quot;https://en.wikipedia.org/wiki/Memoization&quot;&gt;Wikipedia&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;Now let's say there is a function &lt;code&gt;f&lt;/code&gt; of type &lt;code&gt;int -&amp;gt; int&lt;/code&gt; whose output only depends on the input. &lt;code&gt;f&lt;/code&gt; is very expensive to compute. We'd like you to write a memoized version of this function, i.e. another function &lt;code&gt;g&lt;/code&gt; of the same type, that returns the same values – &lt;code&gt;g(x) = f(x)&lt;/code&gt; for all x – but only does the expensive computation once for each input value.&lt;/p&gt;
&lt;p&gt;A typical first solution we're looking for at this stage uses a hash-table to store calculated results. A possible solution in OCaml might be:&lt;/p&gt;
&lt;pre class=&quot;ocaml&quot;&gt;&lt;ol&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;&lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; memo f =&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; results = Hashtbl.&lt;span style=&quot;color: #060;&quot;&gt;create&lt;/span&gt; &lt;span style=&quot;color: #c6c;&quot;&gt;256&lt;/span&gt; &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;in&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;  &lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;fun&lt;/span&gt; input -&amp;gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;     &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;match&lt;/span&gt; Hashtbl.&lt;span style=&quot;color: #060;&quot;&gt;find&lt;/span&gt; results input &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;with&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;     | None -&amp;gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;let&lt;/span&gt; result = f input &lt;span style=&quot;color: #06c; font-weight: bold;&quot;&gt;in&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        Hashtbl.&lt;span style=&quot;color: #060;&quot;&gt;add&lt;/span&gt; results ~key:input ~data:result;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;        result&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;&quot;&gt;&lt;div style=&quot;font-family: 'Courier New', Courier, monospace; font-weight: normal;&quot;&gt;     | Some result -&amp;gt; result&lt;span style=&quot;color: #6c6;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;(As I said above, you're not required or expected to write in OCaml but in this blog post I'm going to follow my own advice and use the language I'm most familiar with, which is OCaml. You might also object that this does a test-and-set without a lock, so can't possibly be thread-safe. Nice spot! For the purpose of this question let's ignore re-entry to focus on the core ideas.)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Whichever APIs or data structures you end up using for your solution: you should be prepared to talk about how they work and what the complexity of various operations is.&lt;/p&gt;
&lt;h2&gt;Part 2 - Reasoning about and improving your code&lt;/h2&gt;
&lt;p&gt;Can you think of any issues we could run into when using the function from part 1? For example, let's say we run your function in production and notice our application performs significantly worse than before. Quite the opposite from what we hoped memoization would do! Can you see what the problem might be?&lt;/p&gt;
&lt;p&gt;The big problem is memory usage. Our application might call &lt;code&gt;f&lt;/code&gt; with lots of different inputs and each result will be stored in the hashtable forever – a memory leak! Can you come up with some ideas to improve upon this?&lt;/p&gt;
&lt;p&gt;A reasonable approach to control the memory usage is to bound the size of the hash-table and to evict things from it in a FIFO fashion. What trade-offs does FIFO have versus other eviction schemes? How could you modify your memo function to implement FIFO? Let's aim for O(1) complexity when evicting from the cache.&lt;/p&gt;
&lt;p&gt;There are a few different ways to do this. A good solution keeps a separate queue: when adding a new result to your hashtable, if the size grows beyond the bound, then dequeue from the queue and remove that element from the hashtable.&lt;/p&gt;
&lt;p&gt;Besides being able to write code to do this, we look for how you communicate your thoughts on the problem and ideas to improve it. We don't necessarily expect every candidate to immediately jump to the O(1) solution, but we're interested in the process of talking through this problem and what you can come up with.&lt;/p&gt;
&lt;h2&gt;Part 3 - Going further&lt;/h2&gt;
&lt;p&gt;As you probably realize, FIFO can be very inefficient in some use-cases. Let's say we want to do LRU (least recently used) instead. We still want the implementation to be as efficient as possible. How can you implement this?&lt;/p&gt;
&lt;p&gt;Once more, there are multiple ways to do this. The easiest solution stores timestamps with each value in the hashtable and linearly scans through the table when evicting. This is O(n). It's possible to improve to O(log n) using a min-heap or even to O(1) using a doubly-linked list.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Side-note: implementing the most efficient solution&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;One way to get to O(1) is to maintain a doubly linked list and make the values in the hash-table point to elements in that list. Then when looking up a cached value in the hash-table, you can slice it out of its current position in the list and put it at the top in O(1). You maintain a separate pointer to the bottom of the doubly linked list to evict in O(1).&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Few candidates come up with the doubly-linked list immediately, so don't worry if this is not something you thought of straight away. While we might ask you to implement parts of your solution, this part is intended as a discussion and test your ideas for improving complexity. We'll guide you to the right level of abstraction, so you don't have to worry too much about which details to include.&lt;/p&gt;
&lt;p&gt;We also have various other extensions for this question that make it possible to keep going further as far as time allows.&lt;/p&gt;
&lt;h2&gt;What we look for&lt;/h2&gt;
&lt;p&gt;Again, for a good overview see &lt;a href=&quot;https://blogs.janestreet.com/interviewing-at-jane-street/&quot;&gt;this post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While interviewing, we try to evaluate how well you would fit in our work environment by collaboratively solving a problem. This means the journey through the interview is a lot more important than the snapshot of the solution at the end of it. We are more interested in seeing how you approach a difficult problem than just capturing a boolean flag whether you can come up with the solution.&lt;/p&gt;
&lt;p&gt;As a concrete example, we might prefer a candidate that wrote careful and clear code, communicated well and had good insights and ideas along the way, but didn't get as far through the problem compared to another candidate that immediately solved every part but was sloppy and hard to follow.&lt;/p&gt;
&lt;p&gt;This makes it impossible to give a rigid set of requirements of what needs to be achieved during the interview. Nevertheless, to give you some rough guidelines:&lt;/p&gt;
&lt;p&gt;Every successful candidate should achieve a bug-free solution for part 1 relatively quickly. If some of part 1 sounds unfamiliar to you, it might be better to hold off applying to give yourself more time to prepare.&lt;/p&gt;
&lt;p&gt;Most candidates that we pass also complete part 2 fully in the time of the interview. Strong candidates finish part 3 with a complete solution, but not finishing this part doesn't mean that you will be rejected! As said above, it's what happens during the interview that really counts, not the result at the end.&lt;/p&gt;
&lt;h2&gt;Sharing questions afterwards&lt;/h2&gt;
&lt;p&gt;We are interested in seeing you approach a difficult problem and walk through the process of deriving a solution with you. If you already know the question in advance (either by finding it online, or by talking to friends who have previously applied), it reduces the efficacy of the interview: We now only get to test if you can write code for a problem you've already understood and solved, which is a small subset of things we are interested in learning about. For example, if you've read through this post, we wouldn't learn much from asking you &lt;em&gt;Memo&lt;/em&gt;!&lt;/p&gt;
&lt;p&gt;Thus we would like to ask you &lt;em&gt;not to share the interview question&lt;/em&gt; with anybody else (in person or online).&lt;/p&gt;
&lt;h2&gt;What happens next&lt;/h2&gt;
&lt;p&gt;We usually try to get back to you about the outcome of the interview within one week. During busy periods this might take a bit longer, but not hearing from us after 10 days is unexpected and you should definitely poke us.&lt;/p&gt;
&lt;p&gt;If the interview went well, we invite you to come to one of our offices (New York, London or Hong Kong) for a day of onsite interviews. These proceed in much the same way as the phone interview – all questions are technical.&lt;/p&gt;
&lt;h2&gt;Ready to apply?&lt;/h2&gt;
&lt;p&gt;If you read this post and feel ready to apply, then simply &lt;strong&gt;&lt;a href=&quot;https://www.janestreet.com/join-jane-street/apply/&quot;&gt;go here&lt;/a&gt;&lt;/strong&gt;. We have a very straightforward application process – all we need is your resume or CV. We look forward to interviewing you!&lt;/p&gt;
</content><category scheme="https://blogs.janestreet.com" term="OCaml"/><id>https://blogs.janestreet.com/?p=1628</id><title xml:base="https://blogs.janestreet.com/wp-atom.php" type="html">What a Jane Street dev interview is like</title><updated>2017-03-01T08:50:29-00:00</updated><author><name>Sebastian Funk</name></author></entry><entry><source><updated>2017-05-09T12:00:00-00:00</updated><link title="OCaml Weekly News" type="text/html" href="http://alan.petitepomme.net/cwn/" rel="related"/><link title="OCaml Weekly News" type="application/rss+xml" href="http://alan.petitepomme.net/cwn/cwn.rss" rel="self"/><id>http://alan.petitepomme.net/cwn/</id><title type="text">OCaml Weekly News</title><author><name>OCaml Weekly News</name></author></source><link href="http://alan.petitepomme.net/cwn/2017.02.28.html" rel="alternate"/><content xml:base="http://alan.petitepomme.net/cwn/cwn.rss" type="html">&lt;ol&gt;&lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.02.28.html#1&gt;List of structurally typed objects&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.02.28.html#2&gt;mirage 3.0.0&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.02.28.html#3&gt;Ocaml Github Pull Requests&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=http://alan.petitepomme.net/cwn/2017.02.28.html#4&gt;Other OCaml News&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;</content><id>http://alan.petitepomme.net/cwn/2017.02.28.html</id><title type="text">Weekly News</title><updated>2017-02-28T12:00:00-00:00</updated><author><name>OCaml Weekly News</name></author></entry><entry><summary xml:base="http://erratique.ch/" type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">Ten years ago I published a <a href="http://alan.petitepomme.net/cwn/2007.02.27.html#3">first bit</a> of free software. Over the <a href="tags/OCaml">years</a>, this has now expanded to 28 OCaml packages, without counting random informally published elucubrations. Thanks to <a href="http://ocamllabs.io">OCaml Labs</a>' support, there will be more.</div></summary><source><updated>2017-02-27T19:15:55-00:00</updated><rights type="text">Copyright © 2007-2017, Daniel Bünzli</rights><link type="text/html" href="http://erratique.ch/" rel="alternate"/><link href="http://erratique.ch/feeds/news.atom" rel="self"/><icon>http://erratique.ch/images/e-small.png</icon><id>urn:uuid:3a8dc03a-ee18-4144-ab7a-a6bd91e1972a</id><title type="text">Erratique</title><author><name>Daniel Bünzli</name></author></source><link href="http://erratique.ch/contact.en" rel="alternate"/><category term="erratique-news"/><id>urn:uuid:e53a84e0-a842-525c-adc6-8393a5806063</id><title type="text">10</title><updated>2017-02-27T19:15:55-00:00</updated><author><name>Daniel Bünzli</name></author></entry><entry><source><updated>2017-02-23T13:57:42-00:00</updated><rights type="text">Content is available under  unless otherwise noted.</rights><link title="the OCaml Labs wiki - Blog:News [en]" type="text/html" href="https://ocaml.io/w/Blog:News" rel="related"/><link title="the OCaml Labs wiki - Blog:News [en]" type="application/rss+xml" href="https://ocaml.io/index.php?title=Blog:News&amp;feed=rss" rel="self"/><generator>MediaWiki 1.26.2</generator><id>https://ocaml.io/w/Blog:News</id><title type="text">the OCaml Labs wiki - Blog:News [en]</title><author><name>OCaml Labs</name></author></source><link href="https://ocaml.io/w/Blog:News/Moving_from_ocaml.io_to_ocamllabs.io" rel="alternate"/><link href="https://ocaml.io/w/Blog_talk:News/Moving_from_ocaml.io_to_ocamllabs.io" rel="related"/><content xml:base="https://ocaml.io/index.php?title=Blog:News&amp;feed=rss" type="html">&lt;p&gt;We are pleased to announce that the new and improved &lt;a rel=&quot;nofollow&quot; class=&quot;external text&quot; href=&quot;http://ocamllabs.io/&quot;&gt;OCaml Labs website&lt;/a&gt; is here! 
&lt;/p&gt;&lt;p&gt;This wiki will remain active while we transition our content to &lt;a rel=&quot;nofollow&quot; class=&quot;external text&quot; href=&quot;http://ocamllabs.io/&quot;&gt;ocamllabs.io&lt;/a&gt;, but it will be retired eventually. The new site will have all the recent news and exciting developments from OCaml Labs together with links to related projects and people, so it will be easier than ever to keep up to date with everything we are doing. 
&lt;/p&gt;&lt;p&gt;We hope you enjoy the new site!
&lt;/p&gt;
</content><id>https://ocaml.io/w/Blog:News/Moving_from_ocaml.io_to_ocamllabs.io</id><title type="text">Moving from ocaml.io to ocamllabs.io</title><updated>2017-02-23T13:57:42-00:00</updated><author><name>OCaml Labs</name></author></entry><entry><summary type="text">&lt;p&gt;Conex is a library to verify and attest package release integrity and authenticity through the use of cryptographic signatures.&lt;/p&gt;
</summary><source><updated>2017-03-12T13:27:37-00:00</updated><link href="https://hannes.nqsb.io/atom" rel="self"/><id>urn:uuid:981361ca-e71d-4997-a52c-baeee78e4156</id><title type="text">full stack engineer</title><author><name>Hannes Mehnert</name></author></source><published>2017-02-16T23:35:02-00:00</published><link href="https://hannes.nqsb.io/Posts/Conex" rel="alternate"/><content xml:base="https://hannes.nqsb.io/atom" type="html">

&lt;p&gt;Less than two years after the initial proposal, we&amp;#39;re happy to present conex
0.9.2.  Pleas note that this is still work in progress, to be deployed with opam
2.0 and the &lt;a href='https://github.com/ocaml/opam-repository'&gt;opam repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src='https://berlin.ccc.de/~hannes/conex.png' alt='screenshot' /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href='https://github.com/hannesm/conex'&gt;Conex&lt;/a&gt; is a library to verify and attest release integrity and
authenticity of a community repository through the use of cryptographic signatures.&lt;/p&gt;
&lt;p&gt;Packages are collected in a community repository to provide an index and
allowing cross-references.  Authors submit their packages to the repository. which
is curated by a team of janitors.  Information
about a package stored in a repository includes: license, author, releases,
their dependencies, build instructions, url, tarball checksum.  When someone
publishes a new package, the janitors integrate it into the repository, if it
compiles and passes some validity checks.  For example, its name must not be misleading,
nor may it be too general.&lt;/p&gt;
&lt;p&gt;Janitors keep an eye on the repository and fix emergent failures.  A new
compiler release, or a release of a package on which other packages depend, might break the compilation of
a package.  Janitors usually fix these problems by adding a patch to the build script, or introducing
a version constraint in the repository.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Conex&lt;/em&gt; ensures that every release of each package has been approved by its author or a quorum of janitors.
A conex-aware client initially verifies the repository using janitor key fingerprints as anchor.
Afterwards, the on-disk repository is trusted, and every update is verified (as a patch) individually.
This incremental verification is accomplished by ensuring all resources
that the patch modifies result in a valid repository with
sufficient approvals.  Additionally, monotonicity is preserved by
embedding counters in each resource, and enforcing a counter
increment after modification.
This mechanism avoids rollback attacks, when an
attacker presents you an old version of the repository.&lt;/p&gt;
&lt;p&gt;A timestamping service (NYI) will periodically approve a global view of the
verified repository, together with a timestamp.  This is then used by the client
to prevent mix-and-match attacks, where an attacker mixes some old packages and
some new ones.  Also, the client is able to detect freeze attacks, since at
least every day there should be a new signature done by the timestamping service.&lt;/p&gt;
&lt;p&gt;The trust is rooted in digital signatures by package authors.  The server which
hosts the repository does not need to be trusted.  Neither does the host serving
release tarballs.&lt;/p&gt;
&lt;p&gt;If a single janitor would be powerful enough to approve a key for any author,
compromising one janitor would be sufficient to enroll any new identities,
modify dependencies, build scripts, etc.  In conex, a quorum of janitors (let&amp;#39;s
say 3) have to approve such changes.  This is different from current workflows,
where a single janitor with access to the repository can merge fixes.&lt;/p&gt;
&lt;p&gt;Conex adds metadata, in form of resources, to the repository to ensure integrity and
authenticity.  There are different kinds of resources:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;em&gt;Authors&lt;/em&gt;, consisting of a unique identifier, public key(s), accounts.&lt;/li&gt;&lt;li&gt;&lt;em&gt;Teams&lt;/em&gt;, sharing the same namespace as authors, containing a set of members.&lt;/li&gt;&lt;li&gt;&lt;em&gt;Authorisation&lt;/em&gt;, one for each package, describing which identities are authorised for the package.&lt;/li&gt;&lt;li&gt;&lt;em&gt;Package index&lt;/em&gt;, for each package, listing all releases.&lt;/li&gt;&lt;li&gt;&lt;em&gt;Release&lt;/em&gt;, for each release, listing checksums of all data files.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Modifications to identities and authorisations need to be approved by a quorum
of janitors, package index and release files can be modified either by an authorised
id or by a quorum of janitors.&lt;/p&gt;
&lt;h2 id=&quot;Documentation&quot;&gt;Documentation&lt;/h2&gt;

&lt;p&gt;&lt;a href='https://hannesm.github.io/conex/doc/'&gt;API documentation&lt;/a&gt; is
available online, also a &lt;a href='https://hannesm.github.io/conex/coverage/'&gt;coverage
report&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We presented an &lt;a href='https://github.com/hannesm/conex-paper/raw/master/paper.pdf'&gt;abstract at OCaml
2016&lt;/a&gt; about an
earlier design.&lt;/p&gt;
&lt;p&gt;Another article on an &lt;a href='http://opam.ocaml.org/blog/Signing-the-opam-repository/'&gt;earlier design (from
2015)&lt;/a&gt; is also
available.&lt;/p&gt;
&lt;p&gt;Conex is inspired by &lt;a href='https://theupdateframework.github.io/'&gt;the update
framework&lt;/a&gt;, especially on their &lt;a href='https://isis.poly.edu/~jcappos/papers/samuel_tuf_ccs_2010.pdf'&gt;CCS 2010
paper&lt;/a&gt;, and
adapted to the opam repository.&lt;/p&gt;
&lt;p&gt;The &lt;a href='https://github.com/theupdateframework/tuf/blob/develop/docs/tuf-spec.txt'&gt;TUF
spec&lt;/a&gt;
has a good overview of attacks and threat model, both of which are shared by conex.&lt;/p&gt;
&lt;h2 id=&quot;What39smissing&quot;&gt;What&amp;#39;s missing&lt;/h2&gt;

&lt;ul&gt;&lt;li&gt;See &lt;a href='https://github.com/hannesm/conex/issues/7'&gt;issue 7&lt;/a&gt; for a laundry list&lt;/li&gt;&lt;li&gt;Timestamping service&lt;/li&gt;&lt;li&gt;Key revocation and rollover&lt;/li&gt;&lt;li&gt;Tool to approve a PR (for janitors)&lt;/li&gt;&lt;li&gt;Camelus like opam-repository check bot&lt;/li&gt;&lt;li&gt;Integration into release management systems&lt;/li&gt;&lt;/ul&gt;

&lt;h2 id=&quot;Gettingstarted&quot;&gt;Getting started&lt;/h2&gt;

&lt;p&gt;At the moment, our &lt;a href='https://github.com/ocaml/opam-repository'&gt;opam repository&lt;/a&gt;
does not include any metadata needed for signing.  We&amp;#39;re in a bootstrap phase:
we need you to generate a keypair, claim your packages, and approve your releases.&lt;/p&gt;
&lt;p&gt;We cannot verify the main opam repository yet, but opam2 has support for a
&lt;a href='http://opam.ocaml.org/doc/2.0/Manual.html#configfield-repository-validation-command'&gt;&lt;code&gt;repository validation command&lt;/code&gt;&lt;/a&gt;,
builtin, which should then call out to &lt;code&gt;conex_verify&lt;/code&gt; (there is a &lt;code&gt;--nostrict&lt;/code&gt;
flag for the impatient).  There is also an &lt;a href='https://github.com/hannesm/testrepo'&gt;example repository&lt;/a&gt; which uses the opam validation command.&lt;/p&gt;
&lt;p&gt;To reduce the manual work, we analysed 7000 PRs of the opam repository within
the last 4.5 years (more details &lt;a href='https://hannes.nqsb.io/Posts/Maintainers'&gt;here&lt;/a&gt;.
This resulted in an educated guess who are the people
modifying each package, which we use as a basis whom to authorise for
which packages.  Please check with &lt;code&gt;conex_author status&lt;/code&gt; below whether your team
membership and authorised packages were inferred correctly.&lt;/p&gt;
&lt;p&gt;Each individual author - you - need to generate their private key, submit
their public key and starts approving releases (and old ones after careful
checking that the build script, patches, and tarball checksum are valid).
Each resource can be approved in multiple versions at the same time.&lt;/p&gt;
&lt;h3 id=&quot;Installation&quot;&gt;Installation&lt;/h3&gt;

&lt;p&gt;TODO: remove clone once &lt;a href='https://github.com/ocaml/opam-repository/pull/8494'&gt;PR 8494&lt;/a&gt; is merged.&lt;/p&gt;
&lt;pre class='bash'&gt;&lt;code class='bash'&gt;$ git clone -b auth https://github.com/hannesm/opam-repository.git repo
$ opam install conex
$ cd repo&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will install conex, namely command line utilities, &lt;code&gt;conex_author&lt;/code&gt; and
&lt;code&gt;conex_verify_nocrypto&lt;/code&gt;/&lt;code&gt;conex_verify_openssl&lt;/code&gt;.  All files read and written by conex are in the usual
opam file format.  This means can always manually modify them (but be careful,
modifications need to increment counters, add checksums, and be signed).  Conex
does not deal with git, you have to manually &lt;code&gt;git add&lt;/code&gt; files and open pull
requests.&lt;/p&gt;
&lt;h3 id=&quot;Authorenrollment&quot;&gt;Author enrollment&lt;/h3&gt;

&lt;p&gt;For the opam repository, we will use GitHub ids as conex ids.  Thus, your conex
id and your GitHub id should match up.&lt;/p&gt;
&lt;pre class='bash'&gt;&lt;code class='bash'&gt;repo$ conex_author init --repo ~/repo --id hannesm
Created keypair hannesm.  Join teams, claim your packages, sign your approved resources and open a PR :)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This attempts to parse &lt;code&gt;~/repo/id/hannesm&lt;/code&gt;, errors if it is a team or an author
with a publickey.  Otherwise it generates a keypair, writes the private part as
&lt;code&gt;home.hannes.repo.hannesm.private&lt;/code&gt; (the absolute path separated by dots,
followed by your id, and &lt;code&gt;private&lt;/code&gt; - if you move your repository, rename your
private key) into &lt;code&gt;~/.conex/&lt;/code&gt;, the checksums of the public part and your
accounts into &lt;code&gt;~/repo/id/hannesm&lt;/code&gt;.  See &lt;code&gt;conex_author help init&lt;/code&gt; for more
options (esp. additional verbosity &lt;code&gt;-v&lt;/code&gt; can be helpful).&lt;/p&gt;
&lt;pre class='bash'&gt;&lt;code class='bash'&gt;repo$ git status -s
 M id/hannesm

repo$ git diff //abbreviated output
-  [&amp;quot;counter&amp;quot; 0x0]
+  [&amp;quot;counter&amp;quot; 0x1]

-  [&amp;quot;resources&amp;quot; []]
+  [
+    &amp;quot;resources&amp;quot;
+    [
+      [
+        [&amp;quot;typ&amp;quot; &amp;quot;key&amp;quot;]
+        [&amp;quot;name&amp;quot; &amp;quot;hannesm&amp;quot;]
+        [&amp;quot;index&amp;quot; 0x1]
+        [&amp;quot;digest&amp;quot; [&amp;quot;SHA256&amp;quot; &amp;quot;ht9ztjjDwWwD/id6LSVi7nKqVyCHQuQu9ORpr8Zo2aY=&amp;quot;]]
+      ]
+      [
+        [&amp;quot;typ&amp;quot; &amp;quot;account&amp;quot;]
+        [&amp;quot;name&amp;quot; &amp;quot;hannesm&amp;quot;]
+        [&amp;quot;index&amp;quot; 0x2]
+        [&amp;quot;digest&amp;quot; [&amp;quot;SHA256&amp;quot; &amp;quot;aCsktJ5M9PI6T+m1NIQtuIFYILFkqoHKwBxwvuzpuzg=&amp;quot;]]
+      ]
+
+keys: [
+  [
+    [
+      &amp;quot;RSA&amp;quot;
+      &amp;quot;&amp;quot;&amp;quot;
+-----BEGIN PUBLIC KEY-----
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAyUhArwt4XcxLanARyH9S
...
+9KQdg6QnLsQh/j74QKLOZacCAwEAAQ==
+-----END PUBLIC KEY-----&amp;quot;&amp;quot;&amp;quot;
+      0x58A3419F
+    ]
+    [
+      0x58A79A1D
+      &amp;quot;RSA-PSS-SHA256&amp;quot;
+      &amp;quot;HqqicsDx4hG9pFM5E7&amp;quot;
+    ]
+  ]
+]&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;Status&quot;&gt;Status&lt;/h3&gt;

&lt;p&gt;If you have a single identity and contribute to a single signed opam repository,
you don&amp;#39;t need to specify &lt;code&gt;--id&lt;/code&gt; or &lt;code&gt;--repo&lt;/code&gt; from now on.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;status&lt;/code&gt; subcommand presents an author-specific view on the repository.  It
lists the own public keys, team membership, queued resources, and authorised
packages.&lt;/p&gt;
&lt;p&gt;The opam repository is in a transitionary state, we explicitly pass &lt;code&gt;--quorum
0&lt;/code&gt;, which means that every checksum is valid (approved by a quorum of 0
janitors).&lt;/p&gt;
&lt;pre class='bash'&gt;&lt;code class='bash'&gt;repo$ conex_author status --quorum 0 arp
author hannesm #1 (created 0) verified 3 resources, 0 queued
4096 bit RSA key created 1487094175 approved, SHA256: ht9ztjjDwWwD/id6LSVi7nKqVyCHQuQu9ORpr8Zo2aY=
account GitHub hannesm approved
account email hannes@mehnert.org approved
package arp authorisation approved
conex_author: [ERROR] package index arp was not found in repository&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This shows your key material and accounts, team membership and packages you are
authorised to modify (inferred as described
&lt;a href='https://hannes.nqsb.io/Posts/Maintainer'&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;--noteam&lt;/code&gt; argument limits the package list to only these you are personally
authorised for.  The &lt;code&gt;--id&lt;/code&gt; argument presents you with a view of another author,
or from a team perspective.  The positional argument is a prefix matching on
package names (leave empty for all).&lt;/p&gt;
&lt;h3 id=&quot;Resourceapproval&quot;&gt;Resource approval&lt;/h3&gt;

&lt;p&gt;Each resource needs to be approved individually.  Each author has a local queue
for to-be-signed resources, which is extended with &lt;code&gt;authorisation&lt;/code&gt;, &lt;code&gt;init&lt;/code&gt;,
&lt;code&gt;key&lt;/code&gt;, &lt;code&gt;release&lt;/code&gt;, and &lt;code&gt;team&lt;/code&gt; (all have a &lt;code&gt;--dry-run&lt;/code&gt; flag).  The queue can be
dropped using &lt;code&gt;conex_author reset&lt;/code&gt;.  Below shown is &lt;code&gt;conex_author sign&lt;/code&gt;, which
let&amp;#39;s you interactively approve queued resources and cryptopgraphically signs
your approved resources afterwards.&lt;/p&gt;
&lt;p&gt;The output of &lt;code&gt;conex_author status&lt;/code&gt; listed an authorisation for &lt;code&gt;conf-gsl&lt;/code&gt;,
which I don&amp;#39;t feel responsible for.  Let&amp;#39;s drop my privileges:&lt;/p&gt;
&lt;pre class='bash'&gt;&lt;code class='bash'&gt;repo$ conex_author authorisation conf-gsl --remove -m hannesm
modified authorisation and added resource to your queue.&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I checked my arp release careful (checksums of tarballs are correct, opam files
do not execute arbitrary shell code, etc.), and approve this package and its
single release:&lt;/p&gt;
&lt;pre class='bash'&gt;&lt;code class='bash'&gt;repo$ conex_author release arp
conex_author.native: [WARNING] package index arp was not found in repository
conex_author.native: [WARNING] release arp.0.1.1 was not found in repository
wrote release and added resources to your queue.&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once finished with joining and leaving teams (using the &lt;code&gt;team&lt;/code&gt; subcommand),
claiming packages (using the &lt;code&gt;authorisation&lt;/code&gt; subcommand), and approve releases
(using the &lt;code&gt;release&lt;/code&gt; subcommand), you have to cryprographically sign your queued
resource modifications:&lt;/p&gt;
&lt;pre class='bash'&gt;&lt;code class='bash'&gt;repo$ conex_author sign
release arp.0.1.1 #1 (created 1487269425)
[descr: SHA256: aCsNvcj3cBKO0GESWG4r3AzoUEnI0pHGSyEDYNPouoE=;
opam: SHA256: nqy6lD1UP+kXj3+oPXLt2VMUIENEuHMVlVaG2V4z3p0=;
url: SHA256: FaUPievda6cEMjNkWdi0kGVK7t6EpWGfQ4q2NTSTcy0=]
approved (yes/No)?
package arp #1 (created 1487269425) [arp.0.1.1]
approved (yes/No)?y
authorisation conf-gsl #1 (created 0) empty
approved (yes/No)?y
wrote hannesm to disk

repo$ conex_author status --quorum 0 arp
author hannesm #1 (created 0) verified 7 resources, 0 queued
4096 bit RSA key created 1487094175 approved, SHA256: ht9ztjjDwWwD/id6LSVi7nKqVyCHQuQu9ORpr8Zo2aY=
account GitHub hannesm approved
account email hannes@mehnert.org approved
package arp authorisation approved package index approved
release arp.0.1.1: approved&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you now modify anything in &lt;code&gt;packages/arp&lt;/code&gt; (add subdirectories, modify opam,
etc.), this will not be automatically approved (see below for how to do this).&lt;/p&gt;
&lt;p&gt;You manually need to &lt;code&gt;git add&lt;/code&gt; some created files.&lt;/p&gt;
&lt;pre class='bash'&gt;&lt;code class='bash'&gt;repo$ git status -s
 M id/hannesm
 M packages/conf-gsl/authorisation
?? packages/arp/arp.0.1.1/release
?? packages/arp/package

repo$ git add packages/arp/arp.0.1.1/release packages/arp/package
repo$ git commit -m &amp;quot;hannesm key enrollment and some fixes&amp;quot; id packages&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now push this to your fork, and open a PR on opam-repository!&lt;/p&gt;
&lt;h3 id=&quot;Editingapackage&quot;&gt;Editing a package&lt;/h3&gt;

&lt;p&gt;If you need to modify a released package, you modify the opam file (as before,
e.g. introducing a conflict with a dependency), and then approve the
modifications.  After your local modifications, &lt;code&gt;conex_author status&lt;/code&gt; will
complain:&lt;/p&gt;
&lt;pre class='bash'&gt;&lt;code class='bash'&gt;repo$ conex_author status arp --quorum 0
package arp authorisation approved package index approved
release arp.0.1.1: checksums for arp.0.1.1 differ, missing on disk: empty, missing in checksums file: empty, checksums differ: [have opam: SHA256: QSGUU9HdPOrwoRs6XJka4cZpd8h+8NN1Auu5IMN8ew4= want opam: SHA256: nqy6lD1UP+kXj3+oPXLt2VMUIENEuHMVlVaG2V4z3p0=]

repo$ conex_author release arp.0.1.1
released and added resources to your resource list.

repo$ conex_author sign
release arp.0.1.1 #1 (created 1487269943)
[descr: SHA256: aCsNvcj3cBKO0GESWG4r3AzoUEnI0pHGSyEDYNPouoE=;
opam: SHA256: QSGUU9HdPOrwoRs6XJka4cZpd8h+8NN1Auu5IMN8ew4=;
url: SHA256: FaUPievda6cEMjNkWdi0kGVK7t6EpWGfQ4q2NTSTcy0=]
approved (yes/No)? y
wrote hannesm to disk&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;release&lt;/code&gt; subcommand recomputed the checksums, incremented the counter, and
added it to your queue.  The &lt;code&gt;sign&lt;/code&gt; command signed the approved resource.&lt;/p&gt;
&lt;pre class='bash'&gt;&lt;code class='bash'&gt;repo$ git status -s
 M id/hannesm
 M packages/arp/arp.0.1.1/opam
 M packages/arp/arp.0.1.1/package

repo$ git commit -m &amp;quot;fixed broken arp package&amp;quot; id packages&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;Janitortools&quot;&gt;Janitor tools&lt;/h3&gt;

&lt;p&gt;Janitors need to approve teams, keys, accounts, and authorisations.&lt;/p&gt;
&lt;p&gt;To approve resources which are already in the repository on disk,
the &lt;code&gt;key&lt;/code&gt; subcommand queues approval of keys and accounts of the provided author:&lt;/p&gt;
&lt;pre class='bash'&gt;&lt;code class='bash'&gt;repo$ conex_author key avsm
added keys and accounts to your resource list.&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;authorisation&lt;/code&gt; subcommand, and &lt;code&gt;team&lt;/code&gt; subcommand behave similarly for
authorisations and teams.&lt;/p&gt;
&lt;p&gt;Bulk operations are supported as well:&lt;/p&gt;
&lt;pre class='bash'&gt;&lt;code class='bash'&gt;conex_author authorisation all&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will approve all authorisations of the repository which are not yet
approved by you.  Similar for the &lt;code&gt;key&lt;/code&gt; and &lt;code&gt;team&lt;/code&gt; subcommands, which also
accept &lt;code&gt;all&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Don&amp;#39;t forget to &lt;code&gt;conex_author sign&lt;/code&gt; afterwards (or &lt;code&gt;yes | conex_author sign&lt;/code&gt;).&lt;/p&gt;
&lt;h3 id=&quot;Verification&quot;&gt;Verification&lt;/h3&gt;

&lt;p&gt;The two command line utlities, &lt;code&gt;conex_verify_openssl&lt;/code&gt; and
&lt;code&gt;conex_verify_nocrypto&lt;/code&gt; contain the same logic and same command line arguments.&lt;/p&gt;
&lt;p&gt;For bootstrapping purposes (&lt;code&gt;nocrypto&lt;/code&gt; is an opam package with dependencies),
&lt;code&gt;conex_verify_openssl&lt;/code&gt; relies on the openssl command line tool (version 1.0.0
and above) for digest computation and verification of the RSA-PSS signature.&lt;/p&gt;
&lt;p&gt;The goal is to use the opam2 provided hooks, but before we have signatures we
cannot enable them.&lt;/p&gt;
&lt;p&gt;See the &lt;a href='https://github.com/hannesm/testrepo'&gt;example repository&lt;/a&gt; for initial
verification experiments, and opam2 integration.&lt;/p&gt;
&lt;p&gt;I&amp;#39;m interested in feedback, please open an issue on the &lt;a href='https://github.com/hannesm/conex'&gt;conex
repository&lt;/a&gt;.  This article itself is stored as
Markdown &lt;a href='https://github.com/hannesm/hannes.nqsb.io'&gt;in a different repository&lt;/a&gt;.&lt;/p&gt;
</content><category scheme="https://hannes.nqsb.io/tags/package%20signing" term="package signing"/><category scheme="https://hannes.nqsb.io/tags/security" term="security"/><category scheme="https://hannes.nqsb.io/tags/overview" term="overview"/><id>urn:uuid:c9891387-b8e3-5214-9104-e605427827d4</id><title type="text">Conex, establish trust in community repositories</title><updated>2017-02-20T20:33:56-00:00</updated><author><name>hannes</name></author></entry><entry><summary type="text">&lt;p&gt;We describe why manual gathering of metadata is out of date, and version control systems are awesome.&lt;/p&gt;
</summary><source><updated>2017-03-12T13:27:37-00:00</updated><link href="https://hannes.nqsb.io/atom" rel="self"/><id>urn:uuid:981361ca-e71d-4997-a52c-baeee78e4156</id><title type="text">full stack engineer</title><author><name>Hannes Mehnert</name></author></source><published>2017-02-16T23:28:44-00:00</published><link href="https://hannes.nqsb.io/Posts/Maintainers" rel="alternate"/><content xml:base="https://hannes.nqsb.io/atom" type="html">

&lt;p&gt;A very important data point for conex, the new opam signing utility, is who is authorised for a given package.  We
could have written this manually down, or force each author to create a
pull request for their packages, but this would be a long process and not
easy: the main opam repository has around 1500 unique packages, and 350
contributors.  Fortunately, it is a git repository with 5 years of history, and
over 6900 pull requests.  Each opam file may also contain a &lt;code&gt;maintainers&lt;/code&gt; entry,
a list of strings (usually a mail address).&lt;/p&gt;
&lt;p&gt;The data sources we correlate are the &lt;code&gt;maintainers&lt;/code&gt; entry in opam file, and who
actually committed in the opam repository.  This is inspired by &lt;a href='https://github.com/ocaml/opam/issues/2693'&gt;some GitHub
discussion&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;GitHubidandemailaddress&quot;&gt;GitHub id and email address&lt;/h3&gt;

&lt;p&gt;For simplicity, since conex uses any (unique) identifier for authors, and the opam
repository is hosted on GitHub, we use a GitHub id as author identifier.
Maintainer information is an email address, thus we need a mapping between them.&lt;/p&gt;
&lt;p&gt;We wrote a &lt;a href='https://raw.githubusercontent.com/hannesm/conex/master/analysis/loop-prs.sh'&gt;shell
script&lt;/a&gt;
to find all PR merges, their GitHub id (in a brittle way: using the name of the
git remote), and email address of the last commit.  It also saves a diff of the
PR for later.  This results in 6922 PRs (opam repository version 38d908dcbc58d07467fbc00698083fa4cbd94f9d).&lt;/p&gt;
&lt;p&gt;The metadata output is processed by
&lt;a href='https://github.com/hannesm/conex/blob/dbdfc5337c97d62edc74f1c546023bcb5e719343/analysis/maintainer.ml#L134-L156'&gt;github_mail&lt;/a&gt;:
we ignore PRs from GitHub organisations &lt;code&gt;PR.ignore_github&lt;/code&gt;, where commits
&lt;code&gt;PR.ignore_pr&lt;/code&gt; are picked from a different author (manually), bad mail addresses,
and &lt;a href='https://github.com/yallop'&gt;Jeremy&amp;#39;s&lt;/a&gt; mail address (it is added to too many GitHub ids otherwise).  The
goal is to have a for an email address a single GitHub id.  329 authors with 416 mail addresses are mapped.&lt;/p&gt;
&lt;h3 id=&quot;Maintainerinopam&quot;&gt;Maintainer in opam&lt;/h3&gt;

&lt;p&gt;As mentioned, lots of packages contain a &lt;code&gt;maintainers&lt;/code&gt; entry.  In
&lt;a href='https://github.com/hannesm/conex/blob/dbdfc5337c97d62edc74f1c546023bcb5e719343/analysis/maintainer.ml#L40-L68'&gt;&lt;code&gt;maintainers&lt;/code&gt;&lt;/a&gt;
we extract the mail addresses of the &lt;a href='https://github.com/hannesm/conex/blob/dbdfc5337c97d62edc74f1c546023bcb5e719343/analysis/maintainer.ml#L70-L94'&gt;most recently released opam
file&lt;/a&gt;.
Some hardcoded matches are teams which do not properly maintain the maintainers
field (such as mirage and xapi-project ;).  We&amp;#39;re open for suggestions to extend
this massaging to the needs.  Additionally, the contact at ocamlpro mail address
was used for all packages before the maintainers entry was introduced (based on
a discussion with Louis Gesbert).  132 packages with empty maintainers.&lt;/p&gt;
&lt;h3 id=&quot;Fitness&quot;&gt;Fitness&lt;/h3&gt;

&lt;p&gt;Combining these two data sources, we hoped to find a strict small set of whom to
authorise for which package.  Turns out some people use different mail addresses
for git commits and opam maintainer entries, which &lt;a href='https://github.com/hannesm/conex/blob/dbdfc5337c97d62edc74f1c546023bcb5e719343/analysis/maintainer.ml#L233-L269'&gt;are be easily
fixed&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While &lt;a href='https://github.com/hannesm/conex/blob/dbdfc5337c97d62edc74f1c546023bcb5e719343/analysis/maintainer.ml#L169-L205'&gt;processing the full diffs of each
PR&lt;/a&gt;
(using the diff parser of conex mentioned above), ignoring the 44% done by
&lt;a href='https://github.com/hannesm/conex/blob/dbdfc5337c97d62edc74f1c546023bcb5e719343/analysis/maintainer.ml#L158-L165'&gt;janitors&lt;/a&gt;
(a manually created set by looking at log data, please report if wrong), we
categorise the modifications: authorised modification (the GitHub id is
authorised for the package), modification by an author to a team-owned package
(propose to add this author to the team), modification of a package where no
GitHub id is authorised, and unauthorised modification.  We also ignore packages
which are no longer in the opam repository.&lt;/p&gt;
&lt;p&gt;2766 modifications were authorised, 418 were team-owned, 452 were to packages
with no maintainer, and 570 unauthorised.  This results in 125 unowned packages.&lt;/p&gt;
&lt;p&gt;Out of the 452 modifications to packages with no maintainer, 75 are a global
one-to-one author to package relation, and are directly authorised.&lt;/p&gt;
&lt;p&gt;Inference of team members is an overapproximation (everybody who committed
changes to their packages), additionally the janitors are missing.  We will have
to fill these manually.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;alt-ergo -&amp;gt; OCamlPro-Iguernlala UnixJunkie backtracking bobot nobrowser
janestreet -&amp;gt; backtracking hannesm j0sh rgrinberg smondet
mirage -&amp;gt; MagnusS dbuenzli djs55 hannesm hnrgrgr jonludlam mato mor1 pgj pqwy pw374 rdicosmo rgrinberg ruhatch sg2342 talex5 yomimono
ocsigen -&amp;gt; balat benozol dbuenzli hhugo hnrgrgr jpdeplaix mfp pveber scjung slegrand45 smondet vasilisp
xapi-project -&amp;gt; dbuenzli djs55 euanh mcclurmc rdicosmo simonjbeaumont yomimono&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;AlternativeapproachGitHuburls&quot;&gt;Alternative approach: GitHub urls&lt;/h3&gt;

&lt;p&gt;An alternative approach (attempted earlier) working only for GitHub hosted projects, is to authorise
&lt;a href='https://github.com/hannesm/conex/blob/github/analysis/maintainer.ml#L37-L91'&gt;the use of the user part of the GitHub repository
URL&lt;/a&gt;.
Results after filtering GitHub organisations are not yet satisfactory (but only
56 packages with no maintainer, &lt;a href='https://github.com/hannesm/opam-repository/tree/github'&gt;output repo&lt;/a&gt;.  This approach
completely ignores the manually written maintainer field.&lt;/p&gt;
&lt;h3 id=&quot;Conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Manually maintained metadata is easily out of date, and not very useful.  But
combining automatically created metadata with manually, and some manual tweaking
leads to reasonable data.&lt;/p&gt;
&lt;p&gt;The resulting authorised inference is available &lt;a href='https://github.com/hannesm/opam-repository/tree/auth'&gt;in this branch&lt;/a&gt;.&lt;/p&gt;
</content><category scheme="https://hannes.nqsb.io/tags/package%20signing" term="package signing"/><category scheme="https://hannes.nqsb.io/tags/security" term="security"/><id>urn:uuid:c7dd6dac-909c-58b7-b7a1-4f1f8e2d4380</id><title type="text">Who maintains package X?</title><updated>2017-03-09T09:47:08-00:00</updated><author><name>hannes</name></author></entry><entry><summary xml:base="https://blogs.janestreet.com/wp-atom.php" type="html">&lt;p&gt;Our first &lt;a href=&quot;https://blogs.janestreet.com/how-to-build-an-exchange/&quot;&gt;Jane Street Tech Talk&lt;/a&gt; went really well! Thanks to everyone who came and made it a fun event.&lt;/p&gt;
&lt;p&gt;Now it's time for another. We're planning for the series to feature a combination of voices from inside and outside Jane Street. This one is of the latter variety: on March 6th, &lt;a href=&quot;https://people.cs.umass.edu/~arjun/home/&quot;&gt;Arjun Guha&lt;/a&gt; will be presenting &lt;a href=&quot;https://events.janestreet.com/home/tech-talks/&quot;&gt;On Verification for System Configuration Languages&lt;/a&gt;, which is about using static verification techniques for catching bugs in &lt;a href=&quot;https://puppet.com/&quot;&gt;Puppet&lt;/a&gt; configs.&lt;/p&gt;
&lt;p&gt;I've known Arjun for years, and he's a both a good hacker and a serious academic with a real knack for finding good ways of applying ideas from programming languages to systems problems. Also, he has excellent taste in &lt;a href=&quot;https://github.com/arjunguha/ocaml-docker&quot;&gt;programming languages&lt;/a&gt;...&lt;/p&gt; &lt;a href=&quot;https://blogs.janestreet.com/jane-street-tech-talks-verifying-puppet-configs/&quot;&gt;&amp;#187; Continue Reading.&lt;/a&gt;</summary><source><updated>2017-05-11T19:02:45-00:00</updated><subtitle type="text">Jane Street' blogs (Systems and OCaml rolled into one)</subtitle><link type="application/atom+xml" href="https://blogs.janestreet.com/category/ocaml/feed/atom/" rel="self"/><link type="text/html" href="https://blogs.janestreet.com" rel="alternate"/><generator uri="https://wordpress.org/" version="4.7.4">WordPress</generator><id>https://blogs.janestreet.com/feed/atom/</id><title type="text">OCaml – Jane Street Tech Blogs</title><author><name>Jane Street</name></author></source><published>2017-02-16T19:08:56-00:00</published><link type="application/atom+xml" href="https://blogs.janestreet.com/jane-street-tech-talks-verifying-puppet-configs/feed/atom/" rel="replies"/><link type="text/html" href="https://blogs.janestreet.com/jane-street-tech-talks-verifying-puppet-configs/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=jane-street-tech-talks-verifying-puppet-configs#comments" rel="replies"/><link type="text/html" href="https://blogs.janestreet.com/jane-street-tech-talks-verifying-puppet-configs/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=jane-street-tech-talks-verifying-puppet-configs" rel="alternate"/><content xml:base="https://blogs.janestreet.com/wp-atom.php" type="html">&lt;p&gt;Our first &lt;a href=&quot;https://blogs.janestreet.com/how-to-build-an-exchange/&quot;&gt;Jane Street Tech Talk&lt;/a&gt; went really well! Thanks to everyone who came and made it a fun event.&lt;/p&gt;
&lt;p&gt;Now it's time for another. We're planning for the series to feature a combination of voices from inside and outside Jane Street. This one is of the latter variety: on March 6th, &lt;a href=&quot;https://people.cs.umass.edu/~arjun/home/&quot;&gt;Arjun Guha&lt;/a&gt; will be presenting &lt;a href=&quot;https://events.janestreet.com/home/tech-talks/&quot;&gt;On Verification for System Configuration Languages&lt;/a&gt;, which is about using static verification techniques for catching bugs in &lt;a href=&quot;https://puppet.com/&quot;&gt;Puppet&lt;/a&gt; configs.&lt;/p&gt;
&lt;p&gt;I've known Arjun for years, and he's a both a good hacker and a serious academic with a real knack for finding good ways of applying ideas from programming languages to systems problems. Also, he has excellent taste in &lt;a href=&quot;https://github.com/arjunguha/ocaml-docker&quot;&gt;programming languages&lt;/a&gt;...&lt;/p&gt;
&lt;p&gt;I hope you'll come! You can sign up &lt;a href=&quot;https://docs.google.com/a/janestreet.com/forms/d/e/1FAIpQLSfBDmMVxfB0333njocdCL32MpexMVm0shO6YcIM4i4ViNjR1A/viewform?c=0&amp;amp;w=1&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
</content><category scheme="https://blogs.janestreet.com" term="OCaml"/><id>https://blogs.janestreet.com/?p=1620</id><title xml:base="https://blogs.janestreet.com/wp-atom.php" type="html">Jane Street Tech Talks: Verifying Puppet Configs</title><updated>2017-02-16T19:08:56-00:00</updated><author><name>Yaron Minsky</name></author></entry><entry><source><updated>2017-05-07T11:34:10-00:00</updated><link href="http://kcsrk.info/" rel="alternate"/><link href="http://kcsrk.info/atom.xml" rel="self"/><id>http://kcsrk.info</id><title type="text">OCaml feed from KC Sivaramakrishnan</title><author><email>sk826@cl.cam.ac.uk</email><name>KC Sivaramakrishnan</name></author></source><link href="http://kcsrk.info/ocaml/irmin/crdt/2017/02/15/an-easy-interface-to-irmin-library/" rel="alternate"/><content xml:base="http://kcsrk.info/atom-ocaml.xml" type="html">&lt;p&gt;&lt;a href=&quot;https://github.com/kayceesrk/ezirmin&quot;&gt;Ezirmin&lt;/a&gt; is an easy interface over the
&lt;a href=&quot;https://github.com/mirage/irmin&quot;&gt;Irmin&lt;/a&gt;, a library database for building
persistent mergeable data structures based on the principles of Git. In this
post, I will primarily discuss the Ezirmin library, but also discuss some of the
finer technical details of mergeable data types implemented over Irmin.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h1 id=&quot;contents&quot;&gt;Contents&lt;/h1&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#contents&quot; id=&quot;markdown-toc-contents&quot;&gt;Contents&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#irmin-and-ezirmin&quot; id=&quot;markdown-toc-irmin-and-ezirmin&quot;&gt;Irmin and Ezirmin&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#quick-tour-of-ezirmin&quot; id=&quot;markdown-toc-quick-tour-of-ezirmin&quot;&gt;Quick tour of Ezirmin&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#merge-semantics&quot; id=&quot;markdown-toc-merge-semantics&quot;&gt;Merge semantics&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#working-with-history&quot; id=&quot;markdown-toc-working-with-history&quot;&gt;Working with history&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#reacting-to-changes&quot; id=&quot;markdown-toc-reacting-to-changes&quot;&gt;Reacting to changes&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#interaction-with-remotes&quot; id=&quot;markdown-toc-interaction-with-remotes&quot;&gt;Interaction with remotes&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#mergeable-persistent-data-types&quot; id=&quot;markdown-toc-mergeable-persistent-data-types&quot;&gt;Mergeable persistent data types&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#irmin-architecture&quot; id=&quot;markdown-toc-irmin-architecture&quot;&gt;Irmin Architecture&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#user-defined-merges&quot; id=&quot;markdown-toc-user-defined-merges&quot;&gt;User-defined merges&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#mergeable-counters&quot; id=&quot;markdown-toc-mergeable-counters&quot;&gt;Mergeable Counters&lt;/a&gt;        &lt;ul&gt;
          &lt;li&gt;&lt;a href=&quot;#theory-of-merges&quot; id=&quot;markdown-toc-theory-of-merges&quot;&gt;Theory of merges&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#recursive-merges&quot; id=&quot;markdown-toc-recursive-merges&quot;&gt;Recursive merges&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#mergeable-logs&quot; id=&quot;markdown-toc-mergeable-logs&quot;&gt;Mergeable logs&lt;/a&gt;        &lt;ul&gt;
          &lt;li&gt;&lt;a href=&quot;#efficient-mergeable-logs&quot; id=&quot;markdown-toc-efficient-mergeable-logs&quot;&gt;Efficient mergeable logs&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#mergeable-ropes&quot; id=&quot;markdown-toc-mergeable-ropes&quot;&gt;Mergeable ropes&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#next-steps&quot; id=&quot;markdown-toc-next-steps&quot;&gt;Next steps&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;irmin-and-ezirmin&quot;&gt;Irmin and Ezirmin&lt;/h1&gt;

&lt;p&gt;Irmin is a library for manipulating persistent mergeable data structures
(including CRDTs) that follows the same principles of Git. In particular, it has
built-in support for snapshots, branches and reverts, and can compile to
multiple backends. Being written in pure OCaml, apps written using Irmin, as
well as running natively, can run in the browsers or be compiled to Unikernels.
A good introduction to the capabilities of Irmin can be found in the Irmin
&lt;a href=&quot;https://github.com/mirage/irmin/blob/master/README.md&quot;&gt;README&lt;/a&gt; file.&lt;/p&gt;

&lt;p&gt;One of the downsides to being extremely configurable is that the Irmin library
is not beginner friendly. In particular, the library tends to be rather functor
heavy, and even &lt;a href=&quot;https://github.com/mirage/irmin/blob/master/README.md#usage&quot;&gt;simple
uses&lt;/a&gt; require
multiple functor instantiations&lt;sup id=&quot;fnref:irmin&quot;&gt;&lt;a href=&quot;#fn:irmin&quot; class=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. The primary goal of Ezirmin is to
provide a defuntorized interface to Irmin, specialized to useful defaults.
However, as I’ve continued to build Ezirmin, it has come to include a collection
of useful mergeable data types including counters, queues, ropes, logs, etc. I
will spend some time describing some of the interesting aspects of these data
structures.&lt;/p&gt;

&lt;h1 id=&quot;quick-tour-of-ezirmin&quot;&gt;Quick tour of Ezirmin&lt;/h1&gt;

&lt;p&gt;You can install the latest version of Ezirmin by&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;git clone https://github.com/kayceesrk/ezirmin
&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;ezirmin
&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;opam pin add ezirmin .
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Stable versions are also available through OPAM:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;opam install ezirmin
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Let’s fire up &lt;code class=&quot;highlighter-rouge&quot;&gt;utop&lt;/code&gt; and get started:&lt;/p&gt;

&lt;div class=&quot;language-ocaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;ezirmin&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;open&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Lwt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Infix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;We’ll create a mergeable queue of strings using the Git file system backend
rooted at &lt;code class=&quot;highlighter-rouge&quot;&gt;/tmp/ezirminq&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-ocaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;M&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Ezirmin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;FS_queue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;Tc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);;&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;(* Mergeable queue of strings *)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;open&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Lwt_main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;init&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/tmp/ezirminq&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bare&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;master&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;branch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;abstr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;m&lt;/code&gt; is the master branch of the repository. Ezirmin exposes a key value store,
where keys are hierarchical paths and values are whatever data types is stored in
the repo. In this case, the data type is a queue. Let’s push some elements into
the queue:&lt;/p&gt;

&lt;div class=&quot;language-ocaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;push&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;home&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;todo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;buy milk&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;unit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;push&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;work&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;todo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;publish ezirmin&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;unit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to_list&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;home&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;todo&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;];;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;buy milk&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;The updates to the queue is saved in the Git repository at &lt;code class=&quot;highlighter-rouge&quot;&gt;/tmp/ezirminq&lt;/code&gt;. In
another terminal,&lt;/p&gt;

&lt;div class=&quot;language-ocaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;ezirmin&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;M&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Ezirmin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;FS_queue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;Tc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);;&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;(* Mergeable queue of strings *)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;open&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;open&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Lwt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Infix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Lwt_main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;init&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/tmp/ezirminq&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bare&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;master&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;branch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;abstr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pop&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;home&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;todo&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;];;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;option&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Some&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;buy milk&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;For concurrency control, use branches. In the first terminal,&lt;/p&gt;

&lt;div class=&quot;language-ocaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wip&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Lwt_main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clone_force&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;wip&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;push&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wip&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;home&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;todo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;walk dog&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;unit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;push&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wip&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;home&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;todo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;take out trash&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;unit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;The changes are not visible until the branches are merged.&lt;/p&gt;

&lt;div class=&quot;language-ocaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to_list&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;home&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;todo&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;];;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;merge&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wip&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;into&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;unit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to_list&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;home&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;todo&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;];;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;walk dog&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;take out trash&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;merge-semantics&quot;&gt;Merge semantics&lt;/h2&gt;

&lt;p&gt;What should be the semantics of popping the queue at &lt;code class=&quot;highlighter-rouge&quot;&gt;home/todo&lt;/code&gt; concurrently
at the master branch and wip branch? It is reasonable to ascribe exactly once
semantics to pop such that popping the same element on both branches and
subsequently merging the queues would lead to a merge conflict. However, a more
useful semantics is where we relax this invariant and allow elements to be
popped more than once on different branches. In particular, the merge operation
on the queue ensures that:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;An element popped in one of the branches is not present after the merge.&lt;/li&gt;
  &lt;li&gt;Merges respect the program order in each of the branches.&lt;/li&gt;
  &lt;li&gt;Merges converge.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Hence, our merge queues are CRDTs.&lt;/p&gt;

&lt;h2 id=&quot;working-with-history&quot;&gt;Working with history&lt;/h2&gt;

&lt;p&gt;Irmin is fully compatible with Git. Hence, we can explore the history of the
operations using the git command line. In another terminal:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /tmp/ezirminq
&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;git lg
&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; e75da48 - &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;4 minutes ago&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; push - Irmin xxxx.cam.ac.uk.[73126] &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;HEAD -&amp;gt; master, wip&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; 40ed32d - &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;4 minutes ago&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; push - Irmin xxxx.cam.ac.uk.[73126]
&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; 6a56fb0 - &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;5 minutes ago&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; pop - Irmin xxxx.cam.ac.uk.[73221]
&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; 6a2cc9a - &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;6 minutes ago&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; push - Irmin xxxx.cam.ac.uk.[73126]
&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; 55f7fc8 - &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;6 minutes ago&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; push - Irmin xxxx.cam.ac.uk.[73126]
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;The Git log shows that there have been 4 pushes and 1 pop in this repository.
In addition to the data structures being mergeable, they are also persistent.
In particular, every object stored in Irmin has complete provenance. You can
also manipulate history using the Git command line.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;git reset HEAD~2 --hard
&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;git lg
&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; e75da48 - &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;8 minutes ago&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; push - Irmin xxxx.cam.ac.uk.[73126] &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;wip&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; 40ed32d - &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;9 minutes ago&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; push - Irmin xxxx.cam.ac.uk.[73126]
&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; 6a56fb0 - &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;9 minutes ago&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; pop - Irmin xxxx.cam.ac.uk.[73221] &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;HEAD -&amp;gt; master&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; 6a2cc9a - &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;10 minutes ago&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; push - Irmin xxxx.cam.ac.uk.[73126]
&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; 55f7fc8 - &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;10 minutes ago&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; push - Irmin xxxx.cam.ac.uk.[73126]
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Back in the first terminal:&lt;/p&gt;

&lt;div class=&quot;language-ocaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to_list&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;home&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;todo&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;];;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Since we rolled back the master to before the pushes were merged, we see an
empty list. Ezirmin also provides APIs for working with history
programmatically.&lt;/p&gt;

&lt;div class=&quot;language-ocaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Lwt_main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;repo&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;init&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Books&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Ovine Supply Logistics&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;];;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;push_msg&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;push&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;begin&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;push_msg&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Baa&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;push_msg&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Baa&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;push_msg&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Black&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;push_msg&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Camel&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to_list&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Baa&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Baa&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Black&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Camel&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Clearly this is wrong. Let’s fix this by reverting to earlier version:&lt;/p&gt;

&lt;div class=&quot;language-ocaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::_&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;predecessors&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;repo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;(** HEAD~1 version *)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to_list&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Baa&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Baa&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Black&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;update_branch&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to_list&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Baa&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Baa&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Black&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Now that we’ve undone the error, we can do the right thing.&lt;/p&gt;

&lt;div class=&quot;language-ocaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;push_msg&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Sheep&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to_list&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Baa&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Baa&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Black&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Sheep&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;reacting-to-changes&quot;&gt;Reacting to changes&lt;/h2&gt;

&lt;p&gt;Ezirmin supports watching a particular key for updates and invoking a callback
function when there is one.&lt;/p&gt;

&lt;div class=&quot;language-ocaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cb&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Lwt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;print_endline&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;callback: update to home/todo&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;watch&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;home&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;todo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cb&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;The code above installs a listener &lt;code class=&quot;highlighter-rouge&quot;&gt;cb&lt;/code&gt; on the queue at &lt;code class=&quot;highlighter-rouge&quot;&gt;home/todo&lt;/code&gt;, which is
run every time the queue is updated. This includes local &lt;code class=&quot;highlighter-rouge&quot;&gt;push&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;pop&lt;/code&gt;
operations as well as updates due to merges.&lt;/p&gt;

&lt;div class=&quot;language-ocaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;push&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;home&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;todo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;hang pictures&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;home&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;todo&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;unit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id=&quot;interaction-with-remotes&quot;&gt;Interaction with remotes&lt;/h2&gt;

&lt;p&gt;Unlike distributed data stores, where the updates are disseminated
transparently between the replicas, Ezirmin provides you the necessary building
blocks for building your own dissemination protocol. As with Git, Ezirmin
exposes the functionality to &lt;code class=&quot;highlighter-rouge&quot;&gt;push&lt;/code&gt;&lt;sup id=&quot;fnref:push&quot;&gt;&lt;a href=&quot;#fn:push&quot; class=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;pull&lt;/code&gt; changes from remotes.&lt;/p&gt;

&lt;div class=&quot;language-ocaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;show_module&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Sync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Sync&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sig&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;remote&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;remote_uri&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;remote&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pull&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;remote&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;branch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Merge&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Update&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Conflict&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;No_head&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Ok&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Lwt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;push&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;remote&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;branch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Ok&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Lwt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;This design provides the flexibility to describe your own network layout, with
anti-entropy mechanisms built-in to the synchronization protocol. For example,
one might deploy the replicas in a hub-and-spoke model where each replica
accepts client writes locally and periodically publishes changes to the master
and also fetches any latest updates. The data structures provided by Ezirmin
are always mergeable and converge. Hence, the updates are never rejected. It is
important to note that even though we have a centralized master, this
deployment is still highly available. Even if the master is unavailable, the
other nodes can still accept client requests. The replicas may also be
connected in a peer-to-peer fashion without a centralized master for a more
resilient deployment.&lt;/p&gt;

&lt;h1 id=&quot;mergeable-persistent-data-types&quot;&gt;Mergeable persistent data types&lt;/h1&gt;

&lt;p&gt;Ezirmin is equipped with a &lt;a href=&quot;https://github.com/kayceesrk/ezirmin#whats-in-the-box&quot;&gt;growing
collection&lt;/a&gt; of mergeable
data types. The mergeable datatypes occupy a unique position in the space of
CRDTs. Given that we have the history, the design of mergeable datatypes is much
simpler. Additionally, this also leads to &lt;a href=&quot;http://gazagnaire.org/pub/FGM15.pdf&quot;&gt;richer
structures&lt;/a&gt; typically not found in CRDTs.
It is worth studying them in detail.&lt;/p&gt;

&lt;h2 id=&quot;irmin-architecture&quot;&gt;Irmin Architecture&lt;/h2&gt;

&lt;p&gt;Irmin provides a high-level key-value interface built over two lower level
heaps: a &lt;strong&gt;block store&lt;/strong&gt; and a &lt;strong&gt;tag store&lt;/strong&gt;. A block store is an append-only
content-addressable store that stores serialized values of application contents,
prefix-tree nodes, history meta-data, etc. Instead of using physical memory
address of blocks, the blocks are identified by the hash of their contents. As a
result block store enjoys very nice properties. Being content-addressed, we get
sharing for free: two blocks with the same content will have the have the same
hash. This not only applies for individual blocks, but also for
linked-structures. For example,&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt; &lt;img src=&quot;/assets/linked_list.png&quot; alt=&quot;Hash list&quot; /&gt; &lt;/p&gt;

&lt;p&gt;The linked list above is uniquely identified by hash &lt;code class=&quot;highlighter-rouge&quot;&gt;h0&lt;/code&gt; since &lt;code class=&quot;highlighter-rouge&quot;&gt;h0&lt;/code&gt; was
computed from the content &lt;code class=&quot;highlighter-rouge&quot;&gt;a&lt;/code&gt; and the hash of the tail of the list &lt;code class=&quot;highlighter-rouge&quot;&gt;h1&lt;/code&gt;. No
other list has hash &lt;code class=&quot;highlighter-rouge&quot;&gt;h0&lt;/code&gt;. Changing &lt;code class=&quot;highlighter-rouge&quot;&gt;c&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;C&lt;/code&gt; in this list would result in a
different hash for the head of the list&lt;sup id=&quot;fnref:blockchain&quot;&gt;&lt;a href=&quot;#fn:blockchain&quot; class=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;. Moreover, since the block
store is append-only, all previous versions of a application-level data
structure is also available, and thus providing persistence. This also makes for
a nice concurrency story for multiple processes/threads operating on the block
store. The absence of mutations on block store mean that no additional
concurrency control mechanisms are necessary.&lt;/p&gt;

&lt;p&gt;The only mutable part of the Irmin architecture is the tag store, that maps
global names to blocks in the block store. The notion of branches are built on
top of the tag store. Cloning a branch creates a new tag that points to the same
block as the cloned branch.&lt;/p&gt;

&lt;h2 id=&quot;user-defined-merges&quot;&gt;User-defined merges&lt;/h2&gt;

&lt;p&gt;The real power of Irmin is due to the user-defined merges. Irmin expects the
developer to provide a 3-way merge function with the following signature:&lt;/p&gt;

&lt;div class=&quot;language-ocaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;(** User-defined contents. *)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;merge&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;old&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Ok&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Conflict&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;(** 3-way merge. *)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Given the common ancestor &lt;code class=&quot;highlighter-rouge&quot;&gt;old&lt;/code&gt; and the two versions, merge function can either
return a successful merge or mark a conflict. It is up to the developer to ensure
that merges are commutative (&lt;code class=&quot;highlighter-rouge&quot;&gt;merge old a b = merge old b a&lt;/code&gt;) and that the merge
captures the intent of the two branches. &lt;em&gt;If the merge function never conflicts,
we have CRDTs&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id=&quot;mergeable-counters&quot;&gt;Mergeable Counters&lt;/h2&gt;

&lt;p&gt;The simplest mergeable data type is a counter with an increment and decrement
operations. Given that we have a 3-way merge function, the merge is intuitive:&lt;/p&gt;

&lt;script src=&quot;http://gist-it.appspot.com/https://github.com/kayceesrk/ezirmin/blob/125ecd3b8fbebbd501f218397b3c1f2ab12d13cf/src/ezirmin_counter.ml?slice=13:18&quot;&gt;&lt;/script&gt;

&lt;p&gt;Given the two new values for the counter &lt;code class=&quot;highlighter-rouge&quot;&gt;t1&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;t2&lt;/code&gt;, and their lowest common
ancestor value &lt;code class=&quot;highlighter-rouge&quot;&gt;old&lt;/code&gt;, the new value of the counter is the sum of the &lt;code class=&quot;highlighter-rouge&quot;&gt;old&lt;/code&gt; value
and the two deltas: &lt;code class=&quot;highlighter-rouge&quot;&gt;old + (t1 - old) + (t2 - old) = t1 + t2 - old&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;theory-of-merges&quot;&gt;Theory of merges&lt;/h3&gt;

&lt;p&gt;While this definition is intuitive, the proof of why this strategy (i.e.,
computing deltas and applying to the common ancestor) is correct is quite
subtle. It happens to be the case that the patches (deltas) in this case,
integers under addition, form an &lt;a href=&quot;https://en.wikipedia.org/wiki/Abelian_group&quot;&gt;abelian
group&lt;/a&gt;. Judah Jacobson formalizes
&lt;a href=&quot;ftp://ftp.math.ucla.edu/pub/camreport/cam09-83.pdf&quot;&gt;patches for Darcs as inverse
semigroups&lt;/a&gt; and proves
convergence. Every abelian group is also an inverse semigroup. Hence, the above
strategy is correct. Merges can also be equivalently viewed as a &lt;a href=&quot;https://arxiv.org/pdf/1311.3903.pdf&quot;&gt;pushout in
category theory&lt;/a&gt;, leading to the same
result. I will have to save the discussion of the category theoretic reasoning
of Irmin merges for another time. But Liam O’Connor has written a concise
&lt;a href=&quot;http://liamoc.net/posts/2015-11-10-patch-theory.html&quot;&gt;post&lt;/a&gt; on the theory of patches
which is worth a read.&lt;/p&gt;

&lt;h3 id=&quot;recursive-merges&quot;&gt;Recursive merges&lt;/h3&gt;

&lt;p&gt;Since Ezirmin allows arbitrary branching and merging, the lowest common ancestor
need not be unique. One way to end up with multiple lowest common ancestors is
criss-cross merges. For example, consider the history graph below:&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt; &lt;img src=&quot;/assets/criss_cross.png&quot; alt=&quot;Criss cross merge&quot; /&gt; &lt;/p&gt;

&lt;p&gt;The counter at some key in the &lt;code class=&quot;highlighter-rouge&quot;&gt;master&lt;/code&gt; was initially &lt;code class=&quot;highlighter-rouge&quot;&gt;0&lt;/code&gt;. The branch &lt;code class=&quot;highlighter-rouge&quot;&gt;wip&lt;/code&gt; was
cloned at this point. The counter is incremented by &lt;code class=&quot;highlighter-rouge&quot;&gt;1&lt;/code&gt; at &lt;code class=&quot;highlighter-rouge&quot;&gt;master&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;2&lt;/code&gt; at
&lt;code class=&quot;highlighter-rouge&quot;&gt;wip&lt;/code&gt;. At this point, both branches are merged into the other branch. The common
ancestor here is the initial state of counter &lt;code class=&quot;highlighter-rouge&quot;&gt;0&lt;/code&gt;. This results in counter value
of &lt;code class=&quot;highlighter-rouge&quot;&gt;3&lt;/code&gt; in both branches. Suppose there are further increments, &lt;code class=&quot;highlighter-rouge&quot;&gt;2&lt;/code&gt; at &lt;code class=&quot;highlighter-rouge&quot;&gt;master&lt;/code&gt;
and &lt;code class=&quot;highlighter-rouge&quot;&gt;4&lt;/code&gt; at &lt;code class=&quot;highlighter-rouge&quot;&gt;wip&lt;/code&gt;, resulting in counter values &lt;code class=&quot;highlighter-rouge&quot;&gt;5&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;7&lt;/code&gt; respectively in
&lt;code class=&quot;highlighter-rouge&quot;&gt;master&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;wip&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If the &lt;code class=&quot;highlighter-rouge&quot;&gt;wip&lt;/code&gt; branch is now merged in &lt;code class=&quot;highlighter-rouge&quot;&gt;master&lt;/code&gt;, there are two lowest common
ancestors: the commit with value &lt;code class=&quot;highlighter-rouge&quot;&gt;1&lt;/code&gt; at master and &lt;code class=&quot;highlighter-rouge&quot;&gt;2&lt;/code&gt; in wip. Since the 3-way
merge algorithm only work for a single common ancestor, the we adopt a recursive
merge strategy, where the lowest common ancestors are first merged resulting in
a internal commit with value &lt;code class=&quot;highlighter-rouge&quot;&gt;3&lt;/code&gt; (represented by a dotted circle). This commit
is now used as the common ancestor for merging, which results in &lt;code class=&quot;highlighter-rouge&quot;&gt;9&lt;/code&gt; as the new
state of the counter. This matches the increments done in both branches. The
recursive merge strategy is also the default merge strategy for Git.&lt;/p&gt;

&lt;h2 id=&quot;mergeable-logs&quot;&gt;Mergeable logs&lt;/h2&gt;

&lt;p&gt;Another useful data type is &lt;a href=&quot;http://kcsrk.info/ezirmin/Ezirmin.Blob_log.html&quot;&gt;mergeable
logs&lt;/a&gt;, where each log message
is a string. The merge operation accumulates the logs in reverse chronological
order. To this end, each log entry is a pair of timestamp and message, and the
log itself is a list of entries. They are constructed using
&lt;a href=&quot;https://github.com/mirage/mirage-tc&quot;&gt;mirage-tc&lt;/a&gt;:&lt;/p&gt;

&lt;script src=&quot;http://gist-it.appspot.com/https://github.com/kayceesrk/ezirmin/blob/c2220aea1fd26daa90febc822f23f89205af3a69/src/ezirmin_blob_log.ml?slice=34:41&quot;&gt;&lt;/script&gt;

&lt;p&gt;The merge function extracts the newer entries from either branches, sorts them
and appends to the front of the old list.&lt;/p&gt;

&lt;script src=&quot;http://gist-it.appspot.com/https://github.com/kayceesrk/ezirmin/blob/c2220aea1fd26daa90febc822f23f89205af3a69/src/ezirmin_blob_log.ml?slice=48:66&quot;&gt;&lt;/script&gt;

&lt;p&gt;While this implementation is simple, it does not scale well. In particular, each
commit stores the entire log as a single serialized blob. This does not take
advantage of the fact that every commit can share the tail of the log with its
predecessor. Moreover, every append to the log needs to deserialize the entire
log, append the new entry and serialize the log again. Hence, append is an
&lt;code class=&quot;highlighter-rouge&quot;&gt;O(n)&lt;/code&gt; operation, where &lt;code class=&quot;highlighter-rouge&quot;&gt;n&lt;/code&gt; is the size of the log. Merges are also worst case
&lt;code class=&quot;highlighter-rouge&quot;&gt;O(n)&lt;/code&gt;. This is undesirable.&lt;/p&gt;

&lt;h3 id=&quot;efficient-mergeable-logs&quot;&gt;Efficient mergeable logs&lt;/h3&gt;

&lt;p&gt;We can implement a &lt;a href=&quot;http://kcsrk.info/ezirmin/Ezirmin.Log.html&quot;&gt;efficient logs&lt;/a&gt;
by taking advantage of the fact that every commit shares the tail of the log
with its predecessor.&lt;/p&gt;

&lt;div class=&quot;language-ocaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;log_entry&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;V&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;        &lt;span class=&quot;c&quot;&gt;(** V.t is type of message. *)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;prev&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;option&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;(** K.t is the type of address in the block store. *)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Merges simply add a new node which points to the logs of merged branches,
resulting in a DAG that captures the causal history. The following sequence of
operations:&lt;/p&gt;

&lt;div class=&quot;language-ocaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;ezirmin&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;open&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Lwt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Infix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;M&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Ezirmin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Memory_log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;Tc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;open&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Lwt_main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;init&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;master&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Lwt_main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;append&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;m0&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;append&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;m1&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;clone_force&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;wip&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;append&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;w0&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;append&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;m2&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;merge&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;into&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;append&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;w1&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;append&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;w2&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;append&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;m3&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;append&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;m4&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;);;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;results in the heap below.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt; &lt;img src=&quot;/assets/log.png&quot; alt=&quot;Merge log&quot; /&gt; &lt;/p&gt;

&lt;p&gt;Read traverses the log in reverse chronological order.&lt;/p&gt;

&lt;div class=&quot;language-ocaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;read_all&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;m4&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;m3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;m2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;w0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;m1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;m0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;This implementation has &lt;code class=&quot;highlighter-rouge&quot;&gt;O(1)&lt;/code&gt; appends and &lt;code class=&quot;highlighter-rouge&quot;&gt;O(1)&lt;/code&gt; merges, resulting in much
better performance. The graph below compares the blob log implementation and
this linked implementation with file system backend by performing repeated
appends to the log and measuring the latency for append.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt; &lt;img src=&quot;/assets/perf_log.png&quot; alt=&quot;Perf log&quot; /&gt; &lt;/p&gt;

&lt;p&gt;Each point represents the average latency for the previous 100 appends. The
results show that the append latency for linked implementation remains
relatively constant while the blob implementation slows down considerably with
increasing number of appends. Additionally, the linked implementation also
supports efficient &lt;a href=&quot;http://kcsrk.info/ezirmin/Ezirmin.Log.html#VALread&quot;&gt;paginated
reads&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;mergeable-ropes&quot;&gt;Mergeable ropes&lt;/h2&gt;

&lt;p&gt;A rope data structure is used for efficiently storing and manipulating very long
strings. Ezirmin provides &lt;a href=&quot;http://kcsrk.info/ezirmin/Ezirmin.Rope.html&quot;&gt;mergeable
ropes&lt;/a&gt; where for &lt;a href=&quot;http://kcsrk.info/ezirmin/Ezirmin.Rope_content.html&quot;&gt;arbitrary
contents&lt;/a&gt;, but also
specialized for &lt;a href=&quot;http://kcsrk.info/ezirmin/Ezirmin.Rope_string.html&quot;&gt;strings&lt;/a&gt;.
Ropes automatically rebalance to maintain the invariant that the height of the
tree is proportional to the length of the contents. The crux of the merge
strategy is that given a common ancestor and the two trees to be merged,
the merge algorithm works out the smallest subtrees where the modification
occurred. If the modifications are on distinct subtrees, then the merge is
trivial.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt; &lt;img src=&quot;/assets/merge_rope.png&quot; alt=&quot;merge rope&quot; /&gt; &lt;/p&gt;

&lt;p&gt;If the modification is on the same subtree, then the algorithm delegates to
merge the contents. This problem has been well studied under the name of
&lt;a href=&quot;https://en.wikipedia.org/wiki/Operational_transformation&quot;&gt;operational
transformation&lt;/a&gt; (OT).
OT can be categorically explained in terms of pushouts.
Mergeable strings with insert, delete and replace operations are isomorphic to
counters with increment and decrement. We apply a similar strategy to merge
string.&lt;/p&gt;

&lt;script src=&quot;http://gist-it.appspot.com/https://github.com/kayceesrk/ezirmin/blob/c2220aea1fd26daa90febc822f23f89205af3a69/src/ezirmin_rope_string.ml?slice=193:206&quot;&gt;&lt;/script&gt;

&lt;p&gt;First we compute the diff between the common ancestor and the new tree using
&lt;a href=&quot;https://en.wikipedia.org/wiki/Wagner%E2%80%93Fischer_algorithm&quot;&gt;Wagner-Fischer
algorithm&lt;/a&gt;. Then
we transform one patch with respect to the other using standard OT definition
such that we can first apply one of the original patch to the common ancestor
and then apply the transformed patch of the other branch to get the result tree.&lt;/p&gt;

&lt;p&gt;For example,&lt;/p&gt;

&lt;div class=&quot;language-ocaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;ezirmin&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;open&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Lwt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Infix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;open&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Ezirmin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Memory_rope_string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Lwt_main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;init&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;master&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Lwt_main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;make&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;abc&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;write&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nn&quot;&gt;Lwt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;);;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Lwt_main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clone_force&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;w&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Lwt_main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t'&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;(* &quot;axc&quot; *)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;write&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;insert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;y&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t'&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;(* &quot;aybc&quot; *)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;write&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;merge&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;into&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;(* &quot;ayxc&quot; *)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;merge&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;into&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;);;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Lwt_main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;read&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;None&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;failwith&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;impossible&quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Some&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flush&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;|=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nn&quot;&gt;Printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;m is &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;);;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;unit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;ayxc&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;utop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Lwt_main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;read&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;None&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;failwith&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;impossible&quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Some&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flush&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;|=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nn&quot;&gt;Printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;w is &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;unit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;ayxc&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;The combination of mergeable ropes with OT gets the best of both worlds.
Compared to a purely OT based implementation, diffs are only computed if updates
conflict at the leaves. The representation using ropes is also efficient in
terms of storage where multiple versions of the tree shares blocks. A purely
rope based implementation either has the option of storing individual characters
(atoms) at the leaves (and resolve conflicts based on some deterministic
mechanism such as timestamps or other deterministic strategies) or manifest the
conflict at the leaves to the user to get it resolved. A simple strategy might
be to present both of the conflicting strings, and ask the user to resolve it.
Hence, mergeable ropes + OT is strictly better than either of the approaches.&lt;/p&gt;

&lt;h1 id=&quot;next-steps&quot;&gt;Next steps&lt;/h1&gt;

&lt;p&gt;Ezirmin is open to comments and contributions. Next steps would be:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Implement more mergeable data types&lt;/li&gt;
  &lt;li&gt;Implement generic mergeable datatypes using &lt;a href=&quot;https://github.com/samoht/depyt&quot;&gt;depyt&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Explore the data types which admit conflicts. For example, a bank account with
non-negative balance does not form a CRDT with a &lt;code class=&quot;highlighter-rouge&quot;&gt;withdraw&lt;/code&gt; operation. However,
operations such as &lt;code class=&quot;highlighter-rouge&quot;&gt;deposit&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;accrue_interest&lt;/code&gt; can be coordination-free.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 class=&quot;no_toc&quot; id=&quot;footnotes&quot;&gt;Footnotes&lt;/h1&gt;
&lt;div class=&quot;footnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:irmin&quot;&gt;
      &lt;p&gt;Things are indeed improving with a cleaner API in the &lt;a href=&quot;https://github.com/mirage/irmin/pull/397&quot;&gt;1.0 release&lt;/a&gt;.&amp;nbsp;&lt;a href=&quot;#fnref:irmin&quot; class=&quot;reversefootnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:push&quot;&gt;
      &lt;p&gt;Push is currently &lt;a href=&quot;https://github.com/mirage/irmin/issues/379&quot;&gt;broken&lt;/a&gt;. But given that Irmin is compatible with git, one can use &lt;code class=&quot;highlighter-rouge&quot;&gt;git-push&lt;/code&gt; to publish changes.&amp;nbsp;&lt;a href=&quot;#fnref:push&quot; class=&quot;reversefootnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:blockchain&quot;&gt;
      &lt;p&gt;The same principle underlies the irrefutability of &lt;a href=&quot;https://en.wikipedia.org/wiki/Blockchain_(database)&quot;&gt;blockchain&lt;/a&gt;. No block can be changed without reflecting the change in every subsequent block.&amp;nbsp;&lt;a href=&quot;#fnref:blockchain&quot; class=&quot;reversefootnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content><id>http://kcsrk.info/ocaml/irmin/crdt/2017/02/15/an-easy-interface-to-irmin-library</id><title type="text">Ezirmin : An easy interface to the Irmin library</title><updated>2017-02-15T13:46:00-00:00</updated><author><email>sk826@cl.cam.ac.uk</email><name>KC Sivaramakrishnan</name></author></entry><entry><source><updated>2017-02-14T13:14:17-00:00</updated><rights type="text">Copyright © log.examachine.net 2014 </rights><logo>http://188.226.215.182/wp-content/plugins/podpress/images/powered_by_podpress.jpg</logo><link title="OCaml – log.examachine.net" type="text/html" href="https://examachine.net/blog" rel="related"/><link title="OCaml – log.examachine.net" type="application/rss+xml" href="https://examachine.net/blog/category/ocaml/feed/" rel="self"/><generator>https://wordpress.org/?v=4.7.4</generator><id>https://examachine.net/blog</id><title type="text">OCaml – log.examachine.net</title><author><name>Eray Özkural</name></author></source><link href="http://examachine.net/blog/ann-parallpairs/" rel="alternate"/><link href="http://examachine.net/blog/ann-parallpairs/#respond" rel="related"/><content xml:base="https://examachine.net/blog/category/ocaml/feed/" type="html">Parallel all-pairs similarity search algorithms in OCaml Sources Git repository ---&amp;#62; https://github.com/examachine/parallpairs The repository contains the 1.0 sources, a release will be made soon. Citation If you use this code, please cite the following paper. It is currently under review</content><category term="OCaml"/><id>http://examachine.net/blog/?p=356</id><title type="text">ANN: parallpairs</title><updated>2017-02-14T13:14:17-00:00</updated><author><name>Eray Özkural</name></author></entry><entry><source><updated>2017-02-10T19:45:44-00:00</updated><link href="https://ocsigen.github.io" rel="alternate"/><link href="https://ocsigen.github.io/feed.xml" rel="self"/><id>https://ocsigen.github.io/</id><title type="text">Ocsigen Blog</title><author><name>Ocsigen blog</name></author><author><name>Ocsigen Project</name></author></source><link href="https://ocsigen.github.io/blog/2017/02/09/start/" rel="alternate"/><content xml:base="https://ocsigen.github.io/feed.xml" type="html">&lt;p&gt;The Ocsigen team is very happy to announce the first release of two
major new projects:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://ocsigen.org/ocsigen-start/&quot;&gt;Ocsigen Start&lt;/a&gt;: a Web/mobile application skeleton written with
Js_of_ocaml and Eliom. You can use this skeleton as a basis for
your own app, or to learn Web/mobile app development in OCaml.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://ocsigen.org/ocsigen-toolkit/&quot;&gt;Ocsigen Toolkit&lt;/a&gt;: a set of responsive widgets for your mobile
and Web applications in OCaml.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both projects are available via &lt;a href=&quot;https://opam.ocaml.org/&quot;&gt;OPAM&lt;/a&gt; and released under the
LGPL.&lt;/p&gt;

&lt;p&gt;Before installing, you can try out a demo of Ocsigen Start. The demo
is available&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://ocsigen.org/ocsigen-start/demo/&quot;&gt;on the Web&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;via the &lt;a href=&quot;https://play.google.com/store/apps/details?id=com.osdemo.mobile&quot;&gt;Google Play store&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;as an Android &lt;a href=&quot;http://ocsigen.org/ocsigen-start/demo/osdemo.apk&quot;&gt;APK file&lt;/a&gt;; and&lt;/li&gt;
  &lt;li&gt;as an &lt;a href=&quot;http://ocsigen.org/ocsigen-start/demo/osdemo-ios.tgz&quot;&gt;iOS application&lt;/a&gt; to be installed via XCode.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ocsigen Start provides the basic features for user management
(registration, activation links, password recovery, etc.), and some
useful libraries.  Remove the parts you don’t need for your own app.&lt;/p&gt;

&lt;p&gt;Ocsigen Start also contains many examples of code: remote procedure
calls, push notifications from the server, reactive pages, database
interaction, session data, internationalization, and some widgets from
Ocsigen Toolkit.&lt;/p&gt;

&lt;p&gt;Ocsigen Toolkit contains common widgets for mobile and Web apps,
written natively in OCaml and specifically designed for Eliom’s
multi-tier and multi-platform programming style.  You can also use
them in client-only Js_of_ocaml programs.  Many new widgets will be
added in future versions.&lt;/p&gt;

&lt;p&gt;Ocsigen Start and Ocsigen Toolkit are developed by the Ocsigen team at
&lt;a href=&quot;https://www.besport.com/&quot;&gt;Be Sport&lt;/a&gt;, at the &lt;a href=&quot;http://www.univ-paris-diderot.fr/&quot;&gt;Paris Diderot University&lt;/a&gt;, and at the
&lt;a href=&quot;https://www.irill.org/&quot;&gt;IRILL&lt;/a&gt;.&lt;/p&gt;

</content><id>tag:ocsigen.github.io,2017-02-09:/blog/2017/02/09/start</id><title type="text">Ocsigen Start and Ocsigen Toolkit reach 1.0!</title><updated>2017-02-09T00:00:00-00:00</updated><author><name>The Ocsigen Team</name></author></entry><entry><source><updated>2017-02-14T13:14:17-00:00</updated><rights type="text">Copyright © log.examachine.net 2014 </rights><logo>http://188.226.215.182/wp-content/plugins/podpress/images/powered_by_podpress.jpg</logo><link title="OCaml – log.examachine.net" type="text/html" href="https://examachine.net/blog" rel="related"/><link title="OCaml – log.examachine.net" type="application/rss+xml" href="https://examachine.net/blog/category/ocaml/feed/" rel="self"/><generator>https://wordpress.org/?v=4.7.4</generator><id>https://examachine.net/blog</id><title type="text">OCaml – log.examachine.net</title><author><name>Eray Özkural</name></author></source><link href="http://examachine.net/blog/examachinegithub/" rel="alternate"/><link href="http://examachine.net/blog/examachinegithub/#respond" rel="related"/><content xml:base="https://examachine.net/blog/category/ocaml/feed/" type="html">examachine has 22 repositories available. Follow their code on GitHub. Source: examachine (Eray Özkural) &amp;#160; I just uploaded a bunch of free software projects to github. Some of them were on google code, which was terminated by google. You may</content><category term="OCaml"/><id>http://examachine.net/blog/?p=334</id><title type="text">examachine@github</title><updated>2017-02-07T20:08:56-00:00</updated><author><name>Eray Özkural</name></author></entry><entry><source><updated>2017-03-14T08:00:00-00:00</updated><logo>http://gallium.inria.fr/blog/</logo><link title="Gagallium" type="text/html" href="http://gallium.inria.fr/blog/index.rss" rel="related"/><link title="Gagallium" type="application/rss+xml" href="http://gallium.inria.fr/blog/index.rss" rel="self"/><generator>Stog</generator><id>http://gallium.inria.fr/blog/index.rss</id><title type="text">Gagallium</title><author><name>GaGallium</name></author></source><link href="http://gallium.inria.fr/blog/fstar-blog/index.html" rel="alternate"/><content xml:base="http://gallium.inria.fr/blog/index.rss" type="html">
&lt;p&gt;I am no longer an official member of Gallium, but of course Gallium will always remain dear to my heart. And it is with a mix of sadness and anticipation that I've started writing articles on another blog, namely, the &lt;a href=&quot;https://fstarlang.github.io&quot;&gt;F* blog&lt;/a&gt;. If you wish to hear the latest news about F*, and chat about language issues, or just get a sense of what's happening, you can go out there and start lurking in the comments section.&lt;/p&gt;

&lt;p&gt;Looking forward to some bikeshedding^W constructive discussions!&lt;/p&gt;

</content><id>http://gallium.inria.fr/blog/fstar-blog/index.html</id><title type="text">A new blog on the radar!</title><updated>2017-02-07T08:00:00-00:00</updated><author><name>Jonathan Protzenko</name></author></entry><entry><source><updated>2017-02-10T19:45:44-00:00</updated><link href="https://ocsigen.github.io" rel="alternate"/><link href="https://ocsigen.github.io/feed.xml" rel="self"/><id>https://ocsigen.github.io/</id><title type="text">Ocsigen Blog</title><author><name>Ocsigen blog</name></author><author><name>Ocsigen Project</name></author></source><link href="https://ocsigen.github.io/blog/2017/02/06/eliomlang/" rel="alternate"/><content xml:base="https://ocsigen.github.io/feed.xml" type="html">&lt;p&gt;The &lt;a href=&quot;https://ocsigen.org/eliom/&quot;&gt;Eliom framework&lt;/a&gt; is the part of the &lt;a href=&quot;https://ocsigen.org&quot;&gt;ocsigen project&lt;/a&gt; that aims to provide
high level libraries for developing client/server web applications.
It contains a &lt;a href=&quot;https://ocsigen.org/eliom/6.1/manual/ppx-syntax&quot;&gt;language extension&lt;/a&gt; of OCaml that allows implementing both the client
and the server parts of your application as a single program. It also
contains &lt;a href=&quot;https://ocsigen.org/eliom/manual/&quot;&gt;several libraries and utilities&lt;/a&gt; to facilitate web programming.&lt;/p&gt;

&lt;p&gt;The various Ocsigen libraries have received a lot of care
lately. Notably, we have reworked the &lt;a href=&quot;https://ocsigen.github.io/blog/2016/12/12/eliom6/&quot;&gt;service API&lt;/a&gt;, we
have added support for mobile applications and, we have developed
&lt;a href=&quot;https://github.com/ocsigen/ocsigen-start&quot;&gt;ocsigen-start&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Today, I will not talk about the ocsigen libraries. I will talk solely about
the language extension.&lt;/p&gt;

&lt;h2 id=&quot;the-current-language-extension&quot;&gt;The current language extension&lt;/h2&gt;

&lt;p&gt;The Eliom language extension extends OCaml with various annotations that
allows specifying where things are to be defined and executed.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ocaml&quot; data-lang=&quot;ocaml&quot;&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;(* I'm executed on the server *)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;(* I'm declared on the server *)&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;[%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;(* But I will be executed on the client! *)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;~%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;~%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;(* I access values on the server and execute things on the client! *)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The semantics is that the server part is executed first,
then the web page is sent to the client,
then the client part is executed.
See &lt;a href=&quot;https://ocsigen.org/eliom/6.1/manual/ppx-syntax&quot;&gt;the documentation&lt;/a&gt; for detail on the current extension.&lt;/p&gt;

&lt;p&gt;The language extension is currently implemented using a PPX extension and
a custom (and a bit sophisticated) compilation scheme. Note here that I used
the word “language” extension on purpose: this is not a simple syntax extension,
the Eliom language has its own type system, semantics and compilation
scheme, which are extensions of the OCaml ones.&lt;/p&gt;

&lt;p&gt;The current implementation of our language, based on PPX, started to
show its limits in terms of flexibility, convenience and with respect to
the safety guarantees it can provide. This is why I started, as part
of my PhD thesis, to redesign and improve it.&lt;/p&gt;

&lt;h2 id=&quot;formalizing-the-eliom-language&quot;&gt;Formalizing the Eliom language&lt;/h2&gt;

&lt;p&gt;Our first goal was to formalize the Eliom language as an extension of the OCaml
language. Formalizing the language allowed us to better understand its type 
system and semantics, which led to various improvements and bug fixes.
The formalization was &lt;a href=&quot;https://hal.archives-ouvertes.fr/hal-01349774&quot;&gt;published in APLAS 2016&lt;/a&gt;. In this paper,
we present a (rather simple) type system based on two distinct type
universes and the notion of converters, that allows passing values from
the server to the client. We also show that the intuitive semantics
of Eliom, that server code is executed immediately and client code is executed
later in the exact same order it was encountered, does correspond to the
compilation scheme used to slice Eliom programs into a server program and a
client program.&lt;/p&gt;

&lt;p&gt;In the the current implementation, when passing
a server value of type &lt;code class=&quot;highlighter-rouge&quot;&gt;Foo.t&lt;/code&gt; to the client. It also has type &lt;code class=&quot;highlighter-rouge&quot;&gt;Foo.t&lt;/code&gt;,
but the type is now the one available on the client. The actual object
can also be transformed while passing the client/server boundary using
&lt;a href=&quot;https://ocsigen.org/eliom/6.1/manual/clientserver-wrapping&quot;&gt;wrappers&lt;/a&gt;. Unfortunately, this API is very difficult to use, not
flexible and quite unsafe. Instead, we propose to use converters.
Converters can be though as a pair of function: a server serialization
function &lt;code class=&quot;highlighter-rouge&quot;&gt;ty_server -&amp;gt; string&lt;/code&gt; and a client deserialization function
&lt;code class=&quot;highlighter-rouge&quot;&gt;string -&amp;gt; ty_client&lt;/code&gt; (the actual implementation will be a bit different to make (de)serializer composable).
The correctness of a converter depends of course on the good behavior of these
two functions, but the language guarantees that they will be used together
properly and each sides will properly respect the types of the converter.&lt;/p&gt;

&lt;p&gt;By using converters, we can provide a convenient programming model and make
Eliom much easier to extend. We demonstrated this with multiple examples in
&lt;a href=&quot;https://hal.archives-ouvertes.fr/hal-01407898&quot;&gt;another paper published in IFL 2016&lt;/a&gt;.
Unfortunately, a proper implementation of converters is only possible
with some form of ad-hoc polymorphism, which involve using modular implicits.&lt;/p&gt;

&lt;h2 id=&quot;implementing-the-eliom-language&quot;&gt;Implementing the Eliom language&lt;/h2&gt;

&lt;p&gt;In order to actually implement all these new things, I started to work on an
extension of the OCaml compiler capable of handling the Eliom language
constructs. Working directly in the compiler has several advantages:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;We can implement the actual type system of Eliom directly.&lt;/li&gt;
  &lt;li&gt;Easier to extend with new features.&lt;/li&gt;
  &lt;li&gt;Much better error messages.&lt;/li&gt;
  &lt;li&gt;A simpler and faster compilation scheme.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The current work-in-progress compiler is available in the repository
&lt;a href=&quot;https://github.com/ocsigen/ocaml-eliom&quot;&gt;ocsigen/ocaml-eliom&lt;/a&gt;. A minimal runtime,
along with various
associated tools are available in &lt;a href=&quot;https://github.com/ocsigen/eliomlang&quot;&gt;ocsigen/eliomlang&lt;/a&gt;.
A (perpetually broken) playground containing an extremely bare-bone
website using eliomlang without the complete framework is available in &lt;a href=&quot;https://github.com/ocsigen/eliomlang-playground&quot;&gt;ocsigen/eliomlang-playground&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finally, the work on using this new compiler to compile the Eliom framework can be followed via &lt;a href=&quot;https://github.com/ocsigen/eliom/pull/459&quot;&gt;this pull-request&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;going-further&quot;&gt;Going further&lt;/h2&gt;

&lt;p&gt;A more in-depth presentation of the Eliom language can be found &lt;a href=&quot;https://www.irif.fr/~gradanne/papers/eliom/talk_gallium.pdf&quot;&gt;here&lt;/a&gt;.
The &lt;a href=&quot;https://hal.archives-ouvertes.fr/hal-01349774&quot;&gt;APLAS paper&lt;/a&gt; is quite formal and is mostly aimed at people
that want to really understand the minute details of the language. The
&lt;a href=&quot;https://hal.archives-ouvertes.fr/hal-01407898&quot;&gt;IFL paper&lt;/a&gt;, on the other hand, should be accessible to most OCaml programmers
(even those who don’t know Eliom) and demonstrates how to use the new Eliom
constructs to build nice, tierless and typesafe libraries for client/server
web programming.&lt;/p&gt;

&lt;h2 id=&quot;the-future&quot;&gt;The future&lt;/h2&gt;

&lt;p&gt;The work on the Eliom language is far from done. A current area of work
is to extend the OCaml module language to be aware of the Eliom annotations.
A particularly delicate (but promising!) area is the ability to use
Eliom annotations inside functors.
A second area of work is that of stabilizing, debugging and documenting the patched compiler.
Finally, a difficulty raised by this new compiler is that existing build systems,
and in particular ocamlbuild, do not handle the Eliom compilation scheme
very well. Some details on this can be found &lt;a href=&quot;https://github.com/ocsigen/eliom/pull/459&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I wish this progress report has awaken your appetite for well-typed
and modular tierless programming in OCaml. I hope I will be able to
share more news in a few months.&lt;/p&gt;

&lt;p&gt;Happy Eliom programming!&lt;/p&gt;
</content><id>tag:ocsigen.github.io,2017-02-06:/blog/2017/02/06/eliomlang</id><title type="text">News on the Eliom language</title><updated>2017-02-06T00:00:00-00:00</updated><author><name>Gabriel `Drup` Radanne</name></author></entry><entry><source><updated>2017-02-03T23:54:21-00:00</updated><link href="http://philtomson.github.io/" rel="alternate"/><link href="http://philtomson.github.io/atom.xml" rel="self"/><generator uri="http://octopress.org/">Octopress</generator><id>http://philtomson.github.io/</id><title type="text">My Little Garden of Code</title><author><name>Phil Tomson</name></author></source><link href="http://philtomson.github.io/blog/2017/02/02/funemployment/" rel="alternate"/><content xml:base="http://philtomson.github.io/atom.xml" type="html">&lt;p&gt;I finished up a 16-month LLVM contracting gig at the end of 2016. Got the flu a couple of weeks ago and have been pretty much out of commission until today when I finally had enough mental clarity and energy to get this blog going again.&lt;/p&gt;

&lt;p&gt;Since I last posted in 2014 it seems that Octopress has been updated. I had to go back to my old desktop machine and find where all the blog-related files were and transfer them to my current desktop machine. Of course I tried looking at the Octopress documentation to figure out how it works since I&amp;rsquo;d completely forgotten in the last ~2.5 years. And of course, the docs no longer cover the old version of Octopress. So I went with the newer version and tried moving things over. For the most part it works. The twitter button that used to be over there on the right doesn&amp;rsquo;t seem to want to show up anymore and I have no idea why (it&amp;rsquo;s right there in the _config.yml). And pygments now seems to want a space between the language name and the &amp;lsquo;]&amp;rsquo; - so whereas &amp;lsquo;[lang:ocaml]&amp;rsquo; used to work for the code highlighting incantation, now it seems to want &amp;lsquo;[lang:ocaml ]&amp;rsquo; &amp;hellip; weird.&lt;/p&gt;

&lt;p&gt;So now that the blog &lt;em&gt;mostly&lt;/em&gt; seems to be working again, I&amp;rsquo;m going to be looking into BNNs &lt;a href=&quot;https://arxiv.org/pdf/1602.02830v3.pdf.&quot;&gt;(Binarized Neural Networks)&lt;/a&gt;. Weights in BNNs are represented as binary values and instead of matrix multiplications (as is common in regular neural nets) the main operation on binary weights is XNOR which is a lot faster and more amenable for implementation in hardware like FPGAs. But more on BNNs later, I hope to start blogging about my BNN investigations which is why I wanted to get the blog going again.&lt;/p&gt;
</content><id>http://philtomson.github.io/blog/2017/02/02/funemployment</id><title xml:base="http://philtomson.github.io/atom.xml" type="html">FUNemployment</title><updated>2017-02-03T00:49:19-00:00</updated><author><name>Phil Tomson</name></author></entry><entry><source><updated>2017-02-01T00:00:00-00:00</updated><link title="Enter the void *" type="text/html" href="http://blog.emillon.org" rel="related"/><link title="Enter the void *" type="application/rss+xml" href="http://blog.emillon.org/feeds/ocaml.xml" rel="self"/><id>http://blog.emillon.org</id><title type="text">Enter the void *</title><author><name>Etienne Millon</name></author></source><link href="http://blog.emillon.org/posts/2017-02-01-nabomamo-2016-writeup.html" rel="alternate"/><content xml:base="http://blog.emillon.org/feeds/ocaml.xml" type="html">&lt;p&gt;Hello! It’s 2016, it’s November, and apparently it rhymes with &lt;a href=&quot;http://nabomamo.botally.net/&quot;&gt;#NaBoMaMo&lt;/a&gt; 2016, the National Bot Making Month. &lt;a href=&quot;https://github.com/emillon/rain-bot&quot;&gt;I made a bot!&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Full disclosure:&lt;/em&gt; it’s actually 2017, but I started writing this in 2016 so it’s OK. Also I’m not actually from the US, but I’ll relax the definition a bit and let’s pretend it means International Bot Making Year. Close enough!&lt;/p&gt;
&lt;p&gt;Bots are all the rage - Twitter bots, IRC bots, Telegram bots… I decided to make a Slack bot to get more familiar with that API.&lt;/p&gt;
&lt;p&gt;I wanted this to be a small project - write and forget, basically. I started by defining some specs and lock those down:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;that bot works on Slack&lt;/li&gt;
&lt;li&gt;it uses the “will it rain in the next hour” API from Météo France.&lt;/li&gt;
&lt;li&gt;the bot understands 3 commands:&lt;/li&gt;
&lt;li&gt;tell you whether it will rain or not.&lt;/li&gt;
&lt;li&gt;show you a graph of rain level over the next hour.&lt;/li&gt;
&lt;li&gt;tell you when to go out to avoid the rain.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The next step was choosing the tech stack. For hosting itself I was sold on using Heroku from previous projects (or another PaaS host, for what it’s worth)&lt;/p&gt;
&lt;p&gt;As for the programming language itself, I hesitated between three choices:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal&quot;&gt;
&lt;li&gt;focus on the all-included experience: something that has libraries, tooling, but somehow boring;&lt;/li&gt;
&lt;li&gt;focus on the shipping experience: stuff that I use daily, but looking to get something online quickly;&lt;/li&gt;
&lt;li&gt;focus on learning something new.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first one means something like Python or Ruby. I am familiar with the languages and am pretty sure that there are libraries that can take care of the Slack API without me having to ever worry about HTTP endpoints. That means also first-class deployment and hosting.&lt;/p&gt;
&lt;p&gt;The second one is about OCaml: it’s a programming language I use daily at work, but the real goal would be to focus on shipping: create a project, write tests, write implementation, deploy, repeat for new features, forget.&lt;/p&gt;
&lt;p&gt;The third one means a totally new programming language. I heard a lot of good things about Elixir for backend applications and figured that it would be a good intro project. Learning a new language is always an interesting experience, because it makes you a better programmer in all languages, and having clear specs would make this manageable.&lt;/p&gt;
&lt;p&gt;The Python/Ruby solution seemed a bit boring. I probably would not learn a lot, only, maybe add a couple libraries to my toolbelt at most.&lt;/p&gt;
&lt;p&gt;Elixir sounds great, but learning a new language and a new project at the same time is too hard and too time consuming. I would rather write in a new language something I previously wrote in another language. Though for something small and focused like this, that could have worked.&lt;/p&gt;
&lt;p&gt;I first created the project structure: github repo, ocaml project (topkg, opam, etc). I like to use TDD for this kind of projects, so I added a small &lt;a href=&quot;https://github.com/mirage/alcotest&quot;&gt;alcotest&lt;/a&gt; suite. I also created the 12factor separation: a &lt;code&gt;Procfile&lt;/code&gt;, a small &lt;code&gt;bin/&lt;/code&gt; shell that reads the application configuration from the environment and starts a bot from &lt;code&gt;lib/&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I asked myself what to test: the &lt;a href=&quot;https://github.com/mirage/ocaml-cohttp&quot;&gt;cohttp&lt;/a&gt; library is nice, because servers and clients are built using normal functions that take a request and returns a response. That makes it possible to test almost everything at the ocaml level without having to go to the HTTP level. This is especially important since there is no way to mock values and functions in ocaml. Everything has to be real objects.&lt;/p&gt;
&lt;p&gt;However, even if it was possible to test everything, I decided to just focus on the domain logic without testing the HTTP part: for example, I would pass data structures directly to my bot object rather than building a cohttp request.&lt;/p&gt;
&lt;p&gt;A part that is important for me even for a small project like that, is to have some sort of CI: have travis run my test suite, and make a binary ready to be deployed to Heroku. That way, it is impossible to forget how to make changes, test and deploy, since this is all in a script.&lt;/p&gt;
&lt;p&gt;The other part that needed work is the actual Slack integration. The “slash” command API is pretty simple: it is possible to configure a Slack team such that typing &lt;code&gt;/rain&lt;/code&gt; will hit a particular URL. Some options are passed as &lt;code&gt;POST&lt;/code&gt; data and whatever is returned is displayed in Slack.&lt;/p&gt;
&lt;p&gt;I set up the Slack integration, wrote a function to distinguish between &lt;code&gt;/rain&lt;/code&gt; and &lt;code&gt;/rain list&lt;/code&gt; (using the POST data), and by the end of the second iteraton I had my second feature implemented, working, and deployed.&lt;/p&gt;
&lt;p&gt;All in all, that was pretty great. The code or the bot itself are not particularly fantastic, but I learned some important lessons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When you do not want to spend a lot of time on a task, invest in planning and keep the list of features short. That is pretty obvious in the context of paid work, but this is applies well to hobby programming too.&lt;/li&gt;
&lt;li&gt;Know what to test and what not to. Tests are useful to ensure that changes can be made without breaking everything, but testing that your HTTP library can parse POST data is a waste of time.&lt;/li&gt;
&lt;li&gt;In languages where it is not possible to mock or monkey patch functions, dependency injection is still possible. One may even argue that it leads to a better solution, since it removes the coupling between the different components.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can find &lt;a href=&quot;https://github.com/emillon/rain-bot&quot;&gt;the source of this bot on Github&lt;/a&gt;. See you next year, &lt;a href=&quot;http://nabomamo.botally.net/&quot;&gt;#NaBoMaMo&lt;/a&gt;! And thanks to Tully Hansen for organizing this.&lt;/p&gt;</content><id>http://blog.emillon.org/posts/2017-02-01-nabomamo-2016-writeup.html</id><title type="text">NaBoMaMo 2016 writeup</title><updated>2017-02-01T00:00:00-00:00</updated><author><name>Etienne Millon</name></author></entry><entry><summary type="text">&lt;p&gt;implement it once to know you can do it.  implement it a second time and you get readable code.  implementing it a third time from scratch may lead to useful libraries.&lt;/p&gt;
</summary><source><updated>2017-03-12T13:27:37-00:00</updated><link href="https://hannes.nqsb.io/atom" rel="self"/><id>urn:uuid:981361ca-e71d-4997-a52c-baeee78e4156</id><title type="text">full stack engineer</title><author><name>Hannes Mehnert</name></author></source><published>2017-01-30T14:02:47-00:00</published><link href="https://hannes.nqsb.io/Posts/Jackline" rel="alternate"/><content xml:base="https://hannes.nqsb.io/atom" type="html">

&lt;p&gt;&lt;img src='https://berlin.ccc.de/~hannes/jackline2.png' alt='screenshot' /&gt;&lt;/p&gt;
&lt;p&gt;Back in 2014, when we implemented &lt;a href='https://nqsb.io'&gt;TLS&lt;/a&gt; in OCaml, at some point
I was bored with TLS.  I usually need at least two projects (but not more than 5) at the same time to
procrastinate the one I should do with the other one - it is always more fun to
do what you&amp;#39;re not supposed to do.  I started to implement another security
protocol (&lt;a href='https://otr.cypherpunks.ca/'&gt;Off-the-record&lt;/a&gt;, resulted in
&lt;a href='https://hannesm.github.io/ocaml-otr/doc/Otr.html'&gt;ocaml-otr&lt;/a&gt;) on my own,
applying what I learned while co-developing TLS with David.  I was eager to
actually deploy our TLS stack: using it with a web server (see &lt;a href='https://hannes.nqsb.io/Posts/nqsbWebsite'&gt;this post&lt;/a&gt;) is fun, but only using one half
of the state machine (server side) and usually short-lived connections
(discovers lots of issues with connection establishment) - not the client side
and no long living connection (which may discover other kinds of issues, such as
leaking memory).&lt;/p&gt;
&lt;p&gt;To use the stack, I needed to find an application I use on a daily basis (thus
I&amp;#39;m eager to get it up and running if it fails to work).  Mail client or web
client are just a bit too big for a spare time project (maybe not ;).  Another
communication protocol I use daily is jabber, or
&lt;a href='https://en.wikipedia.org/wiki/Xmpp'&gt;XMPP&lt;/a&gt;.  Back then I used
&lt;a href='https://mcabber.com'&gt;mcabber&lt;/a&gt; inside a terminal, which is a curses based client
written in C.&lt;/p&gt;
&lt;p&gt;I started to develop &lt;a href='https://github.com/hannesm/jackline'&gt;jackline&lt;/a&gt; (first
commit is 13th November 2014), a terminal based XMPP client in
&lt;a href='https://hannes.nqsb.io/Posts/OCaml'&gt;OCaml&lt;/a&gt;.  This is a report of a
work-in-progress (unreleased, but publicly available!) software project.  I&amp;#39;m
not happy with the code base, but neverthelss consider it to be a successful
project: dozens of friends are using it (no exact numbers), I got &lt;a href='https://github.com/hannesm/jackline/graphs/contributors'&gt;contributions from other people&lt;/a&gt;
(more than 25 commits from more than 8 individuals), I use it on a daily basis
for lots of personal communication.&lt;/p&gt;
&lt;h2 id=&quot;WhatisXMPP&quot;&gt;What is XMPP?&lt;/h2&gt;

&lt;p&gt;The eXtensible Messaging and Presence Protocol (previously known as Jabber)
describes (these days as &lt;a href='https://tools.ietf.org/html/rfc6120'&gt;RFC 6120&lt;/a&gt;) a
communication protocol based on XML fragments, which enables near real-time
exchange of structured (and extensible) data between two network entities.&lt;/p&gt;
&lt;p&gt;The landscape of instant messaging used to contain ICQ, AOL instant messenger,
and MSN messenger.  In 1999, people defined a completely open protocol standard,
then named Jabber, since 2011 official RFCs.  It is a federated (similar to
eMail) near-real time extensible messaging system (including presence
information) used for instant messaging.  Extensions include end-to-end
encryption, multi-user chat, audio transport, ...  Unicode support is builtin,
everything is UTF8 encoded.&lt;/p&gt;
&lt;p&gt;There are various open jabber servers where people can register accounts, as
well as closed ones.  Google Talk used to federate (until 2014) into XMPP,
Facebook chat used to be based on XMPP.  Those big companies wanted something
&amp;quot;more usable&amp;quot; (where they&amp;#39;re more in control, reliable message delivery via
caching in the server and mandatory delivery receipts, multiple devices all
getting the same messages), and thus moved away from the open standard.&lt;/p&gt;
&lt;h3 id=&quot;XMPPSecurity&quot;&gt;XMPP Security&lt;/h3&gt;

&lt;p&gt;Authentication is done via a TLS channel (where your client should authenticate
the server), and SASL that the server authenticates your client.  I
&lt;a href='https://berlin.ccc.de/~hannes/secure-instant-messaging.pdf'&gt;investigated in 2008&lt;/a&gt; (in German)
which clients and servers use which authentication methods (I hope the state of
certificate verification improved in the last decade).&lt;/p&gt;
&lt;p&gt;End-to-end encryption is achievable using OpenPGP (rarely used in my group of
friends) via XMPP, or &lt;a href='https://otr.cypherpunks.ca/'&gt;Off-the-record&lt;/a&gt;, which was
pioneered over XMPP, and is still in wide use - it gave rise to forward secrecy:
if your long-term (stored on disk) asymmetric keys get seized or stolen, they
are not sufficient to decrypt recorded sessions (you can&amp;#39;t derive the session
key from the asymmetric keys) -- but the encrypted channel is still
authenticated (once you verified the public key via a different channel or a
shared secret, using the &lt;a href='https://en.wikipedia.org/wiki/Socialist_millionaire'&gt;Socialist millionaires problem&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;OTR does not support offline messages (the session keys may already be destroyed
by the time the communication partner reconnects and receives the stored
messages), and thus recently &lt;a href='https://conversations.im/omemo/'&gt;omemo&lt;/a&gt; was
developed.  Other messaging protocols (Signal, Threema) are not really open,
support no federation, but have good support for group encryption and offline
messaging.  (There is a &lt;a href='https://www.cypherpunks.ca/~iang/pubs/secmessaging-oakland15.pdf'&gt;nice overview over secure messaging and threats.&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;There is (AFAIK) no encrypted group messaging via XMPP; also the XMPP server
contains lots of sensible data: your address book (buddy list), together with
offline messages, nicknames you gave to your buddies, subscription information,
and information every time you connect (research of privacy preserving presence
protocols has been done, but is not widely used AFAIK,
e.g. &lt;a href='http://cacr.uwaterloo.ca/techreports/2014/cacr2014-10.pdf'&gt;DP5&lt;/a&gt;).&lt;/p&gt;
&lt;h3 id=&quot;XMPPclientlandscape&quot;&gt;XMPP client landscape&lt;/h3&gt;

&lt;p&gt;See &lt;a href='https://en.wikipedia.org/wiki/Comparison_of_XMPP_clients'&gt;wikipedia&lt;/a&gt; for an
extensive comparison (which does not mention jackline :P).&lt;/p&gt;
&lt;p&gt;A more opinionated analysis is that you were free to choose between C - where
all code has to do manual memory management and bounds checking - with ncurses
(or GTK) and OpenSSL (or GnuTLS) using libpurple (or some other barely
maintained library which tries to unify all instant messaging protocols), or
Python - where you barely know upfront what it will do at runtime - with GTK and
some OpenSSL, or even JavaScript - where external scripts can dynamically modify
the prototype of everything at runtime (and thus modify code arbitrarily,
violating invariants) - calling out to C libraries (NSS, maybe libpurple, who
knows?).&lt;/p&gt;
&lt;p&gt;Due to complex APIs of transport layer security, certificate verification is
&lt;a href='https://pidgin.im/news/security/?id=91'&gt;still not always done correctly&lt;/a&gt; (that&amp;#39;s just
one example, you&amp;#39;ll find more) - even if, it may not allow custom trust anchors
or certificate fingerprint based verification - which are crucial for a
federated operations without a centralised trust authority.&lt;/p&gt;
&lt;p&gt;Large old code basis usually gather dust and getting bitrot - and if you add
patch by patch from random people on the Internet, you&amp;#39;ve to deal with the most
common bug: insufficient checking of input (or output data, &lt;a href='https://dev.gajim.org/gajim/gajim-plugins/issues/145'&gt;if you encrypt only the plain body, but not the marked up one&lt;/a&gt;).  In some
programming languages this easily &lt;a href='https://pidgin.im/news/security/?id=64'&gt;leads to execution of remote code&lt;/a&gt;, other programming languages steal the
work from programmers by deploying automated memory management (finally machines
take our work away! :)) - also named garbage collection, often used together
with automated bounds checking -- this doesn&amp;#39;t mean that you&amp;#39;re safe - there are
still logical flaws, and integer overflows (and funny things which happen at
resource starvation), etc.&lt;/p&gt;
&lt;h3 id=&quot;Goalsandnongoals&quot;&gt;Goals and non-goals&lt;/h3&gt;

&lt;p&gt;My upfront motivation was to write and use an XMPP client tailored to my needs.
I personally don&amp;#39;t use many graphical applications (coding in emacs, mail via
thunderbird, firefox, mplayer, mupdf), but stick mostly to terminal
applications.  I additionally don&amp;#39;t use any terminal multiplexer (saw too many
active &lt;code&gt;screen&lt;/code&gt; sessions on remote servers where people left root shells open).&lt;/p&gt;
&lt;p&gt;The &lt;a href='https://github.com/hannesm/jackline/commit/9322ceefa9a331fa92a6bf253e8d8f010da2229c'&gt;goal was from the beginning&lt;/a&gt;
to write a &amp;quot;minimalistic graphical user interface for a secure (fail hard)
and trustworthy XMPP client&amp;quot;.  By &lt;em&gt;fail hard&lt;/em&gt; I mean exactly that: if it can&amp;#39;t
authenticate the server, don&amp;#39;t send the password.  If there is no
end-to-end encrypted session, don&amp;#39;t send the message.&lt;/p&gt;
&lt;p&gt;As a user of (unreleased) software, there is a single property which I like to
preserve: continue to support all data written to persistent storage.  Even
during large refactorings, ensure that data on the user&amp;#39;s disk will also be
correctly parsed.  There is nothing worse than having to manually configure an
application after update.  The solution is straightforward: put a version in
every file you write, and keep readers for all versions ever written around.
My favourite marshalling format (human readable, structured) are still
S-expressions - luckily there is a
&lt;a href='https://github.com/janestreet/sexplib'&gt;sexplib&lt;/a&gt; in OCaml for handling these.
Additionally, once the initial configuration file has been created (e.g. interactively with the application), the application
does no further writes to the config file.  Users can make arbitrary modifications to the file,
and restart the application (and they can make changes while the application is running).&lt;/p&gt;
&lt;p&gt;I also appreciate another property of software: don&amp;#39;t ever transmit any data or
open a network connection unless initiated by the user (this means no autoconnect on startup, or user is typing indications).  Don&amp;#39;t be obviously
fingerprintable.  A more mainstream demand is surely that software should not
phone home - that&amp;#39;s why I don&amp;#39;t know how many people are using jackline, reports
based on friends opinions are hundreds of users, I personally know at least
several dozens.&lt;/p&gt;
&lt;p&gt;As written &lt;a href='https://hannes.nqsb.io/Posts/OperatingSystem'&gt;earlier&lt;/a&gt;, I often take
a look at the trusted computing base of a computer system.  Jackline&amp;#39;s trusted
computing base consists of the client software itself, its OCaml dependencies
(including OTR, TLS, tty library, ...), then the OCaml runtime system, which
uses some parts of libc, and a whole UNIX kernel underneath -- one goal is to
have jackline running as a unikernel (then you connect via SSH or telnet and
TLS).&lt;/p&gt;
&lt;p&gt;There are only a few features I need in an XMPP client: single account, strict
validation, delivery receipts, notification callback, being able to deal with
friends logged in multiple times with wrongly set priorities - and end-to-end
encryption.  I don&amp;#39;t need inline HTML, avatar images, my currently running
music, leaking timezone information, etc.  I explicitly don&amp;#39;t want to import any
private key material from other clients and libraries, because I want to ensure
that the key was generated by a good random number generator (read &lt;a href='https://mirage.io/blog/mirage-entropy'&gt;David&amp;#39;s blog article&lt;/a&gt; on randomness and entropy).&lt;/p&gt;
&lt;p&gt;The security story is crucial: always do strict certificate validation, fail
hard, make it noticable by the user if they&amp;#39;re doing insecure communication.
Only few people are into reading out loud their OTR public key fingerprint, and
SMP is not trivial -- thus jackline records the known public keys together with
a set of resources used, a session count, and blurred timestamps (accuracy: day)
when the publickey was initially used and when it was used the last time.&lt;/p&gt;
&lt;p&gt;I&amp;#39;m pragmatic - if there is some server (or client) deployed out there which
violates (my interpretation of) the specification, I&amp;#39;m happy to &lt;a href='https://github.com/hannesm/ocaml-otr/issues/10'&gt;implement workarounds&lt;/a&gt;.  Initially I
worked roughly one day a week on jackline.&lt;/p&gt;
&lt;p&gt;To not release the software for some years was something I learned from the
&lt;a href='https://common-lisp.net/project/slime/'&gt;slime&lt;/a&gt; project (&lt;a href='https://www.youtube.com/watch?v=eZDWJfB9XY4'&gt;watch Luke&amp;#39;s presentation from 2013&lt;/a&gt;) - if
there&amp;#39;s someone complaining about an issue, fix it within 10 minutes and ask
them to update.  This only works if each user compiles the git version anyways.&lt;/p&gt;
&lt;h2 id=&quot;Userinterface&quot;&gt;User interface&lt;/h2&gt;

&lt;p&gt;&lt;img src='https://berlin.ccc.de/~hannes/jackline.png' alt='other screenshot' /&gt;&lt;/p&gt;
&lt;p&gt;Stated goal is &lt;em&gt;minimalistic&lt;/em&gt;.  No heavy use of colours.  Visibility on
both black and white background (btw, as a Unix process there is no way to find
out your background colour (or is there?)).  The focus is also &lt;em&gt;security&lt;/em&gt; - and
that&amp;#39;s where I used colours from the beginning: red is unencrypted (non
end-to-end, there&amp;#39;s always the transport layer encryption) communication, green
is encrypted communication.  Verification status of the public key uses the same
colours: red for not verified, green for verified.  Instead of colouring each
message individually, I use the encryption status of the active contact
(highlighted in the contact list, where messages you type now will be sent to)
to colour the entire frame.  This results in a remarkable visual indication and
(at least I) think twice before presssing &lt;code&gt;return&lt;/code&gt; in a red terminal.  Messages
were initially white/black, but got a bit fancier over time: incoming messages
are bold, multi user messages mentioning your nick are underlined.&lt;/p&gt;
&lt;p&gt;The graphical design is mainly inspired by mcabber, as mentioned earlier.  There
are four components: the contact list in the upper left, chat window upper
right, log window on the bottom (surrounded by two status bars), and a readline
input.  The sizes are configurable (via commands and key shortcuts).  A
different view is having the chat window fullscreen (or only the received
messages) - useful for copy and pasting fragments.  Navigation is done in the
contact list.  There is a single active contact (colours are inverted in the
contact list, and the contact is mentioned in the status bar), whose chat
messages are displayed.&lt;/p&gt;
&lt;p&gt;There is not much support for customisation - some people demanded to have a
7bit ASCII version (I output some unicode characters for layout).  Recently I
added support to customise the colours.  I tried to ensure it looks fine on both
black and white background.&lt;/p&gt;
&lt;h2 id=&quot;Code&quot;&gt;Code&lt;/h2&gt;

&lt;p&gt;Initially I targeted GTK with OCaml, but that excursion only lasted &lt;a href='https://github.com/hannesm/jackline/commit/17b674130f7b1fcf2542eb5e0911a40b81fc724e'&gt;two weeks&lt;/a&gt;,
when I switched to a &lt;a href='https://github.com/diml/lambda-term'&gt;lambda-term&lt;/a&gt; terminal
interface.&lt;/p&gt;
&lt;h3 id=&quot;UI&quot;&gt;UI&lt;/h3&gt;

&lt;p&gt;The lambda-term interface survived for a good year (until &lt;a href='https://github.com/hannesm/jackline/pull/117'&gt;7th Feb 2016&lt;/a&gt;),
when I started to use &lt;a href='https://github.com/pqwy/notty'&gt;notty&lt;/a&gt; - developed by
David - using a decent &lt;a href='http://erratique.ch/software/uutf'&gt;unicode library&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Notty back then was under heavy development, I spend several hours rebasing
jackline to updates in notty.  What I got out of it is proper unicode support:
the symbol 茶 gets two characters width (see screenshot at top of page), and the layouting keeps track
how many characters are already written on the terminal.&lt;/p&gt;
&lt;p&gt;I recommend to look into &lt;a href='https://github.com/pqwy/notty'&gt;notty&lt;/a&gt; if you want to
do terminal graphics in OCaml!&lt;/p&gt;
&lt;h3 id=&quot;Applicationlogicandstate&quot;&gt;Application logic and state&lt;/h3&gt;

&lt;p&gt;Stepping back, an XMPP client reacts to two input sources: the user input
(including terminal resize), and network input (or failure).  The output is a
screen (80x25 characters) image.  Each input event can trigger output events on
the display and the network.&lt;/p&gt;
&lt;p&gt;I used to use multiple threads and locking between shared data for these kinds
of applications: there can go something wrong when network and user input
happens at the same time, or what if the output is interrupted by more input
(which happens e.g. during copy and paste).&lt;/p&gt;
&lt;p&gt;Initially I used lots of shared data and had hope, but this was clearly not a
good solution.  Nowadays I use mailboxes, and separate tasks which wait for
receiving a message: one task which writes persistent data (session counts,
verified fingerprints) periodically to ask, another which writes on change to
disk, an error handler
(&lt;a href='https://github.com/hannesm/jackline/blob/ec8f8c01d6503bf52be263cd319ef21f2b62ff2e/bin/jackline.ml#L3-L25'&gt;&lt;code&gt;init_system&lt;/code&gt;&lt;/a&gt;)
which resets the state upon a connection failure, another task which waits for
user input
(&lt;a href='https://github.com/hannesm/jackline/blob/ec8f8c01d6503bf52be263cd319ef21f2b62ff2e/cli/cli_input.ml#L169'&gt;&lt;code&gt;read_terminal&lt;/code&gt;&lt;/a&gt;),
one waiting for network input (&lt;a href='https://github.com/hannesm/jackline/blob/ec8f8c01d6503bf52be263cd319ef21f2b62ff2e/cli/cli_state.ml#L202'&gt;&lt;code&gt;Connect&lt;/code&gt;, including reconnecting timers&lt;/a&gt;),
one to call out the notification hooks
(&lt;a href='https://github.com/hannesm/jackline/blob/ec8f8c01d6503bf52be263cd319ef21f2b62ff2e/cli/cli_state.ml#L100'&gt;&lt;code&gt;Notify&lt;/code&gt;&lt;/a&gt;),
etc.  The main task is simple: wait for input, process input (producing a new
state), render the state, and recursively call itself
(&lt;a href='https://github.com/hannesm/jackline/blob/ec8f8c01d6503bf52be263cd319ef21f2b62ff2e/cli/cli_client.ml#L371'&gt;&lt;code&gt;loop&lt;/code&gt;&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Only recently I solved the copy and paste issue by &lt;a href='https://github.com/hannesm/jackline/commit/cab34acab004023911997ec9aee8b00a976af7e4'&gt;delaying all redraws by 40ms&lt;/a&gt;,
and canceling if another redraw is scheduled.&lt;/p&gt;
&lt;p&gt;The whole
&lt;a href='https://github.com/hannesm/jackline/blob/ec8f8c01d6503bf52be263cd319ef21f2b62ff2e/cli/cli_state.ml#L29-L58'&gt;&lt;code&gt;state&lt;/code&gt;&lt;/a&gt;
contains some user interface parameters (&lt;code&gt;/buddywith&lt;/code&gt;, &lt;code&gt;/logheight&lt;/code&gt;, ..), as
well as the contact map, which contain users, which have sessions, each
containing chat messages.&lt;/p&gt;
&lt;p&gt;The code base is just below 6000 lines of code (way too big ;), and nowadays
supports multi-user chat, sane multi-resource interaction (press &lt;code&gt;enter&lt;/code&gt; to show
all available resources of a contact and message each individually in case you
need to), configurable colours, tab completions for nicknames and commands,
per-user input history, emacs keybindings.  It even works with the XMPP gateway
provided by slack (some startup doing a centralised groupchat with picture embedding and
animated cats).&lt;/p&gt;
&lt;h3 id=&quot;Roadahead&quot;&gt;Road ahead&lt;/h3&gt;

&lt;p&gt;Common feature requests are: &lt;a href='https://github.com/hannesm/jackline/issues/153'&gt;omemo support&lt;/a&gt;,
&lt;a href='https://github.com/hannesm/jackline/issues/104'&gt;IRC support&lt;/a&gt;,
&lt;a href='https://github.com/hannesm/jackline/issues/115'&gt;support for multiple accounts&lt;/a&gt;
(tbh, these are all
things I&amp;#39;d like to have as well).&lt;/p&gt;
&lt;p&gt;But there&amp;#39;s some mess to clean up:&lt;/p&gt;
&lt;ol&gt;&lt;li&gt;&lt;p&gt;The &lt;a href='https://github.com/ermine/xmpp'&gt;XMPP library&lt;/a&gt; makes heavy use of
functors (to abstract over the concrete IO, etc.), and embeds IO deep inside it.
I do prefer (see e.g. &lt;a href='https://usenix15.nqsb.io'&gt;our TLS paper&lt;/a&gt;, or &lt;a href='https://hannes.nqsb.io/Posts/ARP'&gt;my ARP post&lt;/a&gt;) these days to have a pure interface for
the protocol implementation, providing explicit input (state, event, data), and
output (state, action, potentially data to send on network, potentially data to
process by the application).  The &lt;a href='https://github.com/hannesm/xmpp/blob/eee18bd3dd343550169969c0b45548eafd51cfe1/src/sasl.ml'&gt;sasl implementation&lt;/a&gt;
is partial and deeply embedded.  The XML parser is as well deeply embedded (and
&lt;a href='https://github.com/hannesm/jackline/issues/8#issuecomment-67773044'&gt;has some issues&lt;/a&gt;).
The library needs to be torn apart (something I procrastinate since more than
a year).  Once it is pure, the application can have full control over when to
call IO (and esp use the same protocol implementation as well for registering a
new account - &lt;a href='https://github.com/hannesm/jackline/issues/12'&gt;currently not supported&lt;/a&gt;).&lt;/p&gt;
&lt;/li&gt;&lt;li&gt;&lt;p&gt;On the frontend side (the &lt;code&gt;cli&lt;/code&gt; subfolder), there is too much knowledge of
XMPP.  It should be more general, and be reusable (some bits and pieces are
notty utilities, such as wrapping a string to fit into a text box of specific
width, see
&lt;a href='https://github.com/hannesm/jackline/blob/ec8f8c01d6503bf52be263cd319ef21f2b62ff2e/cli/cli_support.ml#L22'&gt;&lt;code&gt;split_unicode&lt;/code&gt;&lt;/a&gt;).&lt;/p&gt;
&lt;/li&gt;&lt;li&gt;&lt;p&gt;The command processing engine itself is 1300 lines (including ad-hoc string
parsing)
(&lt;a href='https://github.com/hannesm/jackline/blob/ec8f8c01d6503bf52be263cd319ef21f2b62ff2e/cli/cli_commands.ml'&gt;&lt;code&gt;Cli_commands&lt;/code&gt;&lt;/a&gt;),
best to replaced by a more decent command abstraction.&lt;/p&gt;
&lt;/li&gt;&lt;li&gt;&lt;p&gt;A big record of functions
(&lt;a href='https://github.com/hannesm/jackline/blob/ec8f8c01d6503bf52be263cd319ef21f2b62ff2e/src/xmpp_callbacks.ml#L46'&gt;&lt;code&gt;user_data&lt;/code&gt;&lt;/a&gt;)
is passed (during &lt;code&gt;/connect&lt;/code&gt; in
&lt;a href='https://github.com/hannesm/jackline/blob/ec8f8c01d6503bf52be263cd319ef21f2b62ff2e/cli/cli_commands.ml#L221-L582'&gt;&lt;code&gt;handle_connect&lt;/code&gt;&lt;/a&gt;)
from the UI to the XMPP task to inject messages and errors.&lt;/p&gt;
&lt;/li&gt;&lt;li&gt;&lt;p&gt;The global variable
&lt;a href='https://github.com/hannesm/jackline/blob/ec8f8c01d6503bf52be263cd319ef21f2b62ff2e/cli/cli_state.ml#L200'&gt;&lt;code&gt;xmpp_session&lt;/code&gt;&lt;/a&gt;
should be part of the earlier mentioned &lt;code&gt;cli_state&lt;/code&gt;, also contacts should be a map, not a Hashtbl (took me some time to learn).&lt;/p&gt;
&lt;/li&gt;&lt;li&gt;&lt;p&gt;Having jackline self-hosted as a MirageOS unikernel.  I&amp;#39;ve implemented a a
&lt;a href='https://github.com/hannesm/telnet'&gt;telnet&lt;/a&gt; server, there is a
&lt;a href='https://github.com/pqwy/notty/tree/mirage'&gt;notty branch&lt;/a&gt; be used with the telnet
server.  But there is (right now) no good story for persistent mutable storage.&lt;/p&gt;
&lt;/li&gt;&lt;li&gt;&lt;p&gt;Jackline predates some very elegant libraries, such as
&lt;a href='http://erratique.ch/software/logs'&gt;logs&lt;/a&gt; and
&lt;a href='http://erratique.ch/software/astring'&gt;astring&lt;/a&gt;, even
&lt;a href='http://caml.inria.fr/pub/docs/manual-ocaml/libref/Pervasives.html#TYPEresult'&gt;result&lt;/a&gt; - since 4.03 part of Pervasives - is not used.
Clearly, other libraries (such as TLS) do not yet use result.&lt;/p&gt;
&lt;/li&gt;&lt;li&gt;&lt;p&gt;After looking in more depths at the logs library, and at user interfaces - I
envision the graphical parts to be (mostly!?) a viewer of logs, and a command
shell (using a control interface, maybe
&lt;a href='https://github.com/mirage/ocaml-9p/'&gt;9p&lt;/a&gt;): Multiple layers (of a protocol),
slightly related (by &lt;a href='http://erratique.ch/software/logs/doc/Logs.Tag.html'&gt;tags&lt;/a&gt; - such as the OTR session), and have the layers be visible to users (see also
&lt;a href='https://github.com/mirleft/tlstools'&gt;tlstools&lt;/a&gt;), a slightly different interface
of similarly structured data.  In jackline I&amp;#39;d like to e.g. see all messages of
a single OTR session (see &lt;a href='https://github.com/hannesm/jackline/issues/111'&gt;issue&lt;/a&gt;), or hide the presence messages in a multi-user chat,
investigate the high-level message, its XML encoded stanza, TLS encrypted
frames, the TCP flow, all down to the ethernet frames send over the wire - also
viewable as sequence diagram and other suitable (terminal) presentations (TCP
window size maybe in a size over time diagram).&lt;/p&gt;
&lt;/li&gt;&lt;li&gt;&lt;p&gt;Once the API between the sources (contacts, hosts) and the UI (what to
display, where and how to trigger notifications, where and how to handle global
changes (such as reconnect)) is clear and implemented, commands need to be
reinvented (some, such as navigation commands and emacs keybindings, are generic
to the user interface, others are specific to XMPP and/or OTR): a new transport
(IRC) or end-to-end crypto protocol (omemo) - should be easy to integrate (with
similar minimal UI features and colours).&lt;/p&gt;
&lt;/li&gt;&lt;/ol&gt;

&lt;h3 id=&quot;Conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Jackline started as a procrastination project, and still is one.  I only develop
on jackline if I enjoy it.  I&amp;#39;m not scared to try new approaches in jackline,
and either reverting them or rewriting some chunks of code again.  It is a
project where I publish early and push often.  I&amp;#39;ve met several people (whom I
don&amp;#39;t think I know personally) in the multi-user chatroom
&lt;code&gt;jackline@conference.jabber.ccc.de&lt;/code&gt;, and fixed bugs, discussed features.&lt;/p&gt;
&lt;p&gt;When introducing &lt;a href='https://github.com/hannesm/jackline/commit/40bec5efba81061cc41df891cadd282120e16816'&gt;customisable colours&lt;/a&gt;,
the proximity to a log viewer became again clear to me - configurable colours
are for severities such as &lt;code&gt;Success&lt;/code&gt;, &lt;code&gt;Warning&lt;/code&gt;, &lt;code&gt;Info&lt;/code&gt;, &lt;code&gt;Error&lt;/code&gt;, &lt;code&gt;Presence&lt;/code&gt; -
maybe I really should get started on implementing a log viewer.&lt;/p&gt;
&lt;p&gt;I would like to have more community contributions to jackline, but the lack of
documentation (there aren&amp;#39;t even a lot of interface files), mixed with a
non-mainstream programming language, and a convoluted code base, makes me want
some code cleanups first, or maybe starting from scratch.&lt;/p&gt;
&lt;p&gt;I&amp;#39;m interested in feedback, either via &lt;a href='https://twitter.com/h4nnes'&gt;twitter&lt;/a&gt; or
on the &lt;a href='https://github.com/hannesm/jackline'&gt;jackline repository on GitHub&lt;/a&gt;.&lt;/p&gt;
</content><category scheme="https://hannes.nqsb.io/tags/UI" term="UI"/><category scheme="https://hannes.nqsb.io/tags/security" term="security"/><id>urn:uuid:73a52847-8672-5fa9-a9ec-39bfcf7a4608</id><title type="text">Jackline, a secure terminal-based XMPP client</title><updated>2017-03-12T13:27:37-00:00</updated><author><name>hannes</name></author></entry></feed>