Jesse's NotesMy own semi-coherent thoughts on technology, politics, local news, and whatever I happen to be reading, doing, or learning at the time. Anything posted on this blog represents my own views, and not those of my employer or any organization.
http://blog.haberkucharsky.com/
Sun, 06 Jan 2019 01:48:43 +0000Sun, 06 Jan 2019 01:48:43 +0000Jekyll v3.7.4Ant colony optimization in Scala<p>In this post, we’ll walk through a novel method of solving a famous mathematical problem from computer science, and in the process, I’ll describe how it can be implemented effectively in Scala.</p>
<p>All the code in this post is available on <a href="https://github.com/hakuch/TravellingAnts">GitHub</a>.</p>
<h1 id="framing-the-problem">Framing the problem</h1>
<p>Let’s consider a map of locations, identified by their numerical index for convenience.</p>
<p><img src="/img/2015-10-05-locations.png" alt="Map of locations" title="Map of locations" /></p>
<p>A salesperson wants to visit each location exactly once to peddle his wares, and then return to his original destination. Because gas costs considerably more these days, he wants to reduce his travel costs (through minimizing the total distance he travels) as much as possible. What’s the optimal route?</p>
<p>This is a classic problem in computer science called the <a href="https://en.wikipedia.org/wiki/Travelling_salesman_problem">travelling salesman problem</a>.</p>
<p>
<div class="has-jax">
In general, if there are \(n\) locations, then the number of possible solutions is \(\mathcal{O}\left(n!\right)\). Even for relatively small location graphs, a so-called "brute-force" algorithm (one that enumerates all possible solutions) will take too long to find the optimal solution.
</div>
</p>
<p>There are many alternative approaches to solving problems like this. A common theme to these approaches is to be smarter about where in the <em>solution space</em> (the set of possible solutions) they search based on heuristics.</p>
<h2 id="some-more-details">Some more details</h2>
<p>Before we start discussing solving methods, let’s establish some more details that are necessary.</p>
<p>Let’s define a <em>solution</em> as some tour of all the locations, without visiting the same one more than once, and returning to the origin.</p>
<div class="has-jax">
If the set of locations that we would like to visit is \(\{1, 2, 3, 4\}\), then some valid solutions are
\[
2 \rightarrow 3 \rightarrow 4 \rightarrow 1 \rightarrow 2
\]
and
\[
4 \rightarrow 2 \rightarrow 1 \rightarrow 3 \rightarrow 4.
\]
</div>
<p>I also said the word “cost” without really establishing what I meant. The <em>cost</em> of a solution is how we’ll differentiate a good solution from a bad one. This is a representative quantity of the utility of a solution. The cost function of an optimization problem is often called the “objective function”.</p>
<p>In this problem, we’ll assume that our salesperson can travel in straight lines between all locations, so we’ll define the objective function as the sum of the euclidean distances between each of the steps in the tour.</p>
<p class="has-jax">
As a refresher, given two points, \(p_1 = \left(x_1, y_1\right)\) and \(p_2 = \left(x_2, y_2\right)\), the distance between them (let's denote it \(d : \mathbb{R}^2 \times \mathbb{R}^2 \rightarrow \mathbb{R}\)) is
\[
d{\left(p_1, p_2\right)} = \sqrt{\left(x_2 - x_1\right)^2 + \left(y_2 - y_1\right)^2}
\]
</p>
<h1 id="representing-the-problem-domain">Representing the problem domain</h1>
<p>We can start by writing some code for our problem domain.</p>
<p>Each location is represented by a two-dimensional point:</p>
<script src="https://gist.github.com/hakuch/ae2a8036d880b2de7fe1.js"></script>
<h2 id="connected-undirected-graphs">Connected, undirected graphs</h2>
<p>The essence of our problem is that the locations form an <em>undirected graph</em> where the edges between nodes (locations) have a weight based on their distance. Furthermore, since every location is connected to every other location, this is a connected graph. We could use a simple associative container to store this structure:</p>
<script src="https://gist.github.com/hakuch/be92996056bbf3bc8569.js"></script>
<p>but Scala allows us abstraction so that we can ensure that the data always conforms to invariants that we expect. Consider the following code, which is a type-generic implementation of a connected graph with some useful utilities:</p>
<script src="https://gist.github.com/hakuch/f623e0cb7fb46ed3458a.js"></script>
<p>A <code class="highlighter-rouge">ConnectedGraph[A, W]</code> is immutable, and the edge weights (of type <code class="highlighter-rouge">W</code>) are not specified individually, but through a function of the edges nodes. This implementation also doesn’t do any verification that node arguments to functions like <code class="highlighter-rouge">weight(source: A, dest: A): W</code> (which is the weight on the edge between the <code class="highlighter-rouge">source</code> and <code class="highlighter-rouge">dest</code> nodes) refer to nodes that are present in the graph.</p>
<h2 id="solutions">Solutions</h2>
<p>In this problem, the nodes are of type <code class="highlighter-rouge">Int</code> and the edge weights are of type <code class="highlighter-rouge">Double</code>. A solution is an ordered list of steps between locations. We also store the graph to which the solution belongs, and a method for calculating the solution’s cost. Finally, we add a function for generating random solutions to a graph.</p>
<script src="https://gist.github.com/hakuch/0a53359da7483c92bfaf.js"></script>
<h1 id="ant-colony-optimization">Ant colony optimization</h1>
<p>With all the preliminary code out of the way, let’s talk about our solver.</p>
<p>Ant colony optimization <sup id="fnref:1"><a href="#fn:1" class="footnote">1</a></sup> is a novel optimization approach that was invented by Marco Dorigo in 1992.</p>
<p>The basic idea is fairly straightforward. In nature (to a rough approximation), ants start out by walking in random directions looking for food, and as they do so, they deposit pheromones along their path. When an ant finds food, it will walk the same path repeatedly as it carries off as much as it can handle back to the colony, and then returns to the food source. When other ants are deciding where to travel, they prefer to follow routes where more pheromones have been deposited. Thus, more and more ants start walking the same route, which encourages more ants, until the whole colony is able to join in.</p>
<p>Let’s try to model this algorithmically to solve our problem <sup id="fnref:2"><a href="#fn:2" class="footnote">2</a></sup>.</p>
<p>To start, we’ll choose a random solution and iteratively run our algorithm many times, while keeping track of the best overall solution to date.</p>
<p>In each iteration, we’ll do the following:</p>
<ul>
<li>
<p class="has-jax">Place \(k\) "ants" on random nodes of the graph.</p>
</li>
<li>
<p>Each ant constructs a tour of the graph. The choice of location to visit next on each step of the tour is weighted by both the distance of the neighbours and the amount of pheromone between them.</p>
</li>
<li>
<p class="has-jax">When all \(k\) ants have returned, increase the pheromone levels in the graph where the ants have travelled.</p>
</li>
</ul>
<p>Additionally, on every iteration, we will decrease the pheromone levels on <em>all</em> edges of the graph. This step is important for the solver to be able to “explore” alternative solutions rather than focusing on a single one. This trade-off is typically called “exploitation versus exploration”.</p>
<h2 id="more-details">More details</h2>
<p>Let’s expand on two details of the algorithm that I alluded to above. These are the way that an ant chooses a new destination on the tour and how pheromones get updated after every iteration.</p>
<p class="has-jax">
For each destination that an ant has not yet visited, we compute a weight that will be used for probabilistically choosing that destination. The weight expression is
\[
w{\left(i, j\right)} = \frac{\frac{f^\alpha_{ij}}{d^\beta{\left(p_i, p_j\right)}}}{\sum_{u,v} \frac{f^\alpha_{uv}}{d^\beta{\left(p_u, p_v\right)}}}
\]
</p>
<ul>
<li>
<p class="has-jax">\(f_{ij}\) is the current amount of pheromone deposited on the edge between \(i\) and \(j\).</p>
</li>
<li>
<p class="has-jax">\(\alpha\) is a configurable constant, usually less than 1.0. A higher value will tend to weight the pheromone value more significantly. </p>
</li>
<li>
<p class="has-jax"> \(\beta\) is similar to \(\alpha\), except that it weights the distance between edges more significantly. </p>
</li>
<li>
<p class="has-jax"> The bottom term is a normalization factor that ensures that all the weights add to one (and thus, that they are probabilities). </p>
</li>
</ul>
<p class="has-jax">
On every iteration, we decrease the pheromone levels on every edge by a fixed factor \(g \in \left(0, 1\right)\):
\[
f_{ij} \leftarrow \left(1 - g\right) \cdot f_{ij}
\]
</p>
<p class="has-jax">
For every step \(\left(i, j\right)\) in an ant's solution, we increase the pheromones on that edge by
\[
f_{ij} \leftarrow f_{ij} + \frac{F}{c \cdot d{\left(p_i, p_j\right)}}
\]
where \(F\) is a fixed constant, and \(c\) is the cost of the the ant's solution. This way, ants will tend to deposit more pheromones on better solutions and prefer edges that are shorter.
</p>
<h1 id="how-it-looks-in-scala">How it looks in Scala</h1>
<p>A lot of the implementation details of the formulae above are self-evident in Scala given the machinery we already defined, so I’ll focus this section on some key elements of the implementation that are worth mentioning.</p>
<p>There are some common themes:</p>
<ul>
<li>
<p>Mutation is never exposed through an interface, but sometimes it’s used internally inside a referentially-transparent function. Structures are never mutated either; new structures are created instead.</p>
</li>
<li>
<p>A modular style that’s familiar to OCaml/SML fans, instead of object-orientation with implementation inheritance <sup id="fnref:3"><a href="#fn:3" class="footnote">3</a></sup>.</p>
</li>
</ul>
<h2 id="ants">Ants</h2>
<p>The code below shows the <code class="highlighter-rouge">Ant</code> class definition.</p>
<script src="https://gist.github.com/hakuch/3ec2b46c34e9685e6933.js"></script>
<p>There are a couple of points worth mentioning here.</p>
<p>The <code class="highlighter-rouge">Ant</code> class is really a module which contains type and method definitions.</p>
<p>The constants <code class="highlighter-rouge">alpha</code> and <code class="highlighter-rouge">beta</code> which are used to control the travel probabilities are left abstract (and the overall class is abstract as a result). We defined <code class="highlighter-rouge">Ant.Defaults</code> so that creating a typical ant instance is as simple as <code class="highlighter-rouge">new Ant with Ant.Defaults</code>, but defining custom values for the constants is as easy as <code class="highlighter-rouge">new Ant { def alpha = 0.3; def beta = 0.5 }</code>, for example.</p>
<h2 id="colonies-of-ants">Colonies of ants</h2>
<p>A colony is parameterized on the kind of ant that it is composed of.</p>
<script src="https://gist.github.com/hakuch/d26fcf2ac6af7efe6fa5.js"></script>
<p>The most interesting things in this implementation include the fact that, like ML functors, the <code class="highlighter-rouge">Colony</code> “module” is a function of a particular <code class="highlighter-rouge">Ant</code> module.</p>
<p>We define a record for keeping track of the solver progress, <code class="highlighter-rouge">Progress</code>. Instead of logging our solver’s progress to <code class="highlighter-rouge">stdout</code> or <code class="highlighter-rouge">stderr</code>, the solver takes an optional listener which is invoked for every ant that returns with the latest progress.</p>
<p>Finally, we use <code class="highlighter-rouge">Task</code> from the Scalaz library. This is like a <code class="highlighter-rouge">scala.concurrent.Future</code>, but <code class="highlighter-rouge">Task</code>s are only executed on their result is explicitly requested, unlike <code class="highlighter-rouge">Future</code>s which start executing immediately. The main loop inside <code class="highlighter-rouge">Colony#solve</code> is a recursive function that makes use of the <code class="highlighter-rouge">Task</code> monad.</p>
<h2 id="main-program">Main program</h2>
<p>The <code class="highlighter-rouge">main</code> function sets up a logger as the solver listener which logs each iteration to a file for analysis, runs the solver for 3000 iterations, and then formats the best solution as a DOT graph.</p>
<script src="https://gist.github.com/hakuch/27a3e45a173b8e895716.js"></script>
<h1 id="sample-results">Sample results</h1>
<p>We can visualize the solution of one run of the program:</p>
<p><img src="/img/2015-10-12-solution.png" alt="Best solution" title="Best solution" /></p>
<p>and also see how the solution progressed as the solver ran:</p>
<p><img src="/img/2015-10-12-solution-iterations.png" alt="Solver iterations" title="Solution iterations" /></p>
<p>As a reminder, the code from this post is available in its entirety on <a href="https://github.com/hakuch/TravellingAnts">GitHub</a>.</p>
<h1 id="next-steps">Next steps</h1>
<p>Where do we go from here? This particular version of ant colony optimization is called “Ant System”, and it’s the first version that Dorigo proposed, but there have since been many suggested improvements.</p>
<p>As far as this particular algorithm is concerned, there are lots of questions remaining:</p>
<ul>
<li>
<p class="has-jax"> What are good relative values of \(\alpha\), \(\beta\), \(F\), and \(k\)?</p>
</li>
<li>
<p>How many iterations should the algorithm run before we say “good enough”?</p>
</li>
<li>What if we were to run many colonies in parallel and choose the best solution that way? Since the solver doesn’t depend on any external state, this is an easy idea to investigate.</li>
</ul>
<h1 id="updates">Updates</h1>
<ul>
<li>
<p>13 October 2015: Thanks to <code class="highlighter-rouge">predef</code> on the <a href="https://www.reddit.com/r/scala/comments/3olg3w/ant_colony_optimization_in_scala/">Scala sub-reddit comments</a> for pointing out the dangers of <code class="highlighter-rouge">Map#mapValues</code>.</p>
</li>
<li>
<p>22 March 2016: Fixed an off-by-one error in the touring code.</p>
</li>
<li>
<p>4 October 2016: Thanks to <code class="highlighter-rouge">merraksh</code> on <a href="https://news.ycombinator.com/item?id=12633362">HN</a> for some helpful corrections.</p>
</li>
</ul>
<h1 id="footnotes">Footnotes</h1>
<div class="footnotes">
<ol>
<li id="fn:1">
<p><a href="https://en.wikipedia.org/wiki/Ant_colony_optimization_algorithms">Ant colony optimization on Wikipedia</a> <a href="#fnref:1" class="reversefootnote">↩</a></p>
</li>
<li id="fn:2">
<p>I <em>highly</em> recommend <a href="https://cs.gmu.edu/~sean/book/metaheuristics/">this</a> free book for a fantastic overview of heuristic optimization algorithms (including ant colony optimization). <a href="#fnref:2" class="reversefootnote">↩</a></p>
</li>
<li id="fn:3">
<p>ML-style (OCaml, SML) modules just make sense to me, and Scala does a reasonable job of encoding these patterns. Perhaps this will be the subject of another blog post. <a href="#fnref:3" class="reversefootnote">↩</a></p>
</li>
</ol>
</div>
Mon, 12 Oct 2015 00:00:00 +0000
http://blog.haberkucharsky.com/technology/2015/10/12/travelling-ants.html
http://blog.haberkucharsky.com/technology/2015/10/12/travelling-ants.htmltechnologyMore monads in OCaml<p>While popular in Haskell, monads can be encoded effectively in OCaml too. This post describes one such encoding, as well as the process of developing a modern OCaml program.</p>
<p>I assume that you know what monads are and why you should care about them. If this is not the case, then there are some excellent books <sup id="fnref:1"><a href="#fn:1" class="footnote">1</a></sup> out there.</p>
<h1 id="introduction">Introduction</h1>
<p>Haskell is famous for the integration of monads in its core language. Not only are functions like <code class="highlighter-rouge">>>=</code> supported syntactically through the <code class="highlighter-rouge">do</code> syntax <sup id="fnref:2"><a href="#fn:2" class="footnote">2</a></sup>, but monads are commonly used for program flow and used by necessity for managing and tracking effects. One of the reasons that it is so nice to use monads (and, for that matter, other abstractions like functors and monoids) in Haskell is its <em>type-classes</em>. Type-classes are a means of achieving so-called “ad-hoc polymorphism”: common interfaces that are shared between things that may share no other relation.</p>
<p>One example of a type-class defined in standard Haskell (the “Prelude”) is <code class="highlighter-rouge">Show</code>, which defines how to convert a value into a human-readable string. It makes sense that we would want to be able to <code class="highlighter-rouge">show</code> many different kinds of things. <code class="highlighter-rouge">Show</code> has the following definition (with an example instance for <code class="highlighter-rouge">Bool</code>):</p>
<script src="https://gist.github.com/hakuch/3f5ab49fedfdb02ea07d.js"></script>
<p>There are some important characteristics of type-classes:</p>
<ul>
<li>
<p>Type-class functions can be applied to any type for which an instance is defined in scope somewhere. For example, as long as the <code class="highlighter-rouge">Show Int</code> instance is in scope, <code class="highlighter-rouge">show 23</code> can be invoked without additional annotation.</p>
</li>
<li>
<p>There can only be a single global instance in scope of a type-class for a particular type. This means that, for instance, that without language extensions, <code class="highlighter-rouge">Show String</code> cannot be defined differently than <code class="highlighter-rouge">Show a => Show [a]</code> since <code class="highlighter-rouge">String</code> is a type alias for <code class="highlighter-rouge">[Char]</code>.</p>
</li>
</ul>
<p>While Haskell popularized type-classes through its first-class support for the idiom, it’s absolutely possible to encode these concepts in other programming languages.</p>
<h1 id="enter-ocaml">Enter OCaml</h1>
<p>I’m getting interested in OCaml again. It was actually the first functional programming language I learned back in 2007 or so (shortly afterwards, I learned Haskell), and there are several recent developments in the language and the ecosystem:</p>
<ul>
<li>The <a href="http://opam.ocamlpro.com/">opam</a> package manager makes it easier than ever to install OCaml and its libraries on your system, including seamless switching between versions.</li>
<li>The freely-available online <a href="https://realworldocaml.org/">“Real World OCaml”</a> book is very well-written and accessible.</li>
<li>The <a href="https://mirage.io/">MirageOS</a> project for building so-called “unikernels” in OCaml: programs that are written in OCaml and that run on “bare metal” on the Xen hypervisor.</li>
<li>There are rumors that OCaml will soon be multi-core ready. Currently, threads are multiplexed on a single CPU core.</li>
<li>I hear that the new optimization engine, <code class="highlighter-rouge">flambda</code>, will be merged soon. It performs whole-program optimization a la MLton and apparently significantly improves performance.</li>
</ul>
<p>I won’t attempt to make the case of OCaml versus Haskell, but it is worth noting OCaml is strict by default with strong support for lazy evaluation (unlike Haskell, in which the opposite is true).</p>
<p>Another aspect of OCaml that I find extremely compelling is its strong support for modular design through interfaces and its support for functors: modules that are functions of other modules. I was curious about how monads could be encoded in this system, and in particular, if monads in OCaml were viable for everyday use.</p>
<h1 id="running-these-examples">Running these examples</h1>
<p>I’m going to briefly outline how to get set-up with OCaml since there are still not a tonne of resources out there:</p>
<ol>
<li>
<p><a href="http://opam.ocaml.org/doc/Install.html">Install opam</a>. Then set-up your environment via <code class="highlighter-rouge">opam init --comp=4.02.2</code> (where OCaml 4.02.2 is the latest version as of this writing).</p>
</li>
<li>
<p>Install the utop interactive top-level with <code class="highlighter-rouge">opam install utop</code>. This is a more modern replacement for the default top-level with readline key-bindings and autocompletion. I’m not a huge fan of the curses “bling”, but it does the job.</p>
</li>
<li>
<p>(Optional) Install tools for developing OCaml programs: <code class="highlighter-rouge">opam install merlin ocp-index ocp-indent</code>. These tools (with the corresponding configuration in Emacs or Vim) make it possible to automatically indent OCaml code, jump to definitions, and dynamically inspect the types of values.</p>
</li>
</ol>
<p>You can also find all of the OCaml source code in this post at the corresponding
<a href="https://github.com/hakuch/OCamlMonads">GitHub repository</a>.</p>
<h1 id="starting-with-a-functor">Starting with a functor</h1>
<p>One of the most simple higher-order structures in Haskell is the functor (this unfortunately shares a name with the language construct in OCaml). A functor is a structure that we can map over.</p>
<script src="https://gist.github.com/hakuch/742f0b424648296e0379.js"></script>
<p>Note the file name of the snippet: in OCaml, the name of the file dictates the name of the module to which the contents belong. Therefore, we have just defined the <code class="highlighter-rouge">Functor_class</code> module, which consists of a module signature called <code class="highlighter-rouge">Functor_class.S</code>.</p>
<p>We can play with this definition with utop:</p>
<script src="https://gist.github.com/hakuch/48f0ffae413b7bd29b4d.js"></script>
<p>(Note the <code class="highlighter-rouge">#mod_use</code> directive. This loads the file by wrapping it in a module just like the OCaml compiler would. If we had typed <code class="highlighter-rouge">#use</code> instead, the definitions would be available as if we were inside the module at the top-level.)</p>
<p>Let’s look at a simple functor instance:</p>
<script src="https://gist.github.com/hakuch/0a688c9dceada8a24e00.js"></script>
<p>and how it could be used:</p>
<script src="https://gist.github.com/hakuch/a755236e3c6430db9532.js"></script>
<h1 id="monads-and-ocaml-functors">Monads and OCaml functors</h1>
<p>With the definition of functors in mind, look at the following definition of a monad structure:</p>
<script src="https://gist.github.com/hakuch/166342ee0d2000803271.js"></script>
<p>In Haskell, type-classes can be defined in terms of a minimal set of functions that can be used to implement the other functions. In the case of the monad definition, a number of a functions are usually expressed in terms of two functions: <code class="highlighter-rouge">>>=</code> and <code class="highlighter-rouge">return</code>.</p>
<p>OCaml doesn’t have the notion of partially-implemented signatures in modules: either all values are abstract (module signatures) or all are concrete (modules). Thus, to mirror this notion of functions being defined in terms of others, we use a OCaml functor to “extend” the basic type-class functions of <code class="highlighter-rouge">pure</code> and <code class="highlighter-rouge">bind</code> into the rest of the monad functions. There are some more details of this technique in the <a href="https://realworldocaml.org/v1/en/html/functors.html">functors chapter</a> of “Real World OCaml”.</p>
<h1 id="expressing-relationships-between-higher-order-structures">Expressing relationships between higher-order structures</h1>
<p>Any monad instance is a functor instance “for free”. We can express this idea in the revised definition of the functor class:</p>
<script src="https://gist.github.com/hakuch/d838b509b736eb24d235.js"></script>
<p>We’ve expressed that given any monad instance, we can obtain a functor instance by implementing <code class="highlighter-rouge">map</code> in terms of <code class="highlighter-rouge">bind</code> and <code class="highlighter-rouge">pure</code>.</p>
<h1 id="looking-at-the-option-monad">Looking at the <code class="highlighter-rouge">option</code> monad</h1>
<p>The <code class="highlighter-rouge">Maybe</code> monad instance in Haskell is (in my opinion) the easiest to understand. Let’s see how it can be expressed in OCaml. Since types are lowercase in OCaml, we can create <code class="highlighter-rouge">option.ml</code> (yielding an <code class="highlighter-rouge">Option</code> module) for our definitions without any conflict with the language:</p>
<script src="https://gist.github.com/hakuch/c5164e6a0fd29a2f8689.js"></script>
<p>Let’s compile this module (along with its dependent modules) to see how it works using the ocamlbuild tool:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ocamlbuild option.cmo
</code></pre></div></div>
<p>Ocamlbuild creates compiled objects into the <code class="highlighter-rouge">_build</code> directory, so we should start-up utop with an amended include path: <code class="highlighter-rouge">utop -I _build</code>. Inside utop, we use the <code class="highlighter-rouge">#load_rec</code> directive to load the <code class="highlighter-rouge">Option</code> implementation and any modules that it depends on. We can use the <code class="highlighter-rouge">#show</code> directive to view a module’s signature from within the top-level, too.</p>
<script src="https://gist.github.com/hakuch/c6ec221e26b628bc467b.js"></script>
<h1 id="monads-with-multiple-type-parameters-state">Monads with multiple type parameters: state</h1>
<p>Some monads, like Haskell’s <code class="highlighter-rouge">Maybe</code> monad and <code class="highlighter-rouge">IO</code> monad, have only a single type parameter. However, many have more than one. It’s not immediately clear how to encode this into OCaml’s type system.</p>
<p>One solution is to use another functor. Let’s see how this works in an implementation in OCaml of the <code class="highlighter-rouge">State</code> monad in Haskell. In this case, the state type is an any module that defines a <code class="highlighter-rouge">type t</code>, and our module is parameterized on this state:</p>
<script src="https://gist.github.com/hakuch/91efa96990042acdde34.js"></script>
<p>As an example, consider an example directly from “Functional Programming in Scala”: implementing a simple candy dispenser state machine. First, we’ll show the interface (which doesn’t reveal any state-monad implementation):</p>
<script src="https://gist.github.com/hakuch/64d3992469820eb007a5.js"></script>
<p>and then the implementation, using our state monad parameterized over <code class="highlighter-rouge">Machine_state</code>:</p>
<script src="https://gist.github.com/hakuch/e58840e59e74dc190bcf.js"></script>
<p>As a quick example of the candy dispenser:</p>
<script src="https://gist.github.com/hakuch/484ea9c4e4baaf7b3ab6.js"></script>
<p>You can compile this example with <code class="highlighter-rouge">ocamlbuild main.native</code> which will produce an executable <code class="highlighter-rouge">main.native</code>.</p>
<h1 id="conclusions-and-next-steps">Conclusions and next steps</h1>
<p>It is undeniably more syntactically messy to define these structures in OCaml over Haskell. Nonetheless, I think it’s compelling that OCaml’s module system, which is so useful for structuring programs with interfaces, can define such high-level abstractions without breaking a sweat.</p>
<p>In a paradoxical way, I actually find that sometimes implementing these and other structures in OCaml (and similarly, sometimes Scala) offers more educational insight into how they all work, since there’s less magic with laziness and instances have to be brought directly into scope. I suspect it also makes readability clearer for heavily monadic code. A block that begins with</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>let open Option.Monad in
</code></pre></div></div>
<p>makes it abundantly clear that the monadic operations that follow are in the context of the option monad.</p>
<p>I’d like to fiddle in the future with monad transformers in OCaml, and maybe try writing a larger OCaml program that actually makes use of monads internally.</p>
<h2 id="implicits">Implicits</h2>
<p>What’s very interesting is that there is a branch of OCaml that supports a sort-of hybrid of the existing module system and Haskell’s type-classes called implicit modules. This language construct is virtually identical to Scala’s <code class="highlighter-rouge">implicit</code> mechanism, and more details can be found <a href="http://www.lpw25.net/ml2014.pdf">here</a>. The paper has lots of nifty examples.</p>
<h1 id="other-references">Other references</h1>
<ul>
<li><a href="http://blog.enfranchisedmind.com/2007/08/a-monad-tutorial-for-ocaml/">“A monad tutorial for OCaml”</a></li>
<li><a href="https://existentialtype.wordpress.com/2011/05/01/of-course-ml-has-monads/">“Of course ML has monads!”</a></li>
</ul>
<h1 id="updates">Updates</h1>
<ul>
<li>26 February 2017: Removed unnecessary laziness from the definition of the monad signature.</li>
</ul>
<h1 id="footnotes">Footnotes</h1>
<div class="footnotes">
<ol>
<li id="fn:1">
<p>I highly recommend <a href="http://learnyouahaskell.com/">“Learn you a Haskell for Great Good”</a> and <a href="http://www.manning.com/bjarnason/">“Functional Programming in Scala”</a>. <a href="#fnref:1" class="reversefootnote">↩</a></p>
</li>
<li id="fn:2">
<p>For an example, see <script src="https://gist.github.com/hakuch/d61fb9485c8189ef05e3.js"></script> <a href="#fnref:2" class="reversefootnote">↩</a></p>
</li>
</ol>
</div>
Tue, 21 Jul 2015 00:00:00 +0000
http://blog.haberkucharsky.com/technology/2015/07/21/more-monads-in-ocaml.html
http://blog.haberkucharsky.com/technology/2015/07/21/more-monads-in-ocaml.htmltechnology