Jekyll2021-09-16T20:54:15+02:00https://kleczkow.ski/feed.xmlkleczkow.skiHello, I'm Haskell Developer based in Warsaw. I'm functional programming enthusiast.Konrad Kleczkowskikonrad@kleczkow.skiCayley Representation of… Monads?2021-09-09T17:20:00+02:002021-09-09T17:20:00+02:00https://kleczkow.ski/cayley-representation-of-monads<p>In Haskell we’re using monoids intensively - monoid is an algebraic structure
that has associative binary operation with neutral element.</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="kr">class</span> <span class="kt">Monoid</span> <span class="n">a</span> <span class="kr">where</span>
<span class="n">mempty</span> <span class="o">::</span> <span class="n">a</span>
<span class="n">mappend</span> <span class="o">::</span> <span class="n">a</span> <span class="o">-></span> <span class="n">a</span> <span class="o">-></span> <span class="n">a</span>
</code></pre></div></div>
<p>For instance,
we have lists that form monoid under list concatenation and empty list
as neutral element.</p>
<h2 id="short-tale-about-lists">Short Tale About Lists</h2>
<p>You’re a programmer in some software house that creates embeddable software
for intelligent wash machines — in Haskell. Your task is to create
<code class="language-plaintext highlighter-rouge">reverse</code> function that reverses the list, for example:</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="n">reverse</span> <span class="kt">[]</span> <span class="o">=</span> <span class="kt">[]</span>
<span class="n">reverse</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span>
<span class="n">reverse</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">]</span>
</code></pre></div></div>
<p>If you know Haskell in essential extent, you just write function like this:</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="n">reverse</span> <span class="o">::</span> <span class="p">[</span><span class="n">a</span><span class="p">]</span> <span class="o">-></span> <span class="p">[</span><span class="n">a</span><span class="p">]</span>
<span class="n">reverse</span> <span class="kt">[]</span> <span class="o">=</span> <span class="kt">[]</span>
<span class="n">reverse</span> <span class="p">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">as</span><span class="p">)</span> <span class="o">=</span> <span class="n">reverse</span> <span class="n">as</span> <span class="o">++</span> <span class="p">[</span><span class="n">a</span><span class="p">]</span>
</code></pre></div></div>
<p>You committed the code and you’re using it every day in your software, but
there is a problem. Your function is pretty slow on long lists.</p>
<p>Why? Let’s look at list concatenation.</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="p">(</span><span class="o">++</span><span class="p">)</span> <span class="o">::</span> <span class="p">[</span><span class="n">a</span><span class="p">]</span> <span class="o">-></span> <span class="p">[</span><span class="n">a</span><span class="p">]</span> <span class="o">-></span> <span class="p">[</span><span class="n">a</span><span class="p">]</span>
<span class="kt">[]</span> <span class="o">++</span> <span class="n">bs</span> <span class="o">=</span> <span class="n">bs</span>
<span class="p">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">as</span><span class="p">)</span> <span class="o">++</span> <span class="n">bs</span> <span class="o">=</span> <span class="n">a</span> <span class="o">:</span> <span class="p">(</span><span class="n">as</span> <span class="o">++</span> <span class="n">bs</span><span class="p">)</span>
</code></pre></div></div>
<p>Calling reverse on <code class="language-plaintext highlighter-rouge">[1, 2, 3, 4, 5]</code> will create following thunk:</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="n">reverse</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">]</span>
<span class="o">=</span> <span class="n">reverse</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">]</span> <span class="o">++</span> <span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="o">=</span> <span class="p">(</span><span class="n">reverse</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">]</span> <span class="o">++</span> <span class="p">[</span><span class="mi">2</span><span class="p">])</span> <span class="o">++</span> <span class="p">[</span><span class="mi">3</span><span class="p">]</span>
<span class="o">=</span> <span class="p">((</span><span class="n">reverse</span> <span class="p">[</span><span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">]</span> <span class="o">++</span> <span class="p">[</span><span class="mi">3</span><span class="p">])</span> <span class="o">++</span> <span class="p">[</span><span class="mi">2</span><span class="p">])</span> <span class="o">++</span> <span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="o">=</span> <span class="o">...</span>
<span class="o">=</span> <span class="p">((((</span><span class="kt">[]</span> <span class="o">++</span> <span class="p">[</span><span class="mi">5</span><span class="p">])</span> <span class="o">++</span> <span class="p">[</span><span class="mi">4</span><span class="p">])</span> <span class="o">++</span> <span class="p">[</span><span class="mi">3</span><span class="p">])</span> <span class="o">++</span> <span class="p">[</span><span class="mi">2</span><span class="p">])</span> <span class="o">++</span> <span class="p">[</span><span class="mi">1</span><span class="p">]</span>
</code></pre></div></div>
<p>Each call of <code class="language-plaintext highlighter-rouge">(++)</code> at <code class="language-plaintext highlighter-rouge">n</code>-th number takes <code class="language-plaintext highlighter-rouge">5 - n + 1</code> steps to
concatenate <code class="language-plaintext highlighter-rouge">[n]</code> list. So <code class="language-plaintext highlighter-rouge">reverse</code> is <code class="language-plaintext highlighter-rouge">O(n^2)</code>. Not good.</p>
<p>What if we can encode each action as a function that operates on list?
We call these function as differential list, because we encode only changes in list
rather than all content in one place.</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="kr">type</span> <span class="kt">DList</span> <span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="n">a</span><span class="p">]</span> <span class="o">-></span> <span class="p">[</span><span class="n">a</span><span class="p">]</span>
<span class="n">empty</span> <span class="o">::</span> <span class="kt">DList</span> <span class="n">a</span>
<span class="n">empty</span> <span class="o">=</span> <span class="n">id</span>
<span class="n">singleton</span> <span class="o">::</span> <span class="n">a</span> <span class="o">-></span> <span class="kt">DList</span> <span class="n">a</span>
<span class="n">singleton</span> <span class="n">a</span> <span class="o">=</span> <span class="p">(</span><span class="n">a</span> <span class="o">:</span><span class="p">)</span>
<span class="n">concat</span> <span class="o">::</span> <span class="kt">DList</span> <span class="n">a</span> <span class="o">-></span> <span class="kt">DList</span> <span class="n">a</span> <span class="o">-></span> <span class="kt">DList</span> <span class="n">a</span>
<span class="n">concat</span> <span class="n">f</span> <span class="n">g</span> <span class="o">=</span> <span class="n">f</span> <span class="o">.</span> <span class="n">g</span>
<span class="n">toList</span> <span class="o">::</span> <span class="kt">DList</span> <span class="n">a</span> <span class="o">-></span> <span class="n">a</span>
<span class="n">toList</span> <span class="n">f</span> <span class="o">=</span> <span class="n">f</span> <span class="kt">[]</span>
</code></pre></div></div>
<p>Now we can implement <code class="language-plaintext highlighter-rouge">reverse</code> using <code class="language-plaintext highlighter-rouge">DList</code>.</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="n">reverse</span> <span class="o">::</span> <span class="p">[</span><span class="n">a</span><span class="p">]</span> <span class="o">-></span> <span class="p">[</span><span class="n">a</span><span class="p">]</span>
<span class="n">reverse</span> <span class="o">=</span> <span class="n">toList</span> <span class="o">.</span> <span class="n">go</span>
<span class="kr">where</span>
<span class="n">go</span> <span class="o">::</span> <span class="p">[</span><span class="n">a</span><span class="p">]</span> <span class="o">-></span> <span class="kt">DList</span> <span class="n">a</span>
<span class="n">go</span> <span class="kt">[]</span> <span class="o">=</span> <span class="n">empty</span>
<span class="n">go</span> <span class="p">(</span><span class="n">a</span> <span class="o">:</span> <span class="n">as</span><span class="p">)</span> <span class="o">=</span> <span class="n">go</span> <span class="n">as</span> <span class="p">`</span><span class="n">concat</span><span class="p">`</span> <span class="n">singleton</span> <span class="n">a</span>
</code></pre></div></div>
<p>We replaced <code class="language-plaintext highlighter-rouge">(++)</code> with basically <code class="language-plaintext highlighter-rouge">(.)</code> so concatenation time
(with left associativity) is constant in comparison to lists’ lengths.
This brings significant runtime improvement that we wanted to achieve.</p>
<p><code class="language-plaintext highlighter-rouge">DList</code> is Cayley representation of list monoid. What does that mean?
Cayley’s theorem says that every monoid <code class="language-plaintext highlighter-rouge">M</code> is isomorphic to the submonoid of automorphisms <code class="language-plaintext highlighter-rouge">M -> M</code>.</p>
<p>For sure <code class="language-plaintext highlighter-rouge">DList</code> fits in the Cayley’s theorem.</p>
<p>The moral of this story is that sometimes operation of “original” monoid
can be not effective enough, so we can switch to the Cayley representation
that is more preformant. Also you can notice that during building complex object
using Cayley’s representation we can’t “peek” our object during building process.
So this is kind of trade-off using this technique.</p>
<h2 id="cayley-for-monads">Cayley for Monads</h2>
<p>Now we can see that Cayley’s theorem not only applies for classic monoids. We can
consider, of course, monads, because monad is a monoid in category of endofunctors
under functor composition.</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="kr">class</span> <span class="kt">Functor</span> <span class="n">m</span> <span class="o">=></span> <span class="kt">Monad</span> <span class="n">m</span> <span class="kr">where</span>
<span class="n">return</span> <span class="o">::</span> <span class="n">a</span> <span class="o">-></span> <span class="n">m</span> <span class="n">a</span>
<span class="p">(</span><span class="o">>>=</span><span class="p">)</span> <span class="o">::</span> <span class="n">m</span> <span class="n">a</span> <span class="o">-></span> <span class="p">(</span><span class="n">a</span> <span class="o">-></span> <span class="n">m</span> <span class="n">b</span><span class="p">)</span> <span class="o">-></span> <span class="n">m</span> <span class="n">b</span>
</code></pre></div></div>
<p>But this is not easy task since this category notably differs from <code class="language-plaintext highlighter-rouge">Hask</code> category.
This category is called <code class="language-plaintext highlighter-rouge">[Hask, Hask]</code>. Our goal will be deriving the exponential object
(every exponential in <code class="language-plaintext highlighter-rouge">Hask</code> is a function). Then having monad <code class="language-plaintext highlighter-rouge">M</code> we’ll use <code class="language-plaintext highlighter-rouge">M^M</code> as
Cayley’s representation of monad <code class="language-plaintext highlighter-rouge">M</code>.</p>
<p>We know that every function can be curried and uncurried, this forms one of famous adjunctions,
that can be described as <code class="language-plaintext highlighter-rouge">Hom(a * b, c) ~= Hom(a, c^b)</code>.</p>
<p>Also we know that every <code class="language-plaintext highlighter-rouge">Hask</code> functor can be represented using Yoneda lemma, that is,
functor instance <code class="language-plaintext highlighter-rouge">FA</code> is isomorphic to the natural transformation from functor
<code class="language-plaintext highlighter-rouge">Hask(A, -)</code> to functor <code class="language-plaintext highlighter-rouge">F</code>.</p>
<p>Now we can connect these two facts to derive functor <code class="language-plaintext highlighter-rouge">M^N A</code>.</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">
</span><span class="gp">M^N A ~= Nat(Hask(A, -), M^N) #</span><span class="w"> </span>by Yoneda lemma
<span class="gp"> ~= Nat(Hask(A, -) `o` N, M) #</span><span class="w"> </span>by <span class="s2">"curry"</span> adjunction, <span class="sb">`</span>o<span class="sb">`</span> means composition
<span class="go">
</span></code></pre></div></div>
<p>So using this we can define <code class="language-plaintext highlighter-rouge">Exp</code> data type:</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="kr">newtype</span> <span class="kt">Exp</span> <span class="n">m</span> <span class="n">n</span> <span class="n">a</span> <span class="o">=</span> <span class="kt">Exp</span> <span class="p">{</span> <span class="n">appExp</span> <span class="o">::</span> <span class="n">forall</span> <span class="n">r</span><span class="o">.</span> <span class="p">(</span><span class="n">a</span> <span class="o">-></span> <span class="n">n</span> <span class="n">r</span><span class="p">)</span> <span class="o">-></span> <span class="n">m</span> <span class="n">r</span> <span class="p">}</span>
</code></pre></div></div>
<p>(Natural transformations are <code class="language-plaintext highlighter-rouge">type f ~> g = forall r. f r -> g r</code> in Haskell).</p>
<p>A functor <code class="language-plaintext highlighter-rouge">M^M</code> is a codensity monad, widely used with free monads.
Since free monads are just like lists in runtime, but more restrictive
by design, using Cayley’s representation on it can improve time spent on creating a list of actions of this free monad. This concludes the article.</p>Konrad Kleczkowskikonrad@kleczkow.skiIn Haskell we’re using monoids intensively - monoid is an algebraic structure that has associative binary operation with neutral element.Brief introduction to Conway Game of Life with Comonads2021-04-29T22:00:00+02:002021-04-29T22:00:00+02:00https://kleczkow.ski/conway-aol-with-comonads<p>In this article we take a look at Conway’s Game of Life as a good example for
comonad usage. We will go step-by-step through basic concepts finally presenting
an example of Conway’s Game of Life implementation.</p>
<h2 id="background">Background</h2>
<p>Functor is a polymorphic type that is able to wrap values in it. These values can
be mapped over using some function. This function is often called <code class="language-plaintext highlighter-rouge">map</code> or <code class="language-plaintext highlighter-rouge">fmap</code>, depending
on language’s convention. In Haskell, this kind of type belongs to <code class="language-plaintext highlighter-rouge">Functor</code> type class.</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">class</span> <span class="kt">Functor</span> <span class="n">f</span> <span class="kr">where</span>
<span class="n">fmap</span> <span class="o">::</span> <span class="p">(</span><span class="n">a</span> <span class="o">-></span> <span class="n">b</span><span class="p">)</span> <span class="o">-></span> <span class="n">f</span> <span class="n">a</span> <span class="o">-></span> <span class="n">f</span> <span class="n">b</span>
</code></pre></div></div>
<p>The simplest example you have probably dealt with is a list. List of values can be simply
mapped over by iterating over them, applying function to it and packing them back
to the list (to immutable copy or modifying existing list).</p>
<p>Also well known case is
<code class="language-plaintext highlighter-rouge">Maybe</code> functor.
It allows to do null-safe computations
without tedious checking of null references with control flow statements. Also
there is richer functor called <code class="language-plaintext highlighter-rouge">Either</code> that allows to return a failure with
error details attached (<code class="language-plaintext highlighter-rouge">Left</code>) or can wrap a value coming from successful computation (<code class="language-plaintext highlighter-rouge">Right</code>).</p>
<p>We can say that functor gives value (or values) a <em>context</em> that attaches
specific behavior to it.</p>
<!-- ### Monad
Very briefly, monad is a model of computation that is equipped with a functor `m`
and functions:
* `return :: a -> m a` that allows to inject bare value into the context;
* `bind :: (a -> m b) -> m a -> m b` that allows to run an action on wrapped value.
What does it mean to us in simple words?
`return` function is
easy one, it just injects a value into the functor. For example,
in Haskell `return` function for `Maybe` can look like this:
```haskell
return :: a -> Maybe a
return a = Just a
```
It just takes the value and wraps it around `Maybe` using `Just` constructor.
Similarly we can write it for `Either` functor:
```haskell
return :: a -> Either e a
return a = Right a
```
`bind` function (called also as `flatMap` in other languages) allows to
map context-aware value (`m a`) with function (`a -> m b`) that
returns a new context for it (`m b`). This allows to transform
our context-aware values in sequentional manner. That's way we have
`for`-comprehensions in Scala or `do`-notation in Haskell and they are
using `bind` function to preform pure sequentional interface for computations.
In addition, we have function `join :: m (m a) -> m a` that brings functor layers
into one and it can be implemented using `bind` by saying `join = bind id`.
It is sometimes useful but it will be important in the next section. -->
<h3 id="comonads">Comonads</h3>
<p>Comonads, as name suggests, is a monad, but in an opposite category.
By definition, if we have function <code class="language-plaintext highlighter-rouge">a -> b</code>, then in opposite category it would be
<code class="language-plaintext highlighter-rouge">b -> a</code>. So, let’s rephrase <code class="language-plaintext highlighter-rouge">Monad</code> type class into <code class="language-plaintext highlighter-rouge">Comonad</code> type class using
this play:</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">class</span> <span class="kt">Functor</span> <span class="n">m</span> <span class="o">=></span> <span class="kt">Monad</span> <span class="n">m</span> <span class="kr">where</span>
<span class="n">return</span> <span class="o">::</span> <span class="n">a</span> <span class="o">-></span> <span class="n">m</span> <span class="n">a</span>
<span class="n">join</span> <span class="o">::</span> <span class="n">m</span> <span class="p">(</span><span class="n">m</span> <span class="n">a</span><span class="p">)</span> <span class="o">-></span> <span class="n">m</span> <span class="n">a</span>
<span class="n">bind</span> <span class="o">::</span> <span class="p">(</span><span class="n">a</span> <span class="o">-></span> <span class="n">m</span> <span class="n">b</span><span class="p">)</span> <span class="o">-></span> <span class="n">m</span> <span class="n">a</span> <span class="o">-></span> <span class="n">m</span> <span class="n">b</span>
<span class="kr">class</span> <span class="kt">Functor</span> <span class="n">w</span> <span class="o">=></span> <span class="kt">Comonad</span> <span class="n">w</span> <span class="kr">where</span>
<span class="n">coreturn</span> <span class="o">::</span> <span class="n">w</span> <span class="n">a</span> <span class="o">-></span> <span class="n">a</span>
<span class="n">cojoin</span> <span class="o">::</span> <span class="n">w</span> <span class="n">a</span> <span class="o">-></span> <span class="n">w</span> <span class="p">(</span><span class="n">w</span> <span class="n">a</span><span class="p">)</span>
<span class="n">cobind</span> <span class="o">::</span> <span class="p">(</span><span class="n">w</span> <span class="n">a</span> <span class="o">-></span> <span class="n">b</span><span class="p">)</span> <span class="o">-></span> <span class="n">w</span> <span class="n">a</span> <span class="o">-></span> <span class="n">w</span> <span class="n">b</span>
</code></pre></div></div>
<p>Comonads can be thought as a universe of values that has one distinguished point.
To get that point we can call <code class="language-plaintext highlighter-rouge">coreturn</code>.</p>
<p><code class="language-plaintext highlighter-rouge">cobind</code> corresponds to <code class="language-plaintext highlighter-rouge">bind</code> function and it works like this.
<code class="language-plaintext highlighter-rouge">cobind</code> takes the universe and for each point creates an instance
of comonad that looks at this point. Then <code class="language-plaintext highlighter-rouge">cobind</code> calls function of type <code class="language-plaintext highlighter-rouge">w a -> b</code>
on these copies, resulting a new universe that is made of <code class="language-plaintext highlighter-rouge">b</code>-s.
<code class="language-plaintext highlighter-rouge">cojoin</code> does exactly same thing, but only provides these copies of universes.</p>
<p>You can see that you need implement <code class="language-plaintext highlighter-rouge">coreturn</code> and either <code class="language-plaintext highlighter-rouge">cobind</code> or <code class="language-plaintext highlighter-rouge">cojoin</code> to get the instance of <code class="language-plaintext highlighter-rouge">Comonad</code>.</p>
<p>For the rest of article we will call <code class="language-plaintext highlighter-rouge">coreturn</code> as <code class="language-plaintext highlighter-rouge">extract</code>, <code class="language-plaintext highlighter-rouge">cobind</code> as <code class="language-plaintext highlighter-rouge">extend</code> and
<code class="language-plaintext highlighter-rouge">cojoin</code> as <code class="language-plaintext highlighter-rouge">duplicate</code>.</p>
<h3 id="store-comonad"><code class="language-plaintext highlighter-rouge">Store</code> comonad</h3>
<p>So let consider a pair of values: an index of type <code class="language-plaintext highlighter-rouge">s</code>
and function <code class="language-plaintext highlighter-rouge">s -> a</code> that accesses early mentioned
universe of values of type <code class="language-plaintext highlighter-rouge">a</code>. This is <code class="language-plaintext highlighter-rouge">Store</code> comonad.</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">data</span> <span class="kt">Store</span> <span class="n">s</span> <span class="n">a</span> <span class="o">=</span> <span class="kt">Store</span> <span class="n">s</span> <span class="p">(</span><span class="n">s</span> <span class="o">-></span> <span class="n">a</span><span class="p">)</span>
</code></pre></div></div>
<p>Shall we implement <code class="language-plaintext highlighter-rouge">Comonad</code> type class? Let’s try implement <code class="language-plaintext highlighter-rouge">extract</code>.</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">extract</span> <span class="o">::</span> <span class="kt">Store</span> <span class="n">s</span> <span class="n">a</span> <span class="o">-></span> <span class="n">a</span>
<span class="n">extract</span> <span class="p">(</span><span class="kt">Store</span> <span class="n">idx</span> <span class="n">get</span><span class="p">)</span> <span class="o">=</span> <span class="n">get</span> <span class="n">idx</span>
<span class="n">duplicate</span> <span class="o">::</span> <span class="p">(</span><span class="kt">Store</span> <span class="n">s</span> <span class="n">a</span> <span class="o">-></span> <span class="n">b</span><span class="p">)</span> <span class="o">-></span> <span class="kt">Store</span> <span class="n">s</span> <span class="n">a</span> <span class="o">-></span> <span class="kt">Store</span> <span class="n">s</span> <span class="n">b</span>
<span class="n">duplicate</span> <span class="n">f</span> <span class="p">(</span><span class="kt">Store</span> <span class="n">idx</span> <span class="n">get</span><span class="p">)</span> <span class="o">=</span> <span class="kt">Store</span> <span class="n">idx</span> <span class="p">(</span><span class="nf">\</span><span class="n">i</span> <span class="o">-></span> <span class="n">f</span> <span class="p">(</span><span class="kt">Store</span> <span class="n">i</span> <span class="n">get</span><span class="p">))</span>
</code></pre></div></div>
<p>You can compare this implementation with the explanation of <code class="language-plaintext highlighter-rouge">extend</code> above.</p>
<h2 id="game-of-life-v-store">Game of Life v. <code class="language-plaintext highlighter-rouge">Store</code></h2>
<p>Game of Life, first of all, is a cellular automata. It has
an infinite discrete plane filled with two kind of cells — dead or alive.
Each cell in each step is transformed by provided rules, and these rules are:</p>
<ul>
<li>if current cell is dead and has three alive neighbours, then cell becomes alive;</li>
<li>if current cell is alive and has two or three alive neighbours, then cell still is alive;</li>
<li>otherwise cell becomes dead.</li>
</ul>
<p>We can start implementing this automaton by describing the board.</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">type</span> <span class="kt">Coord</span> <span class="o">=</span> <span class="p">(</span><span class="kt">Int</span><span class="p">,</span> <span class="kt">Int</span><span class="p">)</span>
<span class="kr">type</span> <span class="kt">CellPlane</span> <span class="n">a</span> <span class="o">=</span> <span class="kt">Store</span> <span class="kt">Coord</span> <span class="n">a</span>
<span class="kr">data</span> <span class="kt">Conway</span> <span class="o">=</span> <span class="kt">Dead</span> <span class="o">|</span> <span class="kt">Alive</span> <span class="kr">deriving</span> <span class="p">(</span><span class="kt">Eq</span><span class="p">)</span>
</code></pre></div></div>
<h3 id="game-of-life-is-an-experiment">Game Of Life is an <code class="language-plaintext highlighter-rouge">experiment</code>…</h3>
<p>We need to obtain the state of neighbouring cells around the focused cell. We can implement function
called <code class="language-plaintext highlighter-rouge">experiment</code> in this way:</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">experiment</span> <span class="o">::</span> <span class="kt">Functor</span> <span class="n">f</span> <span class="o">=></span> <span class="p">(</span><span class="n">s</span> <span class="o">-></span> <span class="n">f</span> <span class="n">s</span><span class="p">)</span> <span class="o">-></span> <span class="kt">Store</span> <span class="n">s</span> <span class="n">a</span> <span class="o">-></span> <span class="n">f</span> <span class="n">a</span>
<span class="n">experiment</span> <span class="n">f</span> <span class="p">(</span><span class="kt">Store</span> <span class="n">idx</span> <span class="n">get</span><span class="p">)</span> <span class="o">=</span> <span class="n">fmap</span> <span class="n">get</span> <span class="p">(</span><span class="n">f</span> <span class="n">idx</span><span class="p">)</span>
</code></pre></div></div>
<p>This function passes the current index into the function <code class="language-plaintext highlighter-rouge">s -> f s</code> resulting
with <code class="language-plaintext highlighter-rouge">f s</code>. Since <code class="language-plaintext highlighter-rouge">f</code> is a functor, we can map <code class="language-plaintext highlighter-rouge">f s</code> with <code class="language-plaintext highlighter-rouge">get</code>.</p>
<p>If we’ll consider a list as our functor <code class="language-plaintext highlighter-rouge">f</code>, this gives as a way to get neighbourhood.</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">neighboursOf</span> <span class="o">::</span> <span class="kt">Coord</span> <span class="o">-></span> <span class="p">[</span><span class="kt">Coord</span><span class="p">]</span>
<span class="n">neighboursOf</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> <span class="o">=</span> <span class="p">[</span> <span class="p">(</span><span class="n">x</span> <span class="o">+</span> <span class="n">d</span><span class="p">,</span> <span class="n">y</span> <span class="o">+</span> <span class="n">d'</span><span class="p">)</span> <span class="o">|</span> <span class="n">d</span> <span class="o"><-</span> <span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="o">..</span><span class="mi">1</span><span class="p">],</span> <span class="n">d'</span> <span class="o"><-</span> <span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="o">..</span><span class="mi">1</span><span class="p">],</span> <span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="n">d'</span><span class="p">)</span> <span class="o">/=</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="p">]</span>
<span class="n">neighbouringCells</span> <span class="o">::</span> <span class="kt">CellPlane</span> <span class="kt">Conway</span> <span class="o">-></span> <span class="p">[</span><span class="kt">Conway</span><span class="p">]</span>
<span class="n">neighbouringCells</span> <span class="o">=</span> <span class="n">experiment</span> <span class="n">neighboursOf</span>
</code></pre></div></div>
<h3 id="game-of-life-rules">Game Of Life <em>rules</em></h3>
<p>So now we can easily write the rules of Game Of Life.</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">golStep</span> <span class="o">::</span> <span class="kt">CellPlane</span> <span class="kt">Conway</span> <span class="o">-></span> <span class="kt">Conway</span>
<span class="n">golStep</span> <span class="n">p</span> <span class="o">=</span> <span class="kr">case</span> <span class="n">extract</span> <span class="n">p</span> <span class="kr">of</span>
<span class="kt">Dead</span> <span class="o">|</span> <span class="n">noOfNeighbours</span> <span class="o">==</span> <span class="mi">3</span> <span class="o">-></span> <span class="kt">Alive</span>
<span class="kt">Alive</span> <span class="o">|</span> <span class="n">noOfNeighbours</span> <span class="p">`</span><span class="n">elem</span><span class="p">`</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span> <span class="o">-></span> <span class="kt">Alive</span>
<span class="kr">_</span> <span class="o">-></span> <span class="kt">Dead</span>
<span class="kr">where</span>
<span class="c1">-- @noOfNeighbours@ = number of neighbouring cells that are alive</span>
<span class="n">noOfNeighbours</span> <span class="o">=</span> <span class="n">length</span> <span class="p">(</span><span class="n">filter</span> <span class="p">(</span><span class="o">==</span> <span class="kt">Alive</span><span class="p">)</span> <span class="p">(</span><span class="n">neighbouringCells</span> <span class="n">p</span><span class="p">))</span>
</code></pre></div></div>
<p>Now we need to embed an initial state (given by <code class="language-plaintext highlighter-rouge">Map Coord Conway</code>) into the comonad…</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">toCellPlane</span> <span class="o">::</span> <span class="kt">Map</span> <span class="kt">Coord</span> <span class="kt">Conway</span> <span class="o">-></span> <span class="kt">CellPlane</span> <span class="kt">Conway</span>
<span class="n">toCellPlane</span> <span class="n">cs</span> <span class="o">=</span> <span class="kt">State</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="n">access</span>
<span class="kr">where</span>
<span class="c1">-- If we are out of bounds we assume that cell is dead.</span>
<span class="n">access</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> <span class="o">=</span> <span class="n">fromMaybe</span> <span class="kt">Dead</span> <span class="p">(</span><span class="kt">Map</span><span class="o">.</span><span class="n">lookup</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> <span class="n">cs</span><span class="p">)</span>
</code></pre></div></div>
<p>…as well as we want to extract a finite view of the cell plane.</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">data</span> <span class="kt">Rect</span> <span class="o">=</span> <span class="kt">Rect</span> <span class="p">{</span> <span class="n">x</span> <span class="o">::</span> <span class="kt">Int</span>
<span class="p">,</span> <span class="n">y</span> <span class="o">::</span> <span class="kt">Int</span>
<span class="p">,</span> <span class="n">w</span> <span class="o">::</span> <span class="kt">Int</span>
<span class="p">,</span> <span class="n">h</span> <span class="o">::</span> <span class="kt">Int</span>
<span class="p">}</span>
<span class="n">fromCellPlane</span> <span class="o">::</span> <span class="kt">CellPlane</span> <span class="kt">Conway</span> <span class="o">-></span> <span class="kt">Rect</span> <span class="o">-></span> <span class="kt">Map</span> <span class="kt">Coord</span> <span class="kt">Conway</span>
<span class="n">fromCellPlane</span> <span class="n">p</span> <span class="p">(</span><span class="kt">Rect</span> <span class="n">x</span> <span class="n">y</span> <span class="n">w</span> <span class="n">h</span><span class="p">)</span> <span class="o">=</span> <span class="kt">Map</span><span class="o">.</span><span class="n">fromList</span> <span class="p">(</span><span class="n">coords</span> <span class="p">`</span><span class="n">zip</span><span class="p">`</span> <span class="n">experiment</span> <span class="p">(</span><span class="n">const</span> <span class="n">coords</span><span class="p">)</span> <span class="n">p</span><span class="p">)</span>
<span class="kr">where</span>
<span class="n">coords</span> <span class="o">=</span> <span class="p">[(</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">)</span> <span class="o">|</span> <span class="n">i</span> <span class="o"><-</span> <span class="p">[</span><span class="n">x</span> <span class="o">..</span> <span class="n">x</span> <span class="o">+</span> <span class="n">w</span> <span class="o">-</span> <span class="mi">1</span><span class="p">],</span> <span class="n">j</span> <span class="o"><-</span> <span class="p">[</span><span class="n">y</span> <span class="o">..</span> <span class="n">y</span> <span class="o">+</span> <span class="n">h</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]]</span>
</code></pre></div></div>
<p>Finally we can create an inifite list of evolutions using <code class="language-plaintext highlighter-rouge">iterate</code> function,
that repeatedly calls provided function to it (in our case it’s <code class="language-plaintext highlighter-rouge">extend golStep</code>):</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">evolutions</span> <span class="o">::</span> <span class="kt">CellPlane</span> <span class="kt">Conway</span> <span class="o">-></span> <span class="p">[</span><span class="kt">CellPlane</span> <span class="kt">Conway</span><span class="p">]</span>
<span class="n">evolutions</span> <span class="o">=</span> <span class="n">iterate</span> <span class="p">(</span><span class="n">extend</span> <span class="n">golStep</span><span class="p">)</span>
</code></pre></div></div>
<p>With these three functions — <code class="language-plaintext highlighter-rouge">from/toCellPlane</code> and <code class="language-plaintext highlighter-rouge">evolutions</code> — we can implement
a program that runs Game of Life.</p>
<h2 id="summary">Summary</h2>
<p>Undoubtly, this is an interesting way to describe various cellular automata, using ideas that comes
from category theory. Also comonads provides a way to generalise cellular automata to other spaces
than just infinite plane.</p>
<p>Only disadvantage of this solution is an exponential growth of running time, because at each <code class="language-plaintext highlighter-rouge">extend</code>ing the
state of the plane is computed from scratch and memoising these computations
could be useful. This can be easily achieved in
Haskell using <a href="https://hackage.haskell.org/package/MemoTrie">trie-based pure memoisers</a> or in Scala using a mutable <code class="language-plaintext highlighter-rouge">HashMap</code> to memoise partial results.</p>Konrad Kleczkowskikonrad@kleczkow.skiIn this article we take a look at Conway’s Game of Life as a good example for comonad usage. We will go step-by-step through basic concepts finally presenting an example of Conway’s Game of Life implementation.Actor Model in Haskell2020-09-30T16:40:00+02:002020-09-30T16:40:00+02:00https://kleczkow.ski/actor-model-in-haskell<p>We’ll take a look at very popular way to describe concurrent computations.
Actor model is mainly based on \(\pi\)-calculus, well known theoretical model
developed by R. Milner.</p>
<p>Main principle of this model is <em>everything is an actor</em>. So what could actor do?</p>
<ol>
<li>Actor can send message to other actor.</li>
<li>Actor can receive message from other actor.</li>
<li>Actor can designate next behaviour to be used for the next message it receives.</li>
<li>Actor can spawn finite number of actors. That is, actor model is hierarchical.</li>
</ol>
<p>In this short article we’ll focus on simple implementation of actor model in Haskell using
software transaction memory.</p>
<h2 id="what-does-an-actor-consist-of">What does an actor consist of?</h2>
<p>Each actor is basically a concurrent job that consist of message queue.
Actor pulls message from queue to do some action, especially to send or receive
other messages, spawn an actor or change his behaviour.</p>
<p>To implement this queue we can use software transaction memory to do this safely.
STM gives us a way of controlling memory using transactions.</p>
<p>Transaction principle says us if we execute multiple instructions using transaction
either none or each will be preformed to do a desirable efect (e.g. enqueuing multiple messages).
STM also ensures us that no one modifies target state, so there’s no possibility
to read corrupted state.</p>
<p>We’ll use <code class="language-plaintext highlighter-rouge">TQueue</code> from <code class="language-plaintext highlighter-rouge">stm</code> package to use it as data structure that allows to enqueue messages.</p>
<p>So we can start with our module preamble:</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">module</span> <span class="nn">Control.Concurrent.Actor</span>
<span class="p">(</span> <span class="kt">ActorRef</span> <span class="p">(</span><span class="nf">refId</span><span class="p">)</span>
<span class="p">,</span> <span class="kt">Behaviour</span> <span class="p">(</span><span class="o">..</span><span class="p">)</span>
<span class="p">,</span> <span class="nf">spawn</span>
<span class="p">,</span> <span class="nf">send</span>
<span class="p">)</span>
<span class="kr">where</span>
<span class="kr">import</span> <span class="nn">Control.Monad</span>
<span class="kr">import</span> <span class="nn">Control.Concurrent</span>
<span class="kr">import</span> <span class="nn">Control.Concurrent.STM</span>
</code></pre></div></div>
<p>Then we write a definition of actor reference.</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">data</span> <span class="kt">ActorRef</span> <span class="n">msg</span>
<span class="o">=</span> <span class="kt">ActorRef</span>
<span class="p">{</span> <span class="n">refId</span> <span class="o">::</span> <span class="kt">ThreadId</span>
<span class="p">,</span> <span class="n">refMbox</span> <span class="o">::</span> <span class="kt">TQueue</span> <span class="n">msg</span>
<span class="p">}</span> <span class="kr">deriving</span> <span class="p">(</span><span class="kt">Eq</span><span class="p">)</span>
</code></pre></div></div>
<h2 id="spawning-an-actor">Spawning an actor</h2>
<p>To spawn an actor we need to instantiate <code class="language-plaintext highlighter-rouge">TQueue</code> and create a new green thread
using <code class="language-plaintext highlighter-rouge">forkIO</code>. Also we need to think, how we can model changing behaviour of actor.</p>
<p>We assume that after receiving a message actor wants to designate a new (or the same)
closure that can handle new messages.</p>
<p>Consider this datatype:</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">newtype</span> <span class="kt">Behaviour</span> <span class="n">msg</span> <span class="o">=</span> <span class="kt">Behaviour</span> <span class="p">{</span> <span class="n">getBehaviour</span> <span class="o">::</span> <span class="n">msg</span> <span class="o">-></span> <span class="kt">IO</span> <span class="p">(</span><span class="kt">Behaviour</span> <span class="n">msg</span><span class="p">)</span> <span class="p">}</span>
</code></pre></div></div>
<p>So we can write a loop that can executes a sequence of generated <code class="language-plaintext highlighter-rouge">Behaviour</code>s
by executing <code class="language-plaintext highlighter-rouge">IO</code> actions.</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">spawn</span> <span class="o">::</span> <span class="kt">Behaviour</span> <span class="n">msg</span> <span class="o">-></span> <span class="kt">IO</span> <span class="p">(</span><span class="kt">ActorRef</span> <span class="n">msg</span><span class="p">)</span>
<span class="n">spawn</span> <span class="n">b0</span> <span class="o">=</span> <span class="kr">do</span>
<span class="n">mbox</span> <span class="o"><-</span> <span class="n">newTQueueIO</span>
<span class="kr">let</span> <span class="n">go</span> <span class="p">(</span><span class="kt">Behaviour</span> <span class="n">b</span><span class="p">)</span> <span class="o">=</span> <span class="n">void</span> <span class="o">$</span> <span class="kr">do</span>
<span class="n">msg</span> <span class="o"><-</span> <span class="n">atomically</span> <span class="p">(</span><span class="n">readTQueue</span> <span class="n">mbox</span><span class="p">)</span>
<span class="n">b</span> <span class="n">msg</span> <span class="o">>>=</span> <span class="n">go</span>
<span class="n">pid</span> <span class="o"><-</span> <span class="n">forkIO</span> <span class="p">(</span><span class="n">go</span> <span class="n">b0</span><span class="p">)</span>
<span class="n">pure</span> <span class="p">(</span><span class="kt">ActorRef</span> <span class="n">pid</span> <span class="n">mbox</span><span class="p">)</span>
</code></pre></div></div>
<h2 id="communication-with-actors">Communication with actors</h2>
<p>We implemented message receiving by switching behaviours. Now we want to do
sending routine that will allow to trigger other actors.</p>
<p>That is simple — we need to enqueue message into another mailbox.</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">send</span> <span class="o">::</span> <span class="kt">ActorRef</span> <span class="n">msg</span> <span class="o">-></span> <span class="n">msg</span> <span class="o">-></span> <span class="kt">IO</span> <span class="nb">()</span>
<span class="n">send</span> <span class="n">msg</span> <span class="n">recipent</span> <span class="o">=</span> <span class="n">atomically</span> <span class="p">(</span><span class="n">writeTQueue</span> <span class="p">(</span><span class="n">refMbox</span> <span class="n">recipent</span><span class="p">)</span> <span class="n">msg</span><span class="p">)</span>
</code></pre></div></div>
<h2 id="examples">Examples</h2>
<p>We can implement a file reader using actor model by defining his behaviour
and set of messages to communicate with him.</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">{-# LANGUAGE LambdaCases #-}</span>
<span class="kr">import</span> <span class="nn">Data.IORef</span>
<span class="kr">import</span> <span class="nn">System.IO</span>
<span class="kr">data</span> <span class="kt">FileReaderMsg</span>
<span class="o">=</span> <span class="kt">OpenFile</span> <span class="kt">FilePath</span>
<span class="o">|</span> <span class="kt">SendLine</span> <span class="p">(</span><span class="kt">ActorRef</span> <span class="kt">FileReaderMsg</span><span class="p">)</span>
<span class="o">|</span> <span class="kt">GotLine</span> <span class="kt">String</span>
<span class="o">|</span> <span class="kt">CloseFile</span>
<span class="kr">deriving</span> <span class="p">(</span><span class="kt">Eq</span><span class="p">,</span> <span class="kt">Show</span><span class="p">)</span>
<span class="n">fileReader</span> <span class="o">::</span> <span class="kt">Behaviour</span> <span class="kt">FileReaderMsg</span>
<span class="n">fileReader</span> <span class="o">=</span> <span class="n">whenClosed</span>
<span class="kr">where</span>
<span class="n">whenClosed</span> <span class="o">=</span> <span class="kt">Behaviour</span> <span class="o">$</span> <span class="nf">\</span><span class="kr">case</span>
<span class="kt">OpenFile</span> <span class="n">fp</span> <span class="o">-></span> <span class="kr">do</span>
<span class="n">h</span> <span class="o"><-</span> <span class="n">openFile</span> <span class="n">fp</span> <span class="kt">ReadMode</span>
<span class="n">pure</span> <span class="p">(</span><span class="n">whenOpened</span> <span class="n">h</span><span class="p">)</span>
<span class="kt">CloseFile</span> <span class="o">-></span> <span class="n">pure</span> <span class="n">whenClosed</span> <span class="c1">-- does nothing</span>
<span class="kr">_</span> <span class="o">-></span> <span class="n">error</span> <span class="s">"inappropiate state"</span>
<span class="n">whenOpened</span> <span class="n">h</span> <span class="o">=</span> <span class="kt">Behaviour</span> <span class="o">$</span> <span class="nf">\</span><span class="kr">case</span>
<span class="kt">SendLine</span> <span class="n">replyTo</span> <span class="o">-></span> <span class="kr">do</span>
<span class="n">line</span> <span class="o"><-</span> <span class="n">hGetLine</span> <span class="n">h</span>
<span class="n">replyTo</span> <span class="p">`</span><span class="n">send</span><span class="p">`</span> <span class="kt">GotLine</span> <span class="n">line</span>
<span class="n">pure</span> <span class="p">(</span><span class="n">whenOpened</span> <span class="n">h</span><span class="p">)</span>
<span class="kt">CloseFile</span> <span class="o">-></span> <span class="kr">do</span>
<span class="n">hClose</span> <span class="n">h</span>
<span class="n">pure</span> <span class="n">whenClosed</span>
<span class="kr">_</span> <span class="o">-></span> <span class="n">error</span> <span class="s">"inappropiate state"</span>
</code></pre></div></div>
<p>Then we can use <code class="language-plaintext highlighter-rouge">spawn</code> to get the instance of actor pointed by <code class="language-plaintext highlighter-rouge">ActorRef</code>.</p>
<h1 id="summary">Summary</h1>
<p>This model is very popular among other programming languages such as Scala or C#, because it allows to decouple
all system parts using transparent way to communicate between them.</p>
<p>As usual, with Haskell we can get simple ideas working with simple implementations. Of course, this is only
the taste how actor-based models could look like. The way to improve this implementation is tightening <code class="language-plaintext highlighter-rouge">Behaviour</code>
type to eliminate or mitigate <em>partialness</em> of behaviours.</p>Konrad Kleczkowskikonrad@kleczkow.skiWe’ll take a look at very popular way to describe concurrent computations. Actor model is mainly based on \(\pi\)-calculus, well known theoretical model developed by R. Milner.