<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="http://cloudmark.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="http://cloudmark.github.io/" rel="alternate" type="text/html" /><updated>2026-04-03T20:40:07+00:00</updated><id>http://cloudmark.github.io/feed.xml</id><title type="html">Mark Galea</title><subtitle>stay safe, keep hacking! - cloudmark</subtitle><author><name>Mark Galea</name></author><entry><title type="html">Cats-Actors 2.1.0 Goes Cross-Platform</title><link href="http://cloudmark.github.io/Cats-Actors-Native-And-JS/" rel="alternate" type="text/html" title="Cats-Actors 2.1.0 Goes Cross-Platform" /><published>2026-04-03T00:00:00+00:00</published><updated>2026-04-03T00:00:00+00:00</updated><id>http://cloudmark.github.io/Cats-Actors-Native-And-JS</id><content type="html" xml:base="http://cloudmark.github.io/Cats-Actors-Native-And-JS/"><![CDATA[<p><img class="title" src="/images/cats-actors/logo-small.png" />
Imagine writing your actor logic once (typed messages, functional state, the <code class="language-plaintext highlighter-rouge">!</code> operator, supervision and all) and then deciding on a whim whether it runs as a JVM service, a self-contained native binary, or a live interactive app in your browser. No rewrites, no ports, no platform-specific glue. Just one codebase. Cats-Actors can do that now, and in this post we are going to have some fun with it. We will throw a token around a ring of actors on both JVM and Scala Native, and then (because why not) we will drop eight monkey actors into a banana-throwing arena right here inside this page. Real actors. Real messages. Running in your browser.</p>

<h2 id="setting-up-your-project">Setting Up Your Project</h2>

<p>To get started you will need to configure your project as a cross-project so sbt can compile to all three targets.</p>

<h3 id="adding-dependencies">Adding Dependencies</h3>

<p>Add JitPack to your resolvers and pull in cats-actors using the <code class="language-plaintext highlighter-rouge">%%%</code> triple-percent operator, which selects the right artifact for each platform automatically:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">resolvers</span> <span class="o">+=</span> <span class="s">"jitpack"</span> <span class="n">at</span> <span class="s">"https://jitpack.io"</span>

<span class="n">libraryDependencies</span> <span class="o">+=</span> <span class="s">"com.github.suprnation.cats-actors"</span> <span class="o">%%%</span> <span class="s">"cats-actors"</span> <span class="o">%</span> <span class="s">"2.1.0"</span>
</code></pre></div></div>

<p>Then declare a cross-project in your <code class="language-plaintext highlighter-rouge">build.sbt</code>:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nn">org.portablescala.sbtplatformdeps.PlatformDepsPlugin.autoImport._</span>
<span class="k">import</span> <span class="nn">scala.scalanative.build._</span>

<span class="nc">ThisBuild</span> <span class="o">/</span> <span class="n">scalaVersion</span> <span class="o">:=</span> <span class="s">"2.13.18"</span>

<span class="k">lazy</span> <span class="k">val</span> <span class="nv">myProject</span> <span class="k">=</span> <span class="nf">crossProject</span><span class="o">(</span><span class="nc">JVMPlatform</span><span class="o">,</span> <span class="nc">JSPlatform</span><span class="o">,</span> <span class="nc">NativePlatform</span><span class="o">)</span>
  <span class="o">.</span><span class="py">crossType</span><span class="o">(</span><span class="nv">CrossType</span><span class="o">.</span><span class="py">Full</span><span class="o">)</span>
  <span class="o">.</span><span class="py">settings</span><span class="o">(</span>
    <span class="n">libraryDependencies</span> <span class="o">++=</span> <span class="nc">Seq</span><span class="o">(</span>
      <span class="s">"com.github.suprnation.cats-actors"</span> <span class="o">%%%</span> <span class="s">"cats-actors"</span> <span class="o">%</span> <span class="s">"2.1.0"</span>
    <span class="o">)</span>
  <span class="o">)</span>
  <span class="o">.</span><span class="py">nativeSettings</span><span class="o">(</span>
    <span class="n">nativeConfig</span> <span class="o">~=</span> <span class="o">{</span>
      <span class="nv">_</span><span class="o">.</span><span class="py">withLTO</span><span class="o">(</span><span class="nv">LTO</span><span class="o">.</span><span class="py">none</span><span class="o">)</span>
        <span class="o">.</span><span class="py">withMode</span><span class="o">(</span><span class="nv">Mode</span><span class="o">.</span><span class="py">releaseFull</span><span class="o">)</span>
        <span class="o">.</span><span class="py">withGC</span><span class="o">(</span><span class="nv">GC</span><span class="o">.</span><span class="py">immix</span><span class="o">)</span>
    <span class="o">}</span>
  <span class="o">)</span>
</code></pre></div></div>

<p>With <code class="language-plaintext highlighter-rouge">CrossType.Full</code> you get separate <code class="language-plaintext highlighter-rouge">jvm/</code>, <code class="language-plaintext highlighter-rouge">js/</code>, and <code class="language-plaintext highlighter-rouge">native/</code> source trees alongside the shared one. Everything in <code class="language-plaintext highlighter-rouge">shared/</code> compiles everywhere. Platform-specific code lives in its own tree, and the build wires it in automatically.</p>

<p>From there, running on any platform is just a target name:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sbt <span class="s2">"myProjectJVM/run"</span>      <span class="c"># JVM</span>
sbt <span class="s2">"myProjectJS/run"</span>       <span class="c"># Node.js</span>
sbt <span class="s2">"myProjectNative/run"</span>   <span class="c"># Scala Native binary</span>
</code></pre></div></div>

<blockquote>
  <p>Note: to view and run all code samples discussed in this blog post, clone the <a href="https://github.com/cloudmark/cats-actor-sample">GitHub repository</a>.</p>
</blockquote>

<h2 id="racing-jvm-against-native">Racing JVM Against Native</h2>

<p>The actor ring benchmark is a classic. Popularised by Erlang, it has been used to compare actor systems for decades. Create a ring of <code class="language-plaintext highlighter-rouge">N</code> actors, inject a single token, and let it travel <code class="language-plaintext highlighter-rouge">totalHops</code> times around the ring. Each relay is one message send. Measure the total time. Same code, two platforms, see what happens.</p>

<p>The full code lives in <a href="https://github.com/cloudmark/cats-actor-sample/tree/main/sample7"><code class="language-plaintext highlighter-rouge">sample7</code></a> in the repository, but let’s walk through it.</p>

<div class="mermaid">
graph LR
    N0["RingNode 0 ●"] --&gt;|"RingToken(r-1)"| N1["RingNode 1"]
    N1 --&gt;|"RingToken(r-2)"| N2["RingNode 2"]
    N2 --&gt;|"..."| N3["RingNode N-1"]
    N3 --&gt;|"RingToken(0) → done!"| N0
</div>

<h3 id="the-ring-actor">The Ring Actor</h3>

<p>Each actor in the ring does exactly one thing: if the token still has hops remaining, pass it to the next actor. When the count hits zero, signal that the relay is done.</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">final</span> <span class="k">case</span> <span class="k">class</span> <span class="nc">RingToken</span><span class="o">(</span><span class="n">remaining</span><span class="k">:</span> <span class="kt">Long</span><span class="o">)</span>

<span class="k">final</span> <span class="k">class</span> <span class="nc">RingNode</span><span class="o">(</span>
    <span class="n">index</span><span class="k">:</span> <span class="kt">Int</span><span class="o">,</span>
    <span class="n">ringSize</span><span class="k">:</span> <span class="kt">Int</span><span class="o">,</span>
    <span class="n">slots</span><span class="k">:</span> <span class="kt">Ref</span><span class="o">[</span><span class="kt">IO</span>, <span class="kt">Option</span><span class="o">[</span><span class="kt">Vector</span><span class="o">[</span><span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span>, <span class="kt">RingToken</span><span class="o">]]]],</span>
    <span class="n">done</span><span class="k">:</span> <span class="kt">Deferred</span><span class="o">[</span><span class="kt">IO</span>, <span class="kt">Unit</span><span class="o">]</span>
<span class="o">)</span> <span class="k">extends</span> <span class="nc">Actor</span><span class="o">[</span><span class="kt">IO</span>, <span class="kt">RingToken</span><span class="o">]</span> <span class="o">{</span>

  <span class="k">override</span> <span class="k">def</span> <span class="nf">receive</span><span class="k">:</span> <span class="kt">Receive</span><span class="o">[</span><span class="kt">IO</span>, <span class="kt">RingToken</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
    <span class="k">case</span> <span class="nc">RingToken</span><span class="o">(</span><span class="mi">0L</span><span class="o">)</span> <span class="k">=&gt;</span>
      <span class="nv">done</span><span class="o">.</span><span class="py">complete</span><span class="o">(()).</span><span class="py">void</span>
    <span class="k">case</span> <span class="nc">RingToken</span><span class="o">(</span><span class="n">r</span><span class="o">)</span> <span class="k">if</span> <span class="n">r</span> <span class="o">&gt;</span> <span class="mi">0L</span> <span class="k">=&gt;</span>
      <span class="k">for</span> <span class="o">{</span>
        <span class="n">vecOpt</span> <span class="k">&lt;-</span> <span class="nv">slots</span><span class="o">.</span><span class="py">get</span>
        <span class="n">vec</span>    <span class="k">&lt;-</span> <span class="n">vecOpt</span> <span class="k">match</span> <span class="o">{</span>
          <span class="k">case</span> <span class="nc">Some</span><span class="o">(</span><span class="n">v</span><span class="o">)</span> <span class="k">=&gt;</span> <span class="nv">IO</span><span class="o">.</span><span class="py">pure</span><span class="o">(</span><span class="n">v</span><span class="o">)</span>
          <span class="k">case</span> <span class="nc">None</span>    <span class="k">=&gt;</span> <span class="nv">IO</span><span class="o">.</span><span class="py">raiseError</span><span class="o">(</span><span class="k">new</span> <span class="nc">IllegalStateException</span><span class="o">(</span><span class="s">"ring not wired"</span><span class="o">))</span>
        <span class="o">}</span>
        <span class="n">next</span> <span class="k">=</span> <span class="nf">vec</span><span class="o">((</span><span class="n">index</span> <span class="o">+</span> <span class="mi">1</span><span class="o">)</span> <span class="o">%</span> <span class="n">ringSize</span><span class="o">)</span>
        <span class="k">_</span>    <span class="k">&lt;-</span> <span class="n">next</span> <span class="o">!</span> <span class="nc">RingToken</span><span class="o">(</span><span class="n">r</span> <span class="o">-</span> <span class="mi">1L</span><span class="o">)</span>
      <span class="o">}</span> <span class="nf">yield</span> <span class="o">()</span>
    <span class="k">case</span> <span class="k">_</span> <span class="k">=&gt;</span> <span class="nv">IO</span><span class="o">.</span><span class="py">unit</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<h3 id="breaking-down-the-ringnode">Breaking Down the RingNode</h3>

<ol>
  <li>
    <p><strong>The token</strong>: <code class="language-plaintext highlighter-rouge">RingToken</code> carries a single field, <code class="language-plaintext highlighter-rouge">remaining</code>, counting down from <code class="language-plaintext highlighter-rouge">totalHops</code> to zero. That is all that ever travels on the wire.</p>
  </li>
  <li>
    <p><strong>The ring topology</strong>: The vector of actor refs is stored in a <code class="language-plaintext highlighter-rouge">Ref</code> because all nodes are spawned before any of them know about the others. The harness wires them up in a second pass by calling <code class="language-plaintext highlighter-rouge">slots.set(Some(refs))</code>.</p>
  </li>
  <li>
    <p><strong>The completion signal</strong>: <code class="language-plaintext highlighter-rouge">done</code> is a <code class="language-plaintext highlighter-rouge">Deferred[IO, Unit]</code>, a one-shot, semantically blocking signal. When the last hop arrives, <code class="language-plaintext highlighter-rouge">done.complete(())</code> fires and unblocks the harness that is waiting on <code class="language-plaintext highlighter-rouge">done.get</code>. No polling, no shared mutable variable.</p>
  </li>
  <li>
    <p><strong>The send</strong>: <code class="language-plaintext highlighter-rouge">next ! RingToken(r - 1L)</code> is the fire-and-forget send, pure functional IO, the same whether this code runs on the JVM or compiles to a native binary.</p>
  </li>
</ol>

<h3 id="wiring-and-firing">Wiring and Firing</h3>

<p>The benchmark harness spawns the ring, wires it, fires the first token, and waits:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">private</span> <span class="k">def</span> <span class="nf">runOnce</span><span class="o">(</span><span class="n">system</span><span class="k">:</span> <span class="kt">ActorSystem</span><span class="o">[</span><span class="kt">IO</span><span class="o">],</span> <span class="n">runId</span><span class="k">:</span> <span class="kt">String</span><span class="o">,</span> <span class="n">cfg</span><span class="k">:</span> <span class="kt">Config</span><span class="o">)</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">FiniteDuration</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
  <span class="k">val</span> <span class="nv">n</span>    <span class="k">=</span> <span class="nv">cfg</span><span class="o">.</span><span class="py">ringSize</span>
  <span class="k">val</span> <span class="nv">hops</span> <span class="k">=</span> <span class="nv">cfg</span><span class="o">.</span><span class="py">totalHops</span>

  <span class="k">for</span> <span class="o">{</span>
    <span class="n">done</span>     <span class="k">&lt;-</span> <span class="nc">Deferred</span><span class="o">[</span><span class="kt">IO</span>, <span class="kt">Unit</span><span class="o">]</span>
    <span class="n">slots</span>    <span class="k">&lt;-</span> <span class="nc">Ref</span><span class="o">[</span><span class="kt">IO</span><span class="o">].</span><span class="py">of</span><span class="o">[</span><span class="kt">Option</span><span class="o">[</span><span class="kt">Vector</span><span class="o">[</span><span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span>, <span class="kt">RingToken</span><span class="o">]]]](</span><span class="nc">None</span><span class="o">)</span>
    <span class="n">refsList</span> <span class="k">&lt;-</span> <span class="o">(</span><span class="mi">0</span> <span class="n">until</span> <span class="n">n</span><span class="o">).</span><span class="py">toList</span><span class="o">.</span><span class="py">traverse</span><span class="o">(</span><span class="n">i</span> <span class="k">=&gt;</span>
      <span class="nv">system</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="k">new</span> <span class="nc">RingNode</span><span class="o">(</span><span class="n">i</span><span class="o">,</span> <span class="n">n</span><span class="o">,</span> <span class="n">slots</span><span class="o">,</span> <span class="n">done</span><span class="o">),</span> <span class="n">s</span><span class="s">"ring-$runId-$i"</span><span class="o">)</span>
    <span class="o">)</span>
    <span class="n">refs</span> <span class="k">=</span> <span class="nv">refsList</span><span class="o">.</span><span class="py">toVector</span>
    <span class="k">_</span>    <span class="k">&lt;-</span> <span class="nv">slots</span><span class="o">.</span><span class="py">set</span><span class="o">(</span><span class="nc">Some</span><span class="o">(</span><span class="n">refs</span><span class="o">))</span>
    <span class="n">t0</span>   <span class="k">&lt;-</span> <span class="nc">Clock</span><span class="o">[</span><span class="kt">IO</span><span class="o">].</span><span class="py">monotonic</span>
    <span class="k">_</span>    <span class="k">&lt;-</span> <span class="nf">refs</span><span class="o">(</span><span class="mi">0</span><span class="o">)</span> <span class="o">!</span> <span class="nc">RingToken</span><span class="o">(</span><span class="n">hops</span><span class="o">)</span>
    <span class="k">_</span>    <span class="k">&lt;-</span> <span class="nv">done</span><span class="o">.</span><span class="py">get</span>
    <span class="n">t1</span>   <span class="k">&lt;-</span> <span class="nc">Clock</span><span class="o">[</span><span class="kt">IO</span><span class="o">].</span><span class="py">monotonic</span>
  <span class="o">}</span> <span class="k">yield</span> <span class="n">t1</span> <span class="o">-</span> <span class="n">t0</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Run it yourself:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># JVM</span>
sbt <span class="s2">"sample7JVM/run"</span>

<span class="c"># Scala Native (compile first, then run the binary directly)</span>
sbt <span class="s2">"sample7Native/nativeLink"</span>
./sample7/native/target/scala-2.13/native/com.suprnation.Sample7
</code></pre></div></div>

<p>You can tune things via environment variables (<code class="language-plaintext highlighter-rouge">SAMPLE7_RING_SIZE</code>, <code class="language-plaintext highlighter-rouge">SAMPLE7_TOTAL_HOPS</code>, <code class="language-plaintext highlighter-rouge">SAMPLE7_WARMUP_RUNS</code>, <code class="language-plaintext highlighter-rouge">SAMPLE7_MEASURED_RUNS</code>) or pass them as CLI flags. The same benchmark also runs on Node.js via <code class="language-plaintext highlighter-rouge">sample7JS/run</code> — useful for a quick sanity check, though the browser target is where Scala.js really comes into its own, as you will see in the next section.</p>

<h3 id="sample-output-log">Sample Output :log:</h3>

<p>Here is what the Native binary prints for ring size 64 with 1M hops:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">===</span> Sample 7: actor ring <span class="o">(</span>token relay<span class="o">)</span> <span class="o">===</span>
Startup <span class="o">(</span>entry → actor system ready<span class="o">)</span>: 0.21 ms
Ring size: 64, total hops: 1000000
Warmup: 1, measured: 3

<span class="o">[</span>warmup 1] elapsed: 11.612 s
<span class="o">[</span>run 1] elapsed: 11.498 s
<span class="o">[</span>run 2] elapsed: 11.541 s
<span class="o">[</span>run 3] elapsed: 11.573 s

Median elapsed: 11.541 s
Stddev elapsed: 0.033 s
CV <span class="o">(</span>consistency<span class="o">)</span>: 0.3%  <span class="o">(</span>lower <span class="o">=</span> steadier<span class="o">)</span>
Median throughput: 86696.41 messages/s
Median latency: 11541.000 ns per hop
</code></pre></div></div>

<p>0.21ms startup, 0.3% CV. Now run the same config on the JVM and the startup jumps to 127ms, CV climbs to 6.6%, but throughput reaches 111k msg/s and keeps climbing with ring size. Two different trade-offs, same actor code.</p>

<h3 id="the-numbers">The Numbers</h3>

<p>Results from a sweep across ring sizes of 32, 64, 128, and 256 with 1M total hops:</p>

<p><img src="/images/cats-actors/ring-benchmark.png" alt="Ring benchmark results" /></p>

<p>Native starts up in under 6ms across every ring size while the JVM costs over 120ms at startup. After warmup the JVM pulls ahead on throughput, reaching over 250k messages per second at ring size 128, because the JVM’s just-in-time compiler observes the hot loop at runtime and generates optimised machine code for it, something a statically compiled binary cannot do. Native compiles once ahead of time and runs at a fixed speed, which is why its throughput is steady but does not accelerate with load. The consistency column reflects exactly this: Native’s stddev stays flat and low throughout while the JVM varies more between runs. If you need a process that starts instantly and runs predictably, Native is the right choice. If you need maximum sustained throughput on a long-running service, the JVM takes it. Same actor code, both options open.</p>

<hr />

<h2 id="eight-monkeys-in-the-browser">Eight Monkeys in the Browser</h2>

<p>OK now we are having fun.</p>

<p>Meet Kong, Bonzo, Coco, Mango, Peaches, Bandit, Zippy, and Bubbles. Eight monkey actors spawned into an arena. Each round, every living monkey picks a random target and throws a banana at them. The target has a 25% chance to dodge. Take enough hits and you are out. Last monkey standing wins.</p>

<p>Every banana throw is a real actor message send using the <code class="language-plaintext highlighter-rouge">!</code> operator. The monkeys are making decisions, updating their own state, and communicating asynchronously, exactly as you would write production actor code. And on Scala.js, every event feeds a live React UI running right here in the page.</p>

<p>Go ahead, watch the battle unfold. :point_down:</p>

<iframe src="/banana-battle.html" width="100%" height="800" frameborder="0" style="border-radius:12px; display:block; margin: 1.5rem 0; min-height: 800px;"></iframe>

<p>Not a single line of JavaScript was written. Those are Scala actors, compiled to JS via Scala.js, rendering a React UI through the Slinky bindings. The full code is in <a href="https://github.com/cloudmark/cats-actor-sample/tree/main/sample8"><code class="language-plaintext highlighter-rouge">sample8</code></a> in the repository.</p>

<h3 id="the-monkeyactor">The MonkeyActor</h3>

<p>Each monkey holds its own state in a <code class="language-plaintext highlighter-rouge">Ref[IO, MonkeyState]</code> and receives three kinds of messages:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">sealed</span> <span class="k">trait</span> <span class="nc">ArenaMessage</span>
<span class="k">final</span> <span class="k">case</span> <span class="k">class</span> <span class="nc">Tick</span><span class="o">(</span><span class="n">round</span><span class="k">:</span> <span class="kt">Int</span><span class="o">)</span>                              <span class="k">extends</span> <span class="nc">ArenaMessage</span>
<span class="k">final</span> <span class="k">case</span> <span class="k">class</span> <span class="nc">IncomingBanana</span><span class="o">(</span><span class="n">fromId</span><span class="k">:</span> <span class="kt">Int</span><span class="o">,</span> <span class="n">fromName</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span> <span class="k">extends</span> <span class="nc">ArenaMessage</span>
<span class="k">final</span> <span class="k">case</span> <span class="k">class</span> <span class="nc">ThrowResult</span><span class="o">(</span><span class="n">targetId</span><span class="k">:</span> <span class="kt">Int</span><span class="o">,</span> <span class="n">hit</span><span class="k">:</span> <span class="kt">Boolean</span><span class="o">)</span>      <span class="k">extends</span> <span class="nc">ArenaMessage</span>
</code></pre></div></div>

<p>On a <code class="language-plaintext highlighter-rouge">Tick</code>, a monkey picks a target and throws:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">case</span> <span class="nc">Tick</span><span class="o">(</span><span class="k">_</span><span class="o">)</span> <span class="k">=&gt;</span>
  <span class="k">for</span> <span class="o">{</span>
    <span class="n">me</span> <span class="k">&lt;-</span> <span class="nv">state</span><span class="o">.</span><span class="py">get</span>
    <span class="k">_</span>  <span class="k">&lt;-</span> <span class="nf">if</span> <span class="o">(</span><span class="nv">me</span><span class="o">.</span><span class="py">health</span> <span class="o">&lt;=</span> <span class="mi">0</span> <span class="o">||</span> <span class="nv">me</span><span class="o">.</span><span class="py">bananas</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="o">)</span> <span class="nv">IO</span><span class="o">.</span><span class="py">unit</span> <span class="k">else</span> <span class="nf">throwBanana</span><span class="o">(</span><span class="n">me</span><span class="o">)</span>
  <span class="o">}</span> <span class="nf">yield</span> <span class="o">()</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">throwBanana</code> finds a living target, decrements the banana count, and sends an <code class="language-plaintext highlighter-rouge">IncomingBanana</code> to the target actor:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">private</span> <span class="k">def</span> <span class="nf">throwBanana</span><span class="o">(</span><span class="n">me</span><span class="k">:</span> <span class="kt">MonkeyState</span><span class="o">)</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span> <span class="k">=</span>
  <span class="k">for</span> <span class="o">{</span>
    <span class="n">targets</span> <span class="k">&lt;-</span> <span class="nv">allStates</span><span class="o">.</span><span class="py">traverse</span><span class="o">(</span><span class="nv">_</span><span class="o">.</span><span class="py">get</span><span class="o">).</span><span class="py">map</span><span class="o">(</span><span class="nv">_</span><span class="o">.</span><span class="py">filter</span><span class="o">(</span><span class="n">s</span> <span class="k">=&gt;</span> <span class="nv">s</span><span class="o">.</span><span class="py">health</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="nv">s</span><span class="o">.</span><span class="py">id</span> <span class="o">!=</span> <span class="n">id</span><span class="o">))</span>
    <span class="k">_</span> <span class="k">&lt;-</span> <span class="nf">if</span> <span class="o">(</span><span class="nv">targets</span><span class="o">.</span><span class="py">isEmpty</span><span class="o">)</span> <span class="nv">IO</span><span class="o">.</span><span class="py">unit</span> <span class="k">else</span> <span class="o">{</span>
      <span class="k">val</span> <span class="nv">target</span> <span class="k">=</span> <span class="nf">targets</span><span class="o">(</span><span class="nv">rng</span><span class="o">.</span><span class="py">nextInt</span><span class="o">(</span><span class="nv">targets</span><span class="o">.</span><span class="py">size</span><span class="o">))</span>
      <span class="k">for</span> <span class="o">{</span>
        <span class="k">_</span>       <span class="k">&lt;-</span> <span class="nv">state</span><span class="o">.</span><span class="py">update</span><span class="o">(</span><span class="n">s</span> <span class="k">=&gt;</span> <span class="nv">s</span><span class="o">.</span><span class="py">copy</span><span class="o">(</span><span class="n">bananas</span> <span class="k">=</span> <span class="nv">s</span><span class="o">.</span><span class="py">bananas</span> <span class="o">-</span> <span class="mi">1</span><span class="o">,</span> <span class="n">throws</span> <span class="k">=</span> <span class="nv">s</span><span class="o">.</span><span class="py">throws</span> <span class="o">+</span> <span class="mi">1</span><span class="o">))</span>
        <span class="k">_</span>       <span class="k">&lt;-</span> <span class="nv">PlatformInterop</span><span class="o">.</span><span class="py">appendVisualLog</span><span class="o">(</span><span class="n">s</span><span class="s">"🍌 $name throws at ${target.name}!"</span><span class="o">)</span>
        <span class="k">_</span>       <span class="k">&lt;-</span> <span class="nv">PlatformInterop</span><span class="o">.</span><span class="py">onBananaThrown</span><span class="o">(</span><span class="n">id</span><span class="o">,</span> <span class="nv">target</span><span class="o">.</span><span class="py">id</span><span class="o">)</span>
        <span class="n">monkeys</span> <span class="k">&lt;-</span> <span class="nv">registry</span><span class="o">.</span><span class="py">get</span>
        <span class="k">_</span>       <span class="k">&lt;-</span> <span class="nf">monkeys</span><span class="o">(</span><span class="nv">target</span><span class="o">.</span><span class="py">id</span><span class="o">)</span> <span class="o">!</span> <span class="nc">IncomingBanana</span><span class="o">(</span><span class="n">id</span><span class="o">,</span> <span class="n">name</span><span class="o">)</span>
      <span class="o">}</span> <span class="nf">yield</span> <span class="o">()</span>
    <span class="o">}</span>
  <span class="o">}</span> <span class="nf">yield</span> <span class="o">()</span>
</code></pre></div></div>

<p>On the receiving end the target rolls the dice (25% dodge chance, otherwise take the hit):</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">private</span> <span class="k">def</span> <span class="nf">receiveBanana</span><span class="o">(</span><span class="n">me</span><span class="k">:</span> <span class="kt">MonkeyState</span><span class="o">,</span> <span class="n">fromId</span><span class="k">:</span> <span class="kt">Int</span><span class="o">,</span> <span class="n">fromName</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
  <span class="k">val</span> <span class="nv">dodged</span> <span class="k">=</span> <span class="nv">rng</span><span class="o">.</span><span class="py">nextInt</span><span class="o">(</span><span class="mi">100</span><span class="o">)</span> <span class="o">&lt;</span> <span class="mi">25</span>
  <span class="k">for</span> <span class="o">{</span>
    <span class="n">monkeys</span> <span class="k">&lt;-</span> <span class="nv">registry</span><span class="o">.</span><span class="py">get</span>
    <span class="k">_</span> <span class="k">&lt;-</span> <span class="nf">if</span> <span class="o">(</span><span class="n">dodged</span><span class="o">)</span> <span class="o">{</span>
      <span class="nv">PlatformInterop</span><span class="o">.</span><span class="py">appendVisualLog</span><span class="o">(</span><span class="n">s</span><span class="s">"💨 ${me.name} dodges!"</span><span class="o">)</span> <span class="o">*&gt;</span>
      <span class="o">(</span><span class="nf">monkeys</span><span class="o">(</span><span class="n">fromId</span><span class="o">)</span> <span class="o">!</span> <span class="nc">ThrowResult</span><span class="o">(</span><span class="n">id</span><span class="o">,</span> <span class="n">hit</span> <span class="k">=</span> <span class="kc">false</span><span class="o">))</span>
    <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
      <span class="k">for</span> <span class="o">{</span>
        <span class="n">updated</span> <span class="k">&lt;-</span> <span class="nv">state</span><span class="o">.</span><span class="py">updateAndGet</span><span class="o">(</span><span class="n">s</span> <span class="k">=&gt;</span> <span class="nv">s</span><span class="o">.</span><span class="py">copy</span><span class="o">(</span><span class="n">health</span> <span class="k">=</span> <span class="nv">s</span><span class="o">.</span><span class="py">health</span> <span class="o">-</span> <span class="mi">1</span><span class="o">))</span>
        <span class="k">_</span>       <span class="k">&lt;-</span> <span class="nv">PlatformInterop</span><span class="o">.</span><span class="py">appendVisualLog</span><span class="o">(</span><span class="n">s</span><span class="s">"💥 ${me.name} hit! HP: ${updated.health}"</span><span class="o">)</span>
        <span class="k">_</span>       <span class="k">&lt;-</span> <span class="nf">monkeys</span><span class="o">(</span><span class="n">fromId</span><span class="o">)</span> <span class="o">!</span> <span class="nc">ThrowResult</span><span class="o">(</span><span class="n">id</span><span class="o">,</span> <span class="n">hit</span> <span class="k">=</span> <span class="kc">true</span><span class="o">)</span>
        <span class="k">_</span>       <span class="k">&lt;-</span> <span class="nf">if</span> <span class="o">(</span><span class="nv">updated</span><span class="o">.</span><span class="py">health</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="o">)</span>
                     <span class="nv">PlatformInterop</span><span class="o">.</span><span class="py">appendVisualLog</span><span class="o">(</span><span class="n">s</span><span class="s">"☠️  ${me.name} is out!"</span><span class="o">)</span> <span class="o">*&gt;</span>
                     <span class="nv">PlatformInterop</span><span class="o">.</span><span class="py">onMonkeyEliminated</span><span class="o">(</span><span class="n">id</span><span class="o">)</span>
                   <span class="k">else</span> <span class="nv">IO</span><span class="o">.</span><span class="py">unit</span>
      <span class="o">}</span> <span class="nf">yield</span> <span class="o">()</span>
    <span class="o">}</span>
  <span class="o">}</span> <span class="nf">yield</span> <span class="o">()</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Notice the thrower always gets a <code class="language-plaintext highlighter-rouge">ThrowResult</code> back. Actors closing the loop, idiomatic actor design.</p>

<h3 id="one-trait-three-platforms">One Trait, Three Platforms</h3>

<p>Here is the clever part. The shared actor code never touches any platform-specific API. Instead it calls through a single trait:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">trait</span> <span class="nc">PlatformInteropApi</span> <span class="o">{</span>
  <span class="k">def</span> <span class="nf">appendVisualLog</span><span class="o">(</span><span class="n">line</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span>
  <span class="k">def</span> <span class="nf">onBananaThrown</span><span class="o">(</span><span class="n">fromId</span><span class="k">:</span> <span class="kt">Int</span><span class="o">,</span> <span class="n">toId</span><span class="k">:</span> <span class="kt">Int</span><span class="o">)</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span>
  <span class="k">def</span> <span class="nf">onMonkeyEliminated</span><span class="o">(</span><span class="n">id</span><span class="k">:</span> <span class="kt">Int</span><span class="o">)</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span>
  <span class="k">def</span> <span class="nf">onScoreUpdate</span><span class="o">(</span><span class="n">scores</span><span class="k">:</span> <span class="kt">List</span><span class="o">[(</span><span class="kt">Int</span>, <span class="kt">String</span>, <span class="kt">Int</span>, <span class="kt">Int</span><span class="o">)])</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span>
  <span class="k">def</span> <span class="nf">checkRestart</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Boolean</span><span class="o">]</span>
  <span class="k">def</span> <span class="nf">resetArena</span><span class="o">()</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span>
<span class="o">}</span>
</code></pre></div></div>

<p>On JVM and Native it is minimal, just print to the console and move on:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// JVM and Native</span>
<span class="k">object</span> <span class="nc">PlatformInterop</span> <span class="k">extends</span> <span class="nc">PlatformInteropApi</span> <span class="o">{</span>
  <span class="k">override</span> <span class="k">def</span> <span class="nf">appendVisualLog</span><span class="o">(</span><span class="n">line</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span>         <span class="k">=</span> <span class="nv">IO</span><span class="o">.</span><span class="py">println</span><span class="o">(</span><span class="n">line</span><span class="o">)</span>
  <span class="k">override</span> <span class="k">def</span> <span class="nf">onBananaThrown</span><span class="o">(</span><span class="n">fromId</span><span class="k">:</span> <span class="kt">Int</span><span class="o">,</span> <span class="n">toId</span><span class="k">:</span> <span class="kt">Int</span><span class="o">)</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span> <span class="k">=</span> <span class="nv">IO</span><span class="o">.</span><span class="py">unit</span>
  <span class="k">override</span> <span class="k">def</span> <span class="nf">onMonkeyEliminated</span><span class="o">(</span><span class="n">id</span><span class="k">:</span> <span class="kt">Int</span><span class="o">)</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span>           <span class="k">=</span> <span class="nv">IO</span><span class="o">.</span><span class="py">unit</span>
  <span class="c1">// ...</span>
<span class="o">}</span>
</code></pre></div></div>

<p>On Scala.js, every call feeds the live React arena above:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// JS (browser)</span>
<span class="k">object</span> <span class="nc">PlatformInterop</span> <span class="k">extends</span> <span class="nc">PlatformInteropApi</span> <span class="o">{</span>
  <span class="k">override</span> <span class="k">def</span> <span class="nf">appendVisualLog</span><span class="o">(</span><span class="n">line</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span>         <span class="k">=</span> <span class="nc">IO</span><span class="o">(</span><span class="nv">ReactShowcase</span><span class="o">.</span><span class="py">append</span><span class="o">(</span><span class="n">line</span><span class="o">))</span>
  <span class="k">override</span> <span class="k">def</span> <span class="nf">onBananaThrown</span><span class="o">(</span><span class="n">fromId</span><span class="k">:</span> <span class="kt">Int</span><span class="o">,</span> <span class="n">toId</span><span class="k">:</span> <span class="kt">Int</span><span class="o">)</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span> <span class="k">=</span> <span class="nc">IO</span><span class="o">(</span><span class="nv">ReactShowcase</span><span class="o">.</span><span class="py">addProjectile</span><span class="o">(</span><span class="n">fromId</span><span class="o">,</span> <span class="n">toId</span><span class="o">))</span>
  <span class="k">override</span> <span class="k">def</span> <span class="nf">onMonkeyEliminated</span><span class="o">(</span><span class="n">id</span><span class="k">:</span> <span class="kt">Int</span><span class="o">)</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span>           <span class="k">=</span> <span class="nc">IO</span><span class="o">(</span><span class="nv">ReactShowcase</span><span class="o">.</span><span class="py">eliminateMonkey</span><span class="o">(</span><span class="n">id</span><span class="o">))</span>
  <span class="k">override</span> <span class="k">def</span> <span class="nf">checkRestart</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Boolean</span><span class="o">]</span>                       <span class="k">=</span> <span class="nc">IO</span><span class="o">(</span><span class="nv">ReactShowcase</span><span class="o">.</span><span class="py">consumeRestart</span><span class="o">())</span>
  <span class="c1">// ...</span>
<span class="o">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">ReactShowcase</code> manages state through an <code class="language-plaintext highlighter-rouge">AtomicReference</code> and runs a 50ms paint loop that re-renders the SVG arena. Click restart and the shared actor code picks it up automatically, same functional IO loop across all three platforms.</p>

<h3 id="running-locally">Running Locally</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd </span>sample8
sbt <span class="s2">"starterJS/fastLinkJS"</span>
npm <span class="nb">install</span> <span class="o">&amp;&amp;</span> npm run dev
<span class="c"># open http://localhost:5173</span>
</code></pre></div></div>

<h1 id="conclusion-tada">Conclusion :tada:</h1>

<p>The same actor. The same <code class="language-plaintext highlighter-rouge">receive</code>. The same <code class="language-plaintext highlighter-rouge">!</code>. Running on a JVM, compiled to a native binary, or animating a banana war in your browser. That is Cats-Actors now.</p>

<p>A huge thank you to <a href="https://github.com/rlavolee">Rémi Lavolée</a> and <a href="https://github.com/Voltir">Nick Childers</a> for making this possible.</p>

<p>Check out the <a href="https://github.com/suprnation/cats-actors">Cats-Actors repository</a> and clone the <a href="https://github.com/cloudmark/cats-actor-sample">cats-actor-sample repository</a>, pick a platform, and get hacking.</p>

<p>As always, stay safe, keep hacking!</p>]]></content><author><name>Mark Galea</name></author><summary type="html"><![CDATA[Imagine writing your actor logic once (typed messages, functional state, the ! operator, supervision and all) and then deciding on a whim whether it runs as a JVM service, a self-contained native binary, or a live interactive app in your browser. No rewrites, no ports, no platform-specific glue. Just one codebase. Cats-Actors can do that now, and in this post we are going to have some fun with it. We will throw a token around a ring of actors on both JVM and Scala Native, and then (because why not) we will drop eight monkey actors into a banana-throwing arena right here inside this page. Real actors. Real messages. Running in your browser.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://cloudmark.github.io/images/cats-actors/logo-small.png" /><media:content medium="image" url="http://cloudmark.github.io/images/cats-actors/logo-small.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Typed Actors in Action - Exploring Cats-Actors with Alice and Bob</title><link href="http://cloudmark.github.io/Cats-Actors-In-The-Wild/" rel="alternate" type="text/html" title="Typed Actors in Action - Exploring Cats-Actors with Alice and Bob" /><published>2024-06-27T00:00:00+00:00</published><updated>2024-06-27T00:00:00+00:00</updated><id>http://cloudmark.github.io/Cats-Actors-In-The-Wild</id><content type="html" xml:base="http://cloudmark.github.io/Cats-Actors-In-The-Wild/"><![CDATA[<p><img class="title" src="/images/cats-actors/transaction-2.png" />
Today marks an exciting milestone with the release of Cats-Actors 2.0.0-RC1. This version introduces typed actors, a feature that the community has eagerly awaited. To showcase this new capability, we’ll walk through a classic example of handling wallet transactions between two users, Alice and Bob.
So, sit back and relax as we explore how Alice sends money to Bob using typed actors in Cats-Actors.</p>

<h2 id="meet-alice-and-bob">Meet Alice and Bob</h2>

<p>Alice and Bob are best friends and tech enthusiasts who often lend and borrow money from each other. Today, Alice needs to send some money to Bob to settle a shared expense. To handle this transaction, they decide to use the latest release of Cats-Actors, excited to explore its new typed actors feature.</p>

<p>Typed actors ensure type-checked message passing at compile time, reducing runtime errors. Alice and Bob will create wallet actors to manage their balances and use a transaction actor to coordinate the money transfer from Alice’s wallet to Bob’s.</p>

<h2 id="setting-up-your-project">Setting Up Your Project</h2>
<p>To begin working with typed actors in Cats-Actors, you’ll need to set up your Scala project to include the necessary dependencies and explore the framework’s resources.</p>

<h3 id="adding-dependencies">Adding Dependencies</h3>

<p>First, ensure your Scala project is configured to fetch dependencies from JitPack, a popular repository for GitHub-hosted projects. Add the following lines to your build.sbt file:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code>   <span class="n">resolvers</span> <span class="o">+=</span> <span class="s">"JitPack"</span> <span class="n">at</span> <span class="s">"https://jitpack.io"</span>

   <span class="n">libraryDependencies</span> <span class="o">+=</span> <span class="s">"com.github.suprnation"</span> <span class="o">%</span> <span class="s">"cats-actors_2.13"</span> <span class="o">%</span> <span class="s">"2.0.0-RC1"</span>
</code></pre></div></div>

<p>In the above snippet, <code class="language-plaintext highlighter-rouge">"2.0.0-RC1"</code> should be replaced with the latest version of Cats-Actors available on JitPack. These dependencies enable you to utilize Cats-Actors in your Scala application.</p>

<p>Visit the <a href="https://github.com/suprnation/cats-actors/">Cats-Actors GitHub repository</a> to explore comprehensive documentation, examples, and community contributions related to the framework.</p>

<blockquote>
  <p>Note to view and run all code samples discussed in this blog post, clone the <a href="https://github.com/cloudmark/cats-actor-sample">GitHub repository</a>.</p>
</blockquote>

<h2 id="the-walletactor-managing-alice-and-bobs-wallets-bank">The WalletActor: Managing Alice and Bob’s Wallets :bank:</h2>

<p>The <code class="language-plaintext highlighter-rouge">WalletActor</code> is responsible for managing commands related to wallet operations, including retrieving balances, depositing funds, and withdrawing funds. It ensures robustness by strictly typing its <code class="language-plaintext highlighter-rouge">receive</code> operations to handle only <code class="language-plaintext highlighter-rouge">Command</code> messages, thereby preventing runtime errors. Let’s delve into how it works.</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="nn">com.suprnation.samples</span>

<span class="k">import</span> <span class="nn">cats.effect.</span><span class="o">{</span><span class="nc">ExitCode</span><span class="o">,</span> <span class="nc">IO</span><span class="o">,</span> <span class="nc">IOApp</span><span class="o">,</span> <span class="nc">Ref</span><span class="o">}</span>
<span class="k">import</span> <span class="nn">cats.implicits._</span>
<span class="k">import</span> <span class="nn">com.suprnation.actor.Actor.</span><span class="o">{</span><span class="nc">Actor</span><span class="o">,</span> <span class="nc">Receive</span><span class="o">}</span>
<span class="k">import</span> <span class="nn">com.suprnation.actor.ActorRef.ActorRef</span>
<span class="k">import</span> <span class="nn">com.suprnation.actor._</span>

<span class="k">object</span> <span class="nc">WalletActor</span> <span class="o">{</span>
  <span class="k">sealed</span> <span class="k">trait</span> <span class="nc">Command</span>
  <span class="k">case</span> <span class="k">class</span> <span class="nc">GetBalance</span><span class="o">(</span><span class="n">replyTo</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span>, <span class="kt">Balance</span><span class="o">])</span> <span class="k">extends</span> <span class="nc">Command</span>
  <span class="k">case</span> <span class="k">class</span> <span class="nc">Deposit</span><span class="o">(</span><span class="n">amount</span><span class="k">:</span> <span class="kt">BigDecimal</span><span class="o">,</span> <span class="n">replyTo</span><span class="k">:</span> <span class="kt">Option</span><span class="o">[</span><span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span>, <span class="kt">Response</span><span class="o">]])</span> <span class="k">extends</span> <span class="nc">Command</span>
  <span class="k">case</span> <span class="k">class</span> <span class="nc">Withdraw</span><span class="o">(</span><span class="n">amount</span><span class="k">:</span> <span class="kt">BigDecimal</span><span class="o">,</span> <span class="n">replyTo</span><span class="k">:</span> <span class="kt">Option</span><span class="o">[</span><span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span>, <span class="kt">Response</span><span class="o">]])</span> <span class="k">extends</span> <span class="nc">Command</span>

  <span class="k">sealed</span> <span class="k">trait</span> <span class="nc">Response</span>
  <span class="k">case</span> <span class="k">class</span> <span class="nc">TransactionFailed</span><span class="o">(</span><span class="n">reason</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span> <span class="k">extends</span> <span class="nc">Response</span>
  <span class="k">case</span> <span class="k">class</span> <span class="nc">Balance</span><span class="o">(</span><span class="n">amount</span><span class="k">:</span> <span class="kt">BigDecimal</span><span class="o">)</span> <span class="k">extends</span> <span class="nc">Response</span>

  <span class="k">def</span> <span class="nf">create</span><span class="o">(</span><span class="n">walletId</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Actor</span><span class="o">[</span><span class="kt">IO</span>, <span class="kt">Command</span><span class="o">]]</span> <span class="k">=</span>
    <span class="k">for</span> <span class="o">{</span>
      <span class="n">balance</span> <span class="k">&lt;-</span> <span class="nc">Ref</span><span class="o">[</span><span class="kt">IO</span><span class="o">].</span><span class="py">of</span><span class="o">(</span><span class="nv">BigDecimal</span><span class="o">.</span><span class="py">decimal</span><span class="o">(</span><span class="mf">0.0</span><span class="o">))</span>
    <span class="o">}</span> <span class="k">yield</span> <span class="k">new</span> <span class="nc">Actor</span><span class="o">[</span><span class="kt">IO</span>, <span class="kt">Command</span><span class="o">]</span> <span class="o">{</span>
      <span class="k">override</span> <span class="k">def</span> <span class="nf">receive</span><span class="k">:</span> <span class="kt">Receive</span><span class="o">[</span><span class="kt">IO</span>, <span class="kt">Command</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
        <span class="k">case</span> <span class="nc">Deposit</span><span class="o">(</span><span class="n">amount</span><span class="o">,</span> <span class="n">replyTo</span><span class="o">)</span> <span class="k">=&gt;</span>
          <span class="nv">balance</span><span class="o">.</span><span class="py">update</span><span class="o">(</span><span class="k">_</span> <span class="o">+</span> <span class="n">amount</span><span class="o">)</span> <span class="o">&gt;&gt;</span>
            <span class="nv">balance</span><span class="o">.</span><span class="py">get</span><span class="o">.</span><span class="py">flatMap</span><span class="o">(</span><span class="n">newBalance</span> <span class="k">=&gt;</span>
              <span class="nv">IO</span><span class="o">.</span><span class="py">println</span><span class="o">(</span>
                <span class="n">s</span><span class="s">"[${context.self.path.name}] Deposited $amount to $walletId. New balance: $newBalance"</span>
              <span class="o">)</span> <span class="o">&gt;&gt;</span>
                <span class="nv">replyTo</span><span class="o">.</span><span class="py">fold</span><span class="o">(</span><span class="nv">IO</span><span class="o">.</span><span class="py">unit</span><span class="o">)(</span><span class="k">_</span> <span class="o">!</span> <span class="nc">Balance</span><span class="o">(</span><span class="n">newBalance</span><span class="o">))</span>
            <span class="o">)</span>

        <span class="k">case</span> <span class="nc">Withdraw</span><span class="o">(</span><span class="n">amount</span><span class="o">,</span> <span class="n">replyTo</span><span class="o">)</span> <span class="k">=&gt;</span>
          <span class="nv">balance</span><span class="o">.</span><span class="py">get</span><span class="o">.</span><span class="py">flatMap</span> <span class="o">{</span> <span class="n">currentBalance</span> <span class="k">=&gt;</span>
            <span class="nf">if</span> <span class="o">(</span><span class="n">currentBalance</span> <span class="o">&gt;=</span> <span class="n">amount</span><span class="o">)</span> <span class="o">{</span>
              <span class="nv">balance</span><span class="o">.</span><span class="py">update</span><span class="o">(</span><span class="k">_</span> <span class="o">-</span> <span class="n">amount</span><span class="o">)</span> <span class="o">&gt;&gt;</span>
                <span class="nv">balance</span><span class="o">.</span><span class="py">get</span><span class="o">.</span><span class="py">flatMap</span><span class="o">(</span><span class="n">newBalance</span> <span class="k">=&gt;</span>
                  <span class="nv">IO</span><span class="o">.</span><span class="py">println</span><span class="o">(</span>
                    <span class="n">s</span><span class="s">"[${context.self.path.name}] Withdrew $amount from $walletId. New balance: $newBalance"</span>
                  <span class="o">)</span> <span class="o">&gt;&gt;</span>
                    <span class="nv">replyTo</span><span class="o">.</span><span class="py">fold</span><span class="o">(</span><span class="nv">IO</span><span class="o">.</span><span class="py">unit</span><span class="o">)(</span><span class="k">_</span> <span class="o">!</span> <span class="nc">Balance</span><span class="o">(</span><span class="n">newBalance</span><span class="o">))</span>
                <span class="o">)</span>
            <span class="o">}</span> <span class="k">else</span> <span class="nv">replyTo</span><span class="o">.</span><span class="py">fold</span><span class="o">(</span><span class="nv">IO</span><span class="o">.</span><span class="py">unit</span><span class="o">)(</span><span class="k">_</span> <span class="o">!</span> <span class="nc">TransactionFailed</span><span class="o">(</span><span class="n">s</span><span class="s">"Insufficient funds in $walletId"</span><span class="o">))</span>
          <span class="o">}</span>

        <span class="k">case</span> <span class="nc">GetBalance</span><span class="o">(</span><span class="n">replyTo</span><span class="o">)</span> <span class="k">=&gt;</span>
          <span class="k">for</span> <span class="o">{</span>
            <span class="n">currentBalance</span> <span class="k">&lt;-</span> <span class="nv">balance</span><span class="o">.</span><span class="py">get</span>
            <span class="k">_</span> <span class="k">&lt;-</span> <span class="n">replyTo</span> <span class="o">!</span> <span class="nc">Balance</span><span class="o">(</span><span class="n">currentBalance</span><span class="o">)</span>
          <span class="o">}</span> <span class="nf">yield</span> <span class="o">()</span>
      <span class="o">}</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<h3 id="breaking-down-the-walletactor">Breaking Down the WalletActor</h3>

<p>The <code class="language-plaintext highlighter-rouge">WalletActor</code> handles three main commands:</p>

<ol>
  <li>
    <p><strong>GetBalance</strong>: This command is used to query the current balance of the wallet. It takes an <code class="language-plaintext highlighter-rouge">ActorRef</code> that will receive the balance as a response.</p>

    <div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">case</span> <span class="k">class</span> <span class="nc">GetBalance</span><span class="o">(</span><span class="n">replyTo</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span>, <span class="kt">Balance</span><span class="o">])</span> <span class="k">extends</span> <span class="nc">Command</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Deposit</strong>: This command adds a specified amount to the wallet’s balance. It also optionally takes an <code class="language-plaintext highlighter-rouge">ActorRef</code> to send a response indicating the new balance.</p>

    <div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">case</span> <span class="k">class</span> <span class="nc">Deposit</span><span class="o">(</span><span class="n">amount</span><span class="k">:</span> <span class="kt">BigDecimal</span><span class="o">,</span> <span class="n">replyTo</span><span class="k">:</span> <span class="kt">Option</span><span class="o">[</span><span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span>, <span class="kt">Response</span><span class="o">]])</span> <span class="k">extends</span> <span class="nc">Command</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Withdraw</strong>: This command deducts a specified amount from the wallet’s balance if there are sufficient funds. It can also take an <code class="language-plaintext highlighter-rouge">ActorRef</code> for response purposes.</p>

    <div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">case</span> <span class="k">class</span> <span class="nc">Withdraw</span><span class="o">(</span><span class="n">amount</span><span class="k">:</span> <span class="kt">BigDecimal</span><span class="o">,</span> <span class="n">replyTo</span><span class="k">:</span> <span class="kt">Option</span><span class="o">[</span><span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span>, <span class="kt">Response</span><span class="o">]])</span> <span class="k">extends</span> <span class="nc">Command</span>
</code></pre></div>    </div>
  </li>
</ol>

<p>Responses include the current balance and a transaction failure message if something goes wrong:</p>

<ul>
  <li><strong>TransactionFailed</strong>: Indicates a failed transaction with a reason.</li>
  <li><strong>Balance</strong>: Represents the current balance of the wallet.</li>
</ul>

<p>The create method initializes the <code class="language-plaintext highlighter-rouge">WalletActor</code> with a starting balance of 0. Its <code class="language-plaintext highlighter-rouge">receive</code> method is strictly typed to handle only <code class="language-plaintext highlighter-rouge">Command</code> messages, ensuring type safety and minimizing runtime errors.</p>

<h2 id="the-transactionactor-coordinating-the-transfer-money_mouth_face">The TransactionActor: Coordinating the Transfer :money_mouth_face:</h2>

<p>With Alice and Bob’s wallets all set, it’s time to master the art of money transfer. The <code class="language-plaintext highlighter-rouge">TransactionActor</code> takes on the pivotal role of seamlessly managing transactions between them.</p>

<p>Before we dive into the code, let’s explore the intricate workings of the transaction state machine.</p>

<h3 id="the-transaction-state-machine-">The Transaction State Machine 🤖</h3>

<p>The <code class="language-plaintext highlighter-rouge">TransactionActor</code> takes charge of orchestrating the flow of a transaction between two wallets. The process involves the following states:</p>

<ol>
  <li><strong>PreStart</strong>: Initialization phase where the actor sends a withdrawal request to the source wallet.</li>
  <li><strong>awaitWithdraw</strong>: Waits for confirmation of the withdrawal from the source wallet.</li>
  <li><strong>awaitDeposit</strong>: Waits for confirmation of the deposit to the destination wallet.</li>
  <li><strong>Transaction Complete</strong>: Indicates that the transaction was successful and the actor can be stopped.</li>
  <li><strong>Transaction Failed</strong>: Indicates that the transaction failed, either during withdrawal or deposit, and the actor can be stopped.</li>
</ol>

<p>Here’s a state machine diagram to visualize this flow:</p>

<div class="mermaid">
stateDiagram
    PreStart: PreStart
    awaitWithdraw: awaitWithdraw
    awaitDeposit: awaitDeposit
    TransactionComplete: Transaction Complete
    TransactionFailed: Transaction Failed

    PreStart --&gt; awaitWithdraw: Send withdraw request
    awaitWithdraw --&gt; awaitDeposit: Withdraw successful
    awaitWithdraw --&gt; TransactionFailed: Withdraw failed
    awaitDeposit --&gt; TransactionComplete: Deposit successful
    awaitDeposit --&gt; TransactionFailed: Deposit failed
    TransactionFailed --&gt; [*]: Stop actor
    TransactionComplete --&gt; [*]: Stop actor
</div>

<h3 id="implementing-the-transactionactor">Implementing the TransactionActor</h3>
<p>With the state machine as our guide, let’s roll up our sleeves and bring the <code class="language-plaintext highlighter-rouge">TransactionActor</code> to life!</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">object</span> <span class="nc">TransactionActor</span> <span class="o">{</span>
  <span class="k">sealed</span> <span class="k">trait</span> <span class="nc">Response</span>
  <span class="k">case</span> <span class="k">class</span> <span class="nc">TransactionSuccess</span><span class="o">(</span><span class="n">transactionId</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span> <span class="k">extends</span> <span class="nc">Response</span>
  <span class="k">case</span> <span class="k">class</span> <span class="nc">TransactionFailed</span><span class="o">(</span><span class="n">reason</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span> <span class="k">extends</span> <span class="nc">Response</span>

  <span class="k">def</span> <span class="nf">create</span><span class="o">(</span>
      <span class="n">transactionId</span><span class="k">:</span> <span class="kt">String</span><span class="o">,</span>
      <span class="n">parent</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span>, <span class="kt">Response</span><span class="o">],</span>
      <span class="n">fromWallet</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span>, <span class="kt">WalletActor.Command</span><span class="o">],</span>
      <span class="n">toWallet</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span>, <span class="kt">WalletActor.Command</span><span class="o">],</span>
      <span class="n">amount</span><span class="k">:</span> <span class="kt">BigDecimal</span>
  <span class="o">)</span><span class="k">:</span> <span class="kt">Actor</span><span class="o">[</span><span class="kt">IO</span>, <span class="kt">Nothing</span><span class="o">]</span> <span class="k">=</span> <span class="k">new</span> <span class="nc">Actor</span><span class="o">[</span><span class="kt">IO</span>, <span class="kt">Nothing</span><span class="o">]</span> <span class="o">{</span>

    <span class="k">override</span> <span class="k">def</span> <span class="nf">preStart</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span> <span class="k">=</span> <span class="k">for</span> <span class="o">{</span>
      <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">IO</span><span class="o">.</span><span class="py">println</span><span class="o">(</span>
        <span class="n">s</span><span class="s">"~~~ [Tx: $transactionId] =&gt; Sending withdraw request to [${fromWallet.path.name}].  Awaiting confirmation.  ~~~"</span>
      <span class="o">)</span>
      <span class="k">_</span> <span class="k">&lt;-</span> <span class="n">fromWallet</span> <span class="o">!</span> <span class="nv">WalletActor</span><span class="o">.</span><span class="py">Withdraw</span><span class="o">(</span><span class="n">amount</span><span class="o">,</span> <span class="nv">context</span><span class="o">.</span><span class="py">self</span><span class="o">.</span><span class="py">widenRequest</span><span class="o">.</span><span class="py">some</span><span class="o">)</span>
      <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">become</span><span class="o">(</span><span class="n">awaitWithdraw</span><span class="o">)</span>
    <span class="o">}</span> <span class="nf">yield</span> <span class="o">()</span>

    <span class="k">def</span> <span class="nf">awaitWithdraw</span><span class="k">:</span> <span class="kt">Receive</span><span class="o">[</span><span class="kt">IO</span>, <span class="kt">WalletActor.Response</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
      <span class="k">case</span> <span class="nv">WalletActor</span><span class="o">.</span><span class="py">Balance</span><span class="o">(</span><span class="k">_</span><span class="o">)</span> <span class="k">=&gt;</span>
        <span class="k">for</span> <span class="o">{</span>
          <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">IO</span><span class="o">.</span><span class="py">println</span><span class="o">(</span>
            <span class="n">s</span><span class="s">"~~~ [Tx: $transactionId] =&gt; Withdraw from [${fromWallet.path.name}] confirmed.  Depositing to [${toWallet.path.name}]. ~~~"</span>
          <span class="o">)</span>
          <span class="k">_</span> <span class="k">&lt;-</span> <span class="n">toWallet</span> <span class="o">!</span> <span class="nv">WalletActor</span><span class="o">.</span><span class="py">Deposit</span><span class="o">(</span><span class="n">amount</span><span class="o">,</span> <span class="nv">context</span><span class="o">.</span><span class="py">self</span><span class="o">.</span><span class="py">widenRequest</span><span class="o">.</span><span class="py">some</span><span class="o">)</span>
          <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">become</span><span class="o">(</span><span class="n">awaitDeposit</span><span class="o">)</span>
        <span class="o">}</span> <span class="nf">yield</span> <span class="o">()</span>

      <span class="k">case</span> <span class="nv">WalletActor</span><span class="o">.</span><span class="py">TransactionFailed</span><span class="o">(</span><span class="n">reason</span><span class="o">)</span> <span class="k">=&gt;</span>
        <span class="n">parent</span> <span class="o">!</span> <span class="nc">TransactionFailed</span><span class="o">(</span><span class="n">s</span><span class="s">"Withdraw from source wallet failed: $reason"</span><span class="o">)</span>
        <span class="nv">context</span><span class="o">.</span><span class="py">stop</span><span class="o">(</span><span class="nv">context</span><span class="o">.</span><span class="py">self</span><span class="o">)</span>
    <span class="o">}</span>

    <span class="k">def</span> <span class="nf">awaitDeposit</span><span class="k">:</span> <span class="kt">Receive</span><span class="o">[</span><span class="kt">IO</span>, <span class="kt">WalletActor.Response</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
      <span class="k">case</span> <span class="nv">WalletActor</span><span class="o">.</span><span class="py">Balance</span><span class="o">(</span><span class="k">_</span><span class="o">)</span> <span class="k">=&gt;</span>
        <span class="k">for</span> <span class="o">{</span>
          <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">IO</span><span class="o">.</span><span class="py">println</span><span class="o">(</span>
            <span class="n">s</span><span class="s">"~~~ [Tx: $transactionId] =&gt; Deposit to [${toWallet.path.name}] confirmed.  Killing actor - transaction complete! ~~~"</span>
          <span class="o">)</span>
          <span class="k">_</span> <span class="k">&lt;-</span> <span class="n">parent</span> <span class="o">!</span> <span class="nc">TransactionSuccess</span><span class="o">(</span><span class="n">transactionId</span><span class="o">)</span>
          <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">stop</span><span class="o">(</span><span class="nv">context</span><span class="o">.</span><span class="py">self</span><span class="o">)</span>
        <span class="o">}</span> <span class="nf">yield</span> <span class="o">()</span>

      <span class="k">case</span> <span class="nv">WalletActor</span><span class="o">.</span><span class="py">TransactionFailed</span><span class="o">(</span><span class="n">reason</span><span class="o">)</span> <span class="k">=&gt;</span>
        <span class="n">parent</span> <span class="o">!</span> <span class="nc">TransactionFailed</span><span class="o">(</span><span class="n">s</span><span class="s">"Deposit to destination wallet failed: $reason"</span><span class="o">)</span>
        <span class="nv">context</span><span class="o">.</span><span class="py">stop</span><span class="o">(</span><span class="nv">context</span><span class="o">.</span><span class="py">self</span><span class="o">)</span>
    <span class="o">}</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<h1 id="lights-camera-action-clapper">Lights, Camera, Action! :clapper:</h1>
<p>It’s showtime for our main application! Here, we’ll orchestrate the entire ensemble: setting up the actor system, casting wallet actors for Alice and Bob, and kickstart a thrilling transaction between them. Plus, we’ve got a backstage reporter actor to capture all the action and reactions!</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">object</span> <span class="nc">Main</span> <span class="k">extends</span> <span class="nc">IOApp</span> <span class="o">{</span>
  <span class="k">def</span> <span class="nf">run</span><span class="o">(</span><span class="n">args</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">String</span><span class="o">])</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">ExitCode</span><span class="o">]</span> <span class="k">=</span>
    <span class="nc">ActorSystem</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="s">"actor-system"</span><span class="o">).</span><span class="py">use</span> <span class="o">{</span> <span class="n">system</span> <span class="k">=&gt;</span>
      <span class="k">for</span> <span class="o">{</span>
        <span class="n">auditor</span> <span class="k">&lt;-</span> <span class="nv">system</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="k">new</span> <span class="nc">Actor</span><span class="o">[</span><span class="kt">IO</span>, <span class="kt">Any</span><span class="o">]</span> <span class="o">{</span>
          <span class="k">override</span> <span class="k">def</span> <span class="nf">receive</span><span class="k">:</span> <span class="kt">Receive</span><span class="o">[</span><span class="kt">IO</span>, <span class="kt">Any</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span> <span class="k">case</span> <span class="n">response</span> <span class="k">=&gt;</span>
            <span class="k">val</span> <span class="nv">sender</span><span class="k">:</span> <span class="kt">String</span> <span class="o">=</span> <span class="nv">context</span><span class="o">.</span><span class="py">sender</span><span class="o">.</span><span class="py">map</span><span class="o">(</span><span class="nv">_</span><span class="o">.</span><span class="py">path</span><span class="o">.</span><span class="py">name</span><span class="o">).</span><span class="py">getOrElse</span><span class="o">(</span><span class="s">"N/A"</span><span class="o">)</span>
            <span class="nv">IO</span><span class="o">.</span><span class="py">println</span><span class="o">(</span><span class="n">s</span><span class="s">"[From: $sender] =&gt; $response"</span><span class="o">)</span>
          <span class="o">}</span>
        <span class="o">},</span> <span class="s">"reporter"</span><span class="o">)</span>

        <span class="n">alice</span> <span class="k">&lt;-</span> <span class="nv">system</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nv">WalletActor</span><span class="o">.</span><span class="py">create</span><span class="o">(</span><span class="s">"alice"</span><span class="o">),</span> <span class="s">"alice-actor"</span><span class="o">)</span>
        <span class="k">_</span> <span class="k">&lt;-</span> <span class="n">alice</span> <span class="o">!</span> <span class="nc">Deposit</span><span class="o">(</span><span class="mi">100</span><span class="o">,</span> <span class="nv">auditor</span><span class="o">.</span><span class="py">some</span><span class="o">)</span>

        <span class="n">bob</span> <span class="k">&lt;-</span> <span class="nv">system</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nv">WalletActor</span><span class="o">.</span><span class="py">create</span><span class="o">(</span><span class="s">"bob"</span><span class="o">),</span> <span class="s">"bob-actor"</span><span class="o">)</span>

        <span class="c1">// The transaction actor does not receive any messages, it coordinates flow between two actors.</span>
        <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">system</span><span class="o">.</span><span class="py">actorOf</span><span class="o">[</span><span class="kt">Nothing</span><span class="o">](</span>
          <span class="nv">TransactionActor</span><span class="o">.</span><span class="py">create</span><span class="o">(</span><span class="s">"alice-&gt;bob::1"</span><span class="o">,</span> <span class="n">auditor</span><span class="o">,</span> <span class="n">alice</span><span class="o">,</span> <span class="n">bob</span><span class="o">,</span> <span class="nc">BigDecimal</span><span class="o">(</span><span class="mi">100</span><span class="o">)),</span> <span class="s">"tx-coordinator"</span>
        <span class="o">)</span>

        <span class="c1">// Retrieve the new balances</span>
        <span class="k">_</span> <span class="k">&lt;-</span> <span class="n">alice</span> <span class="o">!</span> <span class="nc">GetBalance</span><span class="o">(</span><span class="n">auditor</span><span class="o">)</span>
        <span class="k">_</span> <span class="k">&lt;-</span> <span class="n">bob</span> <span class="o">!</span> <span class="nc">GetBalance</span><span class="o">(</span><span class="n">auditor</span><span class="o">)</span>

      <span class="o">}</span> <span class="k">yield</span> <span class="nv">ExitCode</span><span class="o">.</span><span class="py">Success</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<h3 id="the-workflow-step-by-step-rocket">The Workflow: Step by Step :rocket:</h3>

<ol>
  <li><strong>Initialization</strong>: The <code class="language-plaintext highlighter-rouge">ActorSystem</code> is set up, and a <code class="language-plaintext highlighter-rouge">reporter</code> actor is created to log actions and results.</li>
  <li><strong>Creating Wallets</strong>: Wallet actors for Alice and Bob are created, and an initial deposit is made to Alice.</li>
  <li><strong>Transaction Coordination</strong>: A <code class="language-plaintext highlighter-rouge">TransactionActor</code> is created to manage the transfer of 100 units from Alice’s wallet to Bob’s. The coordinator sends a withdrawal request to Alice’s wallet and, upon confirmation, sends a deposit request to Bob’s wallet.</li>
  <li><strong>Logging Results</strong>: The <code class="language-plaintext highlighter-rouge">reporter</code> actor logs the balance of each wallet after the transaction is complete.</li>
</ol>

<h3 id="sample-output-and-logs-explanation-log">Sample Output and Logs Explanation :log:</h3>
<p>Below is a snapshot of what you might see when running the application, along with detailed explanations for each log entry:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[</span>alice-actor] Deposited 100 to alice. New balance: 100.0
<span class="o">[</span>From: alice-actor] <span class="o">=&gt;</span> Balance<span class="o">(</span>100.0<span class="o">)</span>
<span class="o">[</span>alice-actor] Withdrew 100 from alice. New balance: 0.0
~~~ <span class="o">[</span>Tx: alice-&gt;bob::1] <span class="o">=&gt;</span> Withdraw from <span class="o">[</span>alice-actor] confirmed.  Depositing to <span class="o">[</span>bob-actor]. ~~~
<span class="o">[</span>From: alice-actor] <span class="o">=&gt;</span> Balance<span class="o">(</span>0.0<span class="o">)</span>
<span class="o">[</span>From: bob-actor] <span class="o">=&gt;</span> Balance<span class="o">(</span>0.0<span class="o">)</span>
<span class="o">[</span>bob-actor] Deposited 100 to bob. New balance: 100.0
~~~ <span class="o">[</span>Tx: alice-&gt;bob::1] <span class="o">=&gt;</span> Deposit to <span class="o">[</span>bob-actor] confirmed.  Killing actor - transaction <span class="nb">complete</span><span class="o">!</span> ~~~
</code></pre></div></div>

<ul>
  <li><code class="language-plaintext highlighter-rouge">~~~ [Tx: alice-&gt;bob::1] =&gt; Sending withdraw request to [alice-actor].  Awaiting confirmation.  ~~~</code>: The transaction actor initiates the withdrawal from Alice’s wallet.</li>
  <li><code class="language-plaintext highlighter-rouge">[alice-actor] Deposited 100 to alice. New balance: 100.0</code>: Alice’s wallet receives a deposit of 100 units.</li>
  <li><code class="language-plaintext highlighter-rouge">[From: alice-actor] =&gt; Balance(100.0)</code>: The reporter logs the balance of Alice’s wallet.</li>
  <li><code class="language-plaintext highlighter-rouge">[alice-actor] Withdrew 100 from alice. New balance: 0.0</code>: Alice’s wallet processes the withdrawal.</li>
  <li><code class="language-plaintext highlighter-rouge">~~~ [Tx: alice-&gt;bob::1] =&gt; Withdraw from [alice-actor] confirmed.  Depositing to [bob-actor]. ~~~</code>: The transaction actor confirms the withdrawal and starts the deposit to Bob’s wallet.</li>
  <li><code class="language-plaintext highlighter-rouge">[From: alice-actor] =&gt; Balance(0.0)</code>: The reporter logs the updated balance of Alice’s wallet.</li>
  <li><code class="language-plaintext highlighter-rouge">[From: bob-actor] =&gt; Balance(0.0)</code>: The reporter logs the initial balance of Bob’s wallet.</li>
  <li><code class="language-plaintext highlighter-rouge">[bob-actor] Deposited 100 to bob. New balance: 100.0</code>: Bob’s wallet receives the deposit.</li>
  <li><code class="language-plaintext highlighter-rouge">~~~ [Tx: alice-&gt;bob::1] =&gt; Deposit to [bob-actor] confirmed.  Killing actor - transaction complete! ~~~</code>: The transaction actor confirms the deposit and completes the transaction.</li>
</ul>

<h1 id="conclusion-tada">Conclusion :tada:</h1>
<p>With the release of Cats-Actors 2.0.0-RC1, typed actors bring a new level of safety and clarity to actor-based programming in Scala. This example demonstrated a classic Alice-to-Bob transaction, showcasing the simplicity and effectiveness of typed actors. Whether you’re building simple applications or complex distributed systems, typed actors can help you write more reliable and maintainable code.</p>

<p>Try it out for yourself, and explore the possibilities that typed actors open up in your projects! :rocket:</p>

<p>As always, stay safe, keep hacking!</p>]]></content><author><name>Mark Galea</name></author><summary type="html"><![CDATA[Today marks an exciting milestone with the release of Cats-Actors 2.0.0-RC1. This version introduces typed actors, a feature that the community has eagerly awaited. To showcase this new capability, we’ll walk through a classic example of handling wallet transactions between two users, Alice and Bob. So, sit back and relax as we explore how Alice sends money to Bob using typed actors in Cats-Actors.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://cloudmark.github.io/images/cats-actors/logo-small.png" /><media:content medium="image" url="http://cloudmark.github.io/images/cats-actors/logo-small.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">A Logic Circuit Simulator with Cats-Actors</title><link href="http://cloudmark.github.io/Cats-Actors/" rel="alternate" type="text/html" title="A Logic Circuit Simulator with Cats-Actors" /><published>2024-06-14T00:00:00+00:00</published><updated>2024-06-14T00:00:00+00:00</updated><id>http://cloudmark.github.io/Cats-Actors</id><content type="html" xml:base="http://cloudmark.github.io/Cats-Actors/"><![CDATA[<p><img class="title" src="/images/cats-actors/logo-small.png" />
Functional programming and the actor model are two powerful paradigms in modern software development. They might seem like they’re in opposition, but in reality, they complement each other beautifully. Scala, as a versatile language, allows multiple paradigms to coexist, and Cats-Actors, a functional programming-based actor system, exemplifies this harmony. Cats-Actors is a reimagining of the actor paradigm model married with the functional paradigm.</p>

<p>Imagine you’re working at ACME Inc., where your task is to create a logic circuit verifier to ensure the reliability of their motherboards. These motherboards will be used in a mission to launch cats into space, and no one wants these feline astronauts to be at risk. You’ve been tasked with developing a logic circuit simulator that accounts for the internal delays of digital circuits, ensuring that all signals stabilize on each clock tick. We certainly don’t want a motherboard with AND gates still transitioning when it’s time to read the values. So, gear up, and let’s embark on this Cats-Actors adventure to build a robust logic circuit simulator and ensure those kittens have a safe sendoff!</p>

<h2 id="setting-up-your-project">Setting Up Your Project</h2>

<p>To get started with Cats-Actors, you need to set up your Scala project with the necessary dependencies. Add the
following to your <code class="language-plaintext highlighter-rouge">build.sbt</code> file:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">resolvers</span> <span class="o">+=</span> <span class="s">"JitPack"</span> <span class="n">at</span> <span class="s">"https://jitpack.io"</span>

<span class="n">libraryDependencies</span> <span class="o">+=</span> <span class="s">"com.github.suprnation"</span> <span class="o">%</span> <span class="s">"cats-actors_2.13"</span> <span class="o">%</span> <span class="s">"1.0.1"</span>
</code></pre></div></div>

<blockquote>
  <p>For a complete listing of all code samples and to clone the project, visit the <a href="https://github.com/cloudmark/cats-actor-sample">GitHub repository</a>.</p>
</blockquote>

<h1 id="understanding-the-actor-model">Understanding the Actor Model</h1>
<p>Before we dive into building our logic circuit simulator, let’s take a moment to understand the actor model. Imagine
actors as independent workers in a factory. Each worker has their own tasks and responsibilities, and they communicate
with each other by passing messages. This setup ensures that no one is stepping on anyone else’s toes, making it easier
to build systems that are both concurrent and fault-tolerant.</p>

<p>In the Cats-Actors framework, these actors get an extra boost from functional programming principles. This means our
actors will use immutable data and pure functions, making our system more predictable and easier to maintain.</p>

<p>So, what can actors do in this model?</p>

<ol>
  <li><strong>Send Messages</strong>: Just like sending a text, actors communicate by sending messages to each other. Each actor has a
mailbox where it receives these messages.</li>
  <li><strong>Create Actors</strong>: Need more hands on deck? Actors can create new actors to help with tasks.</li>
  <li><strong>Change Behavior</strong>: Actors can switch up their behavior based on the messages they get, allowing them to adapt to
different situations.</li>
</ol>

<p>By combining the actor model with functional programming, we get the best of both worlds. This synergy helps us build
systems that are robust, scalable, and easy to maintain.</p>

<h1 id="building-our-logic-circuit-simulator">Building Our Logic Circuit Simulator</h1>
<p>In this section, we’ll start building the core components of our logic circuit simulator using Cats-Actors. Our goal is to construct various logic gates and combine them to simulate complex circuits. Let’s break down the components and build them step by step.</p>

<p>First, we’ll start by creating the Wire actor, which will transport signals. After that, we’ll create basic logic gates like AND, OR, and an alternative OR gate using De Morgan’s laws. We’ll then combine these gates into more complex components such as Half Adders and Full Adders, and finally, we’ll build Demultiplexers.</p>

<p>Ready? Let’s dive in.</p>

<h2 id="1-creating-the-wire-actor">1. Creating the Wire Actor</h2>
<p>The Wire actor is responsible for transporting signals, which can be either true (high voltage) or false (low voltage). It allows component actors to subscribe to state changes and notifies them whenever its state changes.</p>

<p>Here’s the code for the Wire actor:</p>
<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">wire</span><span class="o">(</span><span class="nc">_currentState</span><span class="k">:</span> <span class="kt">Boolean</span><span class="o">)</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Actor</span><span class="o">[</span><span class="kt">IO</span><span class="o">]]</span> <span class="k">=</span> <span class="o">{</span>
      <span class="k">for</span> <span class="o">{</span>
        <span class="n">associationsRef</span> <span class="k">&lt;-</span> <span class="nc">Ref</span><span class="o">[</span><span class="kt">IO</span><span class="o">].</span><span class="py">of</span><span class="o">(</span><span class="nv">Map</span><span class="o">.</span><span class="py">empty</span><span class="o">[</span><span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">]</span>, <span class="kt">String</span><span class="o">])</span>
        <span class="n">currentStateRef</span> <span class="k">&lt;-</span> <span class="nc">Ref</span><span class="o">[</span><span class="kt">IO</span><span class="o">].</span><span class="py">of</span><span class="o">(</span><span class="nc">_currentState</span><span class="o">)</span>
      <span class="o">}</span> <span class="k">yield</span> <span class="k">new</span> <span class="nc">Actor</span><span class="o">[</span><span class="kt">IO</span><span class="o">]</span> <span class="o">{</span>
        <span class="k">override</span> <span class="k">def</span> <span class="nf">receive</span><span class="k">:</span> <span class="kt">Receive</span><span class="o">[</span><span class="kt">IO</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
          <span class="k">case</span> <span class="nc">AddComponent</span><span class="o">(</span><span class="n">name</span><span class="k">:</span> <span class="kt">String</span><span class="o">,</span> <span class="n">b</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">])</span> <span class="k">=&gt;</span>
            <span class="k">for</span> <span class="o">{</span>
              <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">associationsRef</span><span class="o">.</span><span class="py">update</span><span class="o">(</span><span class="k">_</span> <span class="o">+</span> <span class="o">(</span><span class="n">b</span> <span class="o">-&gt;</span> <span class="n">name</span><span class="o">))</span>
              <span class="n">currentState</span> <span class="k">&lt;-</span> <span class="nv">currentStateRef</span><span class="o">.</span><span class="py">get</span>
              <span class="k">_</span> <span class="k">&lt;-</span> <span class="n">b</span> <span class="o">!</span> <span class="nc">StateChange</span><span class="o">(</span><span class="n">name</span><span class="o">,</span> <span class="n">currentState</span><span class="o">)</span>
            <span class="o">}</span> <span class="nf">yield</span> <span class="o">()</span>

          <span class="k">case</span> <span class="nc">GetValue</span> <span class="k">=&gt;</span> <span class="nv">currentStateRef</span><span class="o">.</span><span class="py">get</span>

          <span class="k">case</span> <span class="n">s</span><span class="k">:</span> <span class="kt">Boolean</span> <span class="o">=&gt;</span>
            <span class="nv">currentStateRef</span><span class="o">.</span><span class="py">get</span><span class="o">.</span><span class="py">map</span><span class="o">(</span><span class="k">_</span> <span class="o">!=</span> <span class="n">s</span><span class="o">).</span><span class="py">ifM</span><span class="o">(</span>
              <span class="k">for</span> <span class="o">{</span>
                <span class="n">currentState</span> <span class="k">&lt;-</span> <span class="nv">currentStateRef</span><span class="o">.</span><span class="py">updateAndGet</span><span class="o">(</span><span class="k">_</span> <span class="k">=&gt;</span> <span class="n">s</span><span class="o">)</span>
                <span class="n">associations</span> <span class="k">&lt;-</span> <span class="nv">associationsRef</span><span class="o">.</span><span class="py">get</span>
                <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">associations</span><span class="o">.</span><span class="py">toList</span><span class="o">.</span><span class="py">parTraverse_</span> <span class="o">{</span> 
                  <span class="nf">case</span> <span class="o">(</span><span class="n">ref</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">],</span> <span class="n">name</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span> <span class="k">=&gt;</span>
                     <span class="n">ref</span> <span class="o">!</span> <span class="nc">StateChange</span><span class="o">(</span><span class="n">name</span><span class="o">,</span> <span class="n">currentState</span><span class="o">)</span>
                <span class="o">}</span>
              <span class="o">}</span> <span class="nf">yield</span> <span class="o">(),</span>
              <span class="nv">IO</span><span class="o">.</span><span class="py">unit</span>
         <span class="o">)</span>
     <span class="o">}</span>
   <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>In this code, the Wire actor maintains its current state (<code class="language-plaintext highlighter-rouge">currentState</code>) and a map of associations where each entry maps a subscribing actor to a wire name. When it receives an <code class="language-plaintext highlighter-rouge">AddComponent</code> message, it adds the subscribing actor to its associations and sends the current state to the subscriber. When it receives a boolean value, it updates its state and notifies all subscribed components if the state has changed. Broadcasting state changes to all associations is done in parallel using <code class="language-plaintext highlighter-rouge">parTraverse_</code>.</p>

<h1 id="2-creating-the-basic-logic-gates">2. Creating the Basic Logic Gates</h1>
<p>Now, let’s move on to creating the logic gates. We’ll start with the NOT gate (Inverter). The Inverter actor will take an input and output the inverted result after a delay.</p>

<p>Here’s the code for the Inverter actor:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">inverter</span><span class="o">(</span><span class="n">input</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">],</span> <span class="n">output</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">])</span><span class="k">:</span> <span class="kt">Actor</span><span class="o">[</span><span class="kt">IO</span><span class="o">]</span> <span class="k">=</span> <span class="k">new</span> <span class="nc">Actor</span><span class="o">[</span><span class="kt">IO</span><span class="o">]</span> <span class="o">{</span>
  <span class="k">override</span> <span class="k">def</span> <span class="nf">preStart</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
    <span class="n">input</span> <span class="o">!</span> <span class="nc">AddComponent</span><span class="o">(</span><span class="s">"in"</span><span class="o">,</span> <span class="n">self</span><span class="o">)</span>
  <span class="o">}</span>

  <span class="k">override</span> <span class="k">val</span> <span class="nv">receive</span><span class="k">:</span> <span class="kt">Actor.Receive</span><span class="o">[</span><span class="kt">IO</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
    <span class="k">case</span> <span class="nc">StateChange</span><span class="o">(</span><span class="k">_</span><span class="o">,</span> <span class="n">s</span><span class="k">:</span> <span class="kt">Boolean</span><span class="o">)</span> <span class="k">=&gt;</span>
      <span class="o">(</span><span class="nv">IO</span><span class="o">.</span><span class="py">sleep</span><span class="o">(</span><span class="n">inverterDelay</span><span class="o">)</span> <span class="o">&gt;&gt;</span> <span class="o">(</span><span class="n">output</span> <span class="o">!</span> <span class="o">(!</span><span class="n">s</span><span class="o">))).</span><span class="py">start</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">inverter</code> actor registers itself with the input wire, receiving updates under the name “in”. When it receives a state change, it waits for the inverter delay before sending the inverted signal to the output. This process is run in the background using <code class="language-plaintext highlighter-rouge">start</code>, allowing the actor to continue processing other messages.</p>

<p>Next, we’ll create the AND gate. The And actor will take two inputs and output the result of their AND operation.</p>

<p>Here’s the code for the And actor:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">and</span><span class="o">(</span><span class="n">input0</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">],</span> <span class="n">input1</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">],</span> <span class="n">output</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">])</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Actor</span><span class="o">[</span><span class="kt">IO</span><span class="o">]]</span> <span class="k">=</span> <span class="o">{</span>
  <span class="k">for</span> <span class="o">{</span>
    <span class="n">in0</span> <span class="k">&lt;-</span> <span class="nc">Ref</span><span class="o">[</span><span class="kt">IO</span><span class="o">].</span><span class="py">of</span><span class="o">[</span><span class="kt">Option</span><span class="o">[</span><span class="kt">Boolean</span><span class="o">]](</span><span class="nc">None</span><span class="o">)</span>
    <span class="n">in1</span> <span class="k">&lt;-</span> <span class="nc">Ref</span><span class="o">[</span><span class="kt">IO</span><span class="o">].</span><span class="py">of</span><span class="o">[</span><span class="kt">Option</span><span class="o">[</span><span class="kt">Boolean</span><span class="o">]](</span><span class="nc">None</span><span class="o">)</span>
  <span class="o">}</span> <span class="k">yield</span> <span class="k">new</span> <span class="nc">Actor</span><span class="o">[</span><span class="kt">IO</span><span class="o">]</span> <span class="o">{</span>
    <span class="k">override</span> <span class="k">def</span> <span class="nf">preStart</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
      <span class="o">(</span><span class="n">input0</span> <span class="o">!</span> <span class="nc">AddComponent</span><span class="o">(</span><span class="s">"in0"</span><span class="o">,</span> <span class="n">self</span><span class="o">),</span> 
       <span class="n">input1</span> <span class="o">!</span> <span class="nc">AddComponent</span><span class="o">(</span><span class="s">"in1"</span><span class="o">,</span> <span class="n">self</span><span class="o">)).</span><span class="py">parTupled</span><span class="o">.</span><span class="py">void</span>
    <span class="o">}</span>

    <span class="k">override</span> <span class="k">val</span> <span class="nv">receive</span><span class="k">:</span> <span class="kt">Actor.Receive</span><span class="o">[</span><span class="kt">IO</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
      <span class="k">case</span> <span class="nc">StateChange</span><span class="o">(</span><span class="s">"in0"</span><span class="o">,</span> <span class="n">b</span><span class="k">:</span> <span class="kt">Boolean</span><span class="o">)</span> <span class="k">=&gt;</span> <span class="nv">in0</span><span class="o">.</span><span class="py">set</span><span class="o">(</span><span class="nv">b</span><span class="o">.</span><span class="py">some</span><span class="o">)</span> <span class="o">&gt;&gt;</span> <span class="nv">sendMessage</span><span class="o">.</span><span class="py">start</span>
      <span class="k">case</span> <span class="nc">StateChange</span><span class="o">(</span><span class="s">"in1"</span><span class="o">,</span> <span class="n">b</span><span class="k">:</span> <span class="kt">Boolean</span><span class="o">)</span> <span class="k">=&gt;</span> <span class="nv">in1</span><span class="o">.</span><span class="py">set</span><span class="o">(</span><span class="nv">b</span><span class="o">.</span><span class="py">some</span><span class="o">)</span> <span class="o">&gt;&gt;</span> <span class="nv">sendMessage</span><span class="o">.</span><span class="py">start</span>
    <span class="o">}</span>

    <span class="k">private</span> <span class="k">val</span> <span class="nv">sendMessage</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span> <span class="k">=</span>
      <span class="o">(</span><span class="nv">in0</span><span class="o">.</span><span class="py">get</span><span class="o">,</span> <span class="nv">in1</span><span class="o">.</span><span class="py">get</span><span class="o">).</span><span class="py">flatMapN</span> <span class="o">{</span>
        <span class="nf">case</span> <span class="o">(</span><span class="nc">Some</span><span class="o">(</span><span class="n">first</span><span class="o">),</span> <span class="nc">Some</span><span class="o">(</span><span class="n">second</span><span class="o">))</span> <span class="k">=&gt;</span>
          <span class="nv">IO</span><span class="o">.</span><span class="py">sleep</span><span class="o">(</span><span class="n">andDelay</span><span class="o">)</span> <span class="o">&gt;&gt;</span> <span class="o">(</span><span class="n">output</span> <span class="o">!</span> <span class="o">(</span><span class="n">first</span> <span class="o">&amp;&amp;</span> <span class="n">second</span><span class="o">))</span>
        <span class="k">case</span> <span class="k">_</span> <span class="k">=&gt;</span> <span class="nv">IO</span><span class="o">.</span><span class="py">unit</span>
      <span class="o">}</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>The AND actor listens for state changes from its two input wires. When either input changes, it checks if both inputs are true and sends the result to the output wire after a specified delay (<code class="language-plaintext highlighter-rouge">andDelay</code>). Note how the state changes are run in the background using <code class="language-plaintext highlighter-rouge">start</code>.</p>

<p>Similarly, we can create the OR actor, which outputs true if at least one input is true.</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">or</span><span class="o">(</span><span class="n">input0</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">],</span> <span class="n">input1</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">],</span> <span class="n">output</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">])</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Actor</span><span class="o">[</span><span class="kt">IO</span><span class="o">]]</span> <span class="k">=</span> <span class="o">{</span>
  <span class="k">for</span> <span class="o">{</span>
    <span class="n">in0</span> <span class="k">&lt;-</span> <span class="nc">Ref</span><span class="o">[</span><span class="kt">IO</span><span class="o">].</span><span class="py">of</span><span class="o">[</span><span class="kt">Option</span><span class="o">[</span><span class="kt">Boolean</span><span class="o">]](</span><span class="nc">None</span><span class="o">)</span>
    <span class="n">in1</span> <span class="k">&lt;-</span> <span class="nc">Ref</span><span class="o">[</span><span class="kt">IO</span><span class="o">].</span><span class="py">of</span><span class="o">[</span><span class="kt">Option</span><span class="o">[</span><span class="kt">Boolean</span><span class="o">]](</span><span class="nc">None</span><span class="o">)</span>
  <span class="o">}</span> <span class="k">yield</span> <span class="k">new</span> <span class="nc">Actor</span><span class="o">[</span><span class="kt">IO</span><span class="o">]</span> <span class="o">{</span>
    <span class="k">override</span> <span class="k">def</span> <span class="nf">preStart</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
      <span class="o">(</span><span class="n">input0</span> <span class="o">!</span> <span class="nc">AddComponent</span><span class="o">(</span><span class="s">"in0"</span><span class="o">,</span> <span class="n">self</span><span class="o">),</span> 
      <span class="n">input1</span> <span class="o">!</span> <span class="nc">AddComponent</span><span class="o">(</span><span class="s">"in1"</span><span class="o">,</span> <span class="n">self</span><span class="o">)).</span><span class="py">parTupled</span><span class="o">.</span><span class="py">void</span>
    <span class="o">}</span>

    <span class="k">override</span> <span class="k">val</span> <span class="nv">receive</span><span class="k">:</span> <span class="kt">Actor.Receive</span><span class="o">[</span><span class="kt">IO</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
      <span class="k">case</span> <span class="nc">StateChange</span><span class="o">(</span><span class="s">"in0"</span><span class="o">,</span> <span class="n">b</span><span class="k">:</span> <span class="kt">Boolean</span><span class="o">)</span> <span class="k">=&gt;</span> <span class="nv">in0</span><span class="o">.</span><span class="py">set</span><span class="o">(</span><span class="nv">b</span><span class="o">.</span><span class="py">some</span><span class="o">)</span> <span class="o">&gt;&gt;</span> <span class="nv">sendMessage</span><span class="o">.</span><span class="py">start</span>
      <span class="k">case</span> <span class="nc">StateChange</span><span class="o">(</span><span class="s">"in1"</span><span class="o">,</span> <span class="n">b</span><span class="k">:</span> <span class="kt">Boolean</span><span class="o">)</span> <span class="k">=&gt;</span> <span class="nv">in1</span><span class="o">.</span><span class="py">set</span><span class="o">(</span><span class="nv">b</span><span class="o">.</span><span class="py">some</span><span class="o">)</span> <span class="o">&gt;&gt;</span> <span class="nv">sendMessage</span><span class="o">.</span><span class="py">start</span>
    <span class="o">}</span>

    <span class="k">private</span> <span class="k">def</span> <span class="nf">sendMessage</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
      <span class="o">(</span><span class="nv">in0</span><span class="o">.</span><span class="py">get</span><span class="o">,</span> <span class="nv">in1</span><span class="o">.</span><span class="py">get</span><span class="o">).</span><span class="py">flatMapN</span> <span class="o">{</span>
        <span class="nf">case</span> <span class="o">(</span><span class="nc">Some</span><span class="o">(</span><span class="n">first</span><span class="o">),</span> <span class="nc">Some</span><span class="o">(</span><span class="n">second</span><span class="o">))</span> <span class="k">=&gt;</span>
          <span class="nv">IO</span><span class="o">.</span><span class="py">sleep</span><span class="o">(</span><span class="n">orDelay</span><span class="o">)</span> <span class="o">&gt;&gt;</span> <span class="o">(</span><span class="n">output</span> <span class="o">!</span> <span class="o">(</span><span class="n">first</span> <span class="o">||</span> <span class="n">second</span><span class="o">))</span>
        <span class="k">case</span> <span class="k">_</span> <span class="k">=&gt;</span> <span class="nv">IO</span><span class="o">.</span><span class="py">unit</span>
      <span class="o">}</span>
    <span class="o">}</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>The Or actor’s logic is very similar to the And actor’s logic. It registers with the input wires, listens for state changes, and sends the result to the output wire after the specified delay.</p>

<p>We can notice many commonalities between the And and Or actors. To eliminate redundancy, we can create a higher-order actor called <code class="language-plaintext highlighter-rouge">reducer</code>, which takes a reduction function and a delay as parameters. This actor will generalize the logic for creating gates with two inputs and one output.</p>

<p>Here’s the code for the <code class="language-plaintext highlighter-rouge">reducer</code>:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">reducer</span><span class="o">(</span><span class="n">reduceFn</span><span class="k">:</span> <span class="o">(</span><span class="kt">Boolean</span><span class="o">,</span> <span class="kt">Boolean</span><span class="o">)</span> <span class="k">=&gt;</span> <span class="nc">Boolean</span><span class="o">,</span> <span class="n">delay</span><span class="k">:</span> <span class="kt">Duration</span><span class="o">)</span>
            <span class="o">(</span><span class="n">input0</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">],</span><span class="n">input1</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">],</span> 
            <span class="n">output</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">]</span>
<span class="o">)</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Actor</span><span class="o">[</span><span class="kt">IO</span><span class="o">]]</span> <span class="k">=</span> <span class="o">{</span>
  <span class="k">for</span> <span class="o">{</span>
    <span class="n">in0</span> <span class="k">&lt;-</span> <span class="nc">Ref</span><span class="o">[</span><span class="kt">IO</span><span class="o">].</span><span class="py">of</span><span class="o">[</span><span class="kt">Option</span><span class="o">[</span><span class="kt">Boolean</span><span class="o">]](</span><span class="nc">None</span><span class="o">)</span>
    <span class="n">in1</span> <span class="k">&lt;-</span> <span class="nc">Ref</span><span class="o">[</span><span class="kt">IO</span><span class="o">].</span><span class="py">of</span><span class="o">[</span><span class="kt">Option</span><span class="o">[</span><span class="kt">Boolean</span><span class="o">]](</span><span class="nc">None</span><span class="o">)</span>
  <span class="o">}</span> <span class="k">yield</span> <span class="k">new</span> <span class="nc">Actor</span><span class="o">[</span><span class="kt">IO</span><span class="o">]</span> <span class="o">{</span>
    <span class="k">override</span> <span class="k">def</span> <span class="nf">preStart</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span> <span class="k">=</span>
      <span class="o">(</span><span class="n">input0</span> <span class="o">!</span> <span class="nc">AddComponent</span><span class="o">(</span><span class="s">"in0"</span><span class="o">,</span> <span class="n">self</span><span class="o">),</span> 
      <span class="n">input1</span> <span class="o">!</span> <span class="nc">AddComponent</span><span class="o">(</span><span class="s">"in1"</span><span class="o">,</span> <span class="n">self</span><span class="o">)).</span><span class="py">parTupled</span><span class="o">.</span><span class="py">void</span>

    <span class="k">override</span> <span class="k">val</span> <span class="nv">receive</span><span class="k">:</span> <span class="kt">Actor.Receive</span><span class="o">[</span><span class="kt">IO</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
      <span class="k">case</span> <span class="nc">StateChange</span><span class="o">(</span><span class="s">"in0"</span><span class="o">,</span> <span class="n">b</span><span class="k">:</span> <span class="kt">Boolean</span><span class="o">)</span> <span class="k">=&gt;</span> <span class="nv">in0</span><span class="o">.</span><span class="py">set</span><span class="o">(</span><span class="nv">b</span><span class="o">.</span><span class="py">some</span><span class="o">)</span> <span class="o">&gt;&gt;</span> <span class="nv">sendMessage</span><span class="o">.</span><span class="py">start</span>
      <span class="k">case</span> <span class="nc">StateChange</span><span class="o">(</span><span class="s">"in1"</span><span class="o">,</span> <span class="n">b</span><span class="k">:</span> <span class="kt">Boolean</span><span class="o">)</span> <span class="k">=&gt;</span> <span class="nv">in1</span><span class="o">.</span><span class="py">set</span><span class="o">(</span><span class="nv">b</span><span class="o">.</span><span class="py">some</span><span class="o">)</span> <span class="o">&gt;&gt;</span> <span class="nv">sendMessage</span><span class="o">.</span><span class="py">start</span>
    <span class="o">}</span>

    <span class="k">private</span> <span class="k">def</span> <span class="nf">sendMessage</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
      <span class="o">(</span><span class="nv">in0</span><span class="o">.</span><span class="py">get</span><span class="o">,</span> <span class="nv">in1</span><span class="o">.</span><span class="py">get</span><span class="o">).</span><span class="py">flatMapN</span> <span class="o">{</span>
        <span class="nf">case</span> <span class="o">(</span><span class="nc">Some</span><span class="o">(</span><span class="n">first</span><span class="o">),</span> <span class="nc">Some</span><span class="o">(</span><span class="n">second</span><span class="o">))</span> <span class="k">=&gt;</span>
          <span class="nv">IO</span><span class="o">.</span><span class="py">sleep</span><span class="o">(</span><span class="n">delay</span><span class="o">)</span> <span class="o">&gt;&gt;</span> <span class="o">(</span><span class="n">output</span> <span class="o">!</span> <span class="nf">reduceFn</span><span class="o">(</span><span class="n">first</span><span class="o">,</span> <span class="n">second</span><span class="o">))</span>
        <span class="k">case</span> <span class="k">_</span> <span class="k">=&gt;</span> <span class="nv">IO</span><span class="o">.</span><span class="py">unit</span>
      <span class="o">}</span>
    <span class="o">}</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Using this higher-order function, we can rewrite the AND and OR gates as follows:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">val</span> <span class="nv">and</span> <span class="k">=</span> <span class="nf">reducer</span><span class="o">(</span><span class="k">_</span> <span class="o">&amp;&amp;</span> <span class="k">_</span><span class="o">,</span> <span class="n">andDelay</span><span class="o">)(</span><span class="k">_</span><span class="o">,</span> <span class="k">_</span><span class="o">,</span> <span class="k">_</span><span class="o">)</span>
<span class="k">val</span> <span class="nv">or</span> <span class="k">=</span> <span class="nf">reducer</span><span class="o">(</span><span class="k">_</span> <span class="o">||</span> <span class="k">_</span><span class="o">,</span> <span class="n">orDelay</span><span class="o">)(</span><span class="k">_</span><span class="o">,</span> <span class="k">_</span><span class="o">,</span> <span class="k">_</span><span class="o">)</span>
</code></pre></div></div>

<p>This approach keeps the logic for the AND and OR gates intact while reducing redundancy.</p>

<p>Next, let’s create an alternative implementation of the OR gate using De Morgan’s laws, which, given the timings, will be more efficient. Chip manufacturers often specialize in certain gates to reduce production costs and make those gates super efficient. Other gates can be formed using De Morgan’s laws or truth table deductions. According to De Morgan’s laws:</p>

\[\begin{eqnarray*}
A \lor B &amp;=&amp; \neg(\neg A \land \neg B)
\end{eqnarray*}\]

<p>By using this transformation, we can create the <code class="language-plaintext highlighter-rouge">OrAlt</code> actor:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">orAlt</span><span class="o">(</span><span class="n">input0</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">],</span> <span class="n">input1</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">],</span> <span class="n">output</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">])</span><span class="k">:</span> <span class="kt">Actor</span><span class="o">[</span><span class="kt">IO</span><span class="o">]</span> <span class="k">=</span>
  <span class="k">new</span> <span class="nc">Actor</span><span class="o">[</span><span class="kt">IO</span><span class="o">]</span> <span class="o">{</span>
    <span class="k">override</span> <span class="k">val</span> <span class="nv">preStart</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span> <span class="k">=</span> <span class="k">for</span> <span class="o">{</span>
      <span class="n">notInput0</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">PropsF</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="nf">wire</span><span class="o">(</span><span class="kc">false</span><span class="o">)),</span> <span class="s">"notInput0"</span><span class="o">)</span>
      <span class="n">notInput1</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">PropsF</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="nf">wire</span><span class="o">(</span><span class="kc">false</span><span class="o">)),</span> <span class="s">"notInput1"</span><span class="o">)</span>
      <span class="n">notOutput0</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">PropsF</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="nf">wire</span><span class="o">(</span><span class="kc">false</span><span class="o">)),</span> <span class="s">"notOutput0"</span><span class="o">)</span>

      <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">Props</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="nf">inverter</span><span class="o">(</span><span class="n">input0</span><span class="o">,</span> <span class="n">notInput0</span><span class="o">)),</span> <span class="s">"A"</span><span class="o">)</span>
      <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">Props</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="nf">inverter</span><span class="o">(</span><span class="n">input1</span><span class="o">,</span> <span class="n">notInput1</span><span class="o">)),</span> <span class="s">"B"</span><span class="o">)</span>
      <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">PropsF</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="nf">and</span><span class="o">(</span><span class="n">notInput0</span><span class="o">,</span> <span class="n">notInput1</span><span class="o">,</span> <span class="n">notOutput0</span><span class="o">)),</span> <span class="s">"notAB"</span><span class="o">)</span>
      <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">Props</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="nf">inverter</span><span class="o">(</span><span class="n">notOutput0</span><span class="o">,</span> <span class="n">output</span><span class="o">)),</span> <span class="s">"notNotAB"</span><span class="o">)</span>
    <span class="o">}</span> <span class="nf">yield</span> <span class="o">()</span>
  <span class="o">}</span>
</code></pre></div></div>

<p>In the OrAlt actor, we first invert both inputs, then AND these inverted inputs, and finally invert the result. This approach leverages the efficiency of De Morgan’s laws to potentially reduce the overall computation time, especially in complex circuits.</p>

<blockquote>
  <p>Note how we are now dealing at a higher level of abstraction – we focus on the logical connections between components rather than the internal workings of the actors. A typical approach in the typelevel community is using FS2 and managing these wirings manually. Achieving the same level of abstraction with FS2 can be more challenging. This isn’t to say FS2 is inferior, but Cats-Actors can simplify dynamic graph constructions and modifications at runtime, particularly when handling dynamic stream graphs.</p>
</blockquote>

<p>By using De Morgan’s transformation, we can optimize the OR gate, which typically has a delay of 10ms. In this alternative implementation, we use a NOT gate on each input, an AND gate to combine these negated inputs, and another NOT gate on top of everything. Given that all these components run in parallel, we would have a total delay of only 3ms from the input perturbations, significantly improving efficiency.</p>

<h1 id="3-creating-more-complex-components">3. Creating More Complex Components</h1>

<p>Now that we have created basic logic gates, let’s move on to combining these gates into more complex components. We’ll start with the Half Adder. A Half Adder is a digital circuit that performs addition of two binary digits. It has two inputs, <code class="language-plaintext highlighter-rouge">a</code> and <code class="language-plaintext highlighter-rouge">b</code>, and two outputs, <code class="language-plaintext highlighter-rouge">s</code> (sum) and <code class="language-plaintext highlighter-rouge">c</code> (carry). The sum output is the XOR of the inputs, and the carry output is the AND of the inputs.</p>

<p>Here’s the code for the Half Adder:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">halfAdder</span><span class="o">(</span><span class="n">a</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">],</span> <span class="n">b</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">],</span> <span class="n">s</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">],</span> <span class="n">c</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">])</span><span class="k">:</span> <span class="kt">Actor</span><span class="o">[</span><span class="kt">IO</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
  <span class="k">new</span> <span class="nc">Actor</span><span class="o">[</span><span class="kt">IO</span><span class="o">]</span> <span class="o">{</span>
    <span class="k">override</span> <span class="k">val</span> <span class="nv">preStart</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span> <span class="k">=</span> <span class="k">for</span> <span class="o">{</span>
      <span class="n">d</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">PropsF</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="nf">wire</span><span class="o">(</span><span class="kc">false</span><span class="o">)),</span> <span class="s">"d"</span><span class="o">)</span>
      <span class="n">e</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">PropsF</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="nf">wire</span><span class="o">(</span><span class="kc">false</span><span class="o">)),</span> <span class="s">"e"</span><span class="o">)</span>
      <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">PropsF</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="nf">or</span><span class="o">(</span><span class="n">a</span><span class="o">,</span> <span class="n">b</span><span class="o">,</span> <span class="n">d</span><span class="o">)),</span> <span class="s">"Or"</span><span class="o">)</span>
      <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">PropsF</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="nf">and</span><span class="o">(</span><span class="n">a</span><span class="o">,</span> <span class="n">b</span><span class="o">,</span> <span class="n">c</span><span class="o">)),</span> <span class="s">"And"</span><span class="o">)</span>
      <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">Props</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="nf">inverter</span><span class="o">(</span><span class="n">c</span><span class="o">,</span> <span class="n">e</span><span class="o">)),</span> <span class="s">"Inverter"</span><span class="o">)</span>
      <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">PropsF</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="nf">and</span><span class="o">(</span><span class="n">d</span><span class="o">,</span> <span class="n">e</span><span class="o">,</span> <span class="n">s</span><span class="o">)),</span> <span class="s">"And2"</span><span class="o">)</span>
    <span class="o">}</span> <span class="nf">yield</span> <span class="o">()</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>The Half Adder actor uses our previously defined gates to create the sum and carry outputs. It uses an OR gate, an AND gate, and an inverter to achieve this.</p>

<p>Next, let’s create the Full Adder, which adds three binary digits (two significant bits and a carry bit). The Full Adder outputs a sum and a carry. We’ll use two Half Adders and an OR gate to construct the Full Adder:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">fullAdder</span><span class="o">(</span><span class="n">a</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">],</span> <span class="n">b</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">],</span> <span class="n">cin</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">],</span> <span class="n">sum</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">],</span> <span class="n">cout</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">])</span><span class="k">:</span> <span class="kt">Actor</span><span class="o">[</span><span class="kt">IO</span><span class="o">]</span> <span class="k">=</span> <span class="k">new</span> <span class="nc">Actor</span><span class="o">[</span><span class="kt">IO</span><span class="o">]</span> <span class="o">{</span>
    <span class="k">override</span> <span class="k">val</span> <span class="nv">preStart</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span> <span class="k">=</span> <span class="k">for</span> <span class="o">{</span>
        <span class="n">s</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">PropsF</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="nf">wire</span><span class="o">(</span><span class="kc">false</span><span class="o">)))</span>
        <span class="n">c1</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">PropsF</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="nf">wire</span><span class="o">(</span><span class="kc">false</span><span class="o">)))</span>
        <span class="n">c2</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">PropsF</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="nf">wire</span><span class="o">(</span><span class="kc">false</span><span class="o">)))</span>
        <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">Props</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="nf">halfAdder</span><span class="o">(</span><span class="n">a</span><span class="o">,</span> <span class="n">cin</span><span class="o">,</span> <span class="n">s</span><span class="o">,</span> <span class="n">c1</span><span class="o">)),</span> <span class="s">"HalfAdder1"</span><span class="o">)</span>
        <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">Props</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="nf">halfAdder</span><span class="o">(</span><span class="n">b</span><span class="o">,</span> <span class="n">s</span><span class="o">,</span> <span class="n">sum</span><span class="o">,</span> <span class="n">c2</span><span class="o">)),</span> <span class="s">"HalfAdder2"</span><span class="o">)</span>
        <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">PropsF</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="nf">or</span><span class="o">(</span><span class="n">c1</span><span class="o">,</span> <span class="n">c2</span><span class="o">,</span> <span class="n">cout</span><span class="o">)),</span> <span class="s">"OrGate"</span><span class="o">)</span>
    <span class="o">}</span> <span class="nf">yield</span> <span class="o">()</span>
<span class="o">}</span>
</code></pre></div></div>

<p>By leveraging the Half Adder, the Full Adder actor becomes simpler and more modular. This demonstrates the power of building higher-order components from simpler ones, enhancing our digital circuit simulation capabilities.</p>

<p>Next, let’s build a 2-to-1 Demultiplexer (Demux2), which directs an input signal to one of the two output lines based on a control signal. Here’s the code for Demux2:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">demux2</span><span class="o">(</span><span class="n">in</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">],</span> <span class="n">c</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">],</span> <span class="n">out1</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">],</span> <span class="n">out0</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">])</span><span class="k">:</span> <span class="kt">Actor</span><span class="o">[</span><span class="kt">IO</span><span class="o">]</span> <span class="k">=</span> <span class="k">new</span> <span class="nc">Actor</span><span class="o">[</span><span class="kt">IO</span><span class="o">]</span> <span class="o">{</span>
    <span class="k">override</span> <span class="k">val</span> <span class="nv">preStart</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span> <span class="k">=</span> <span class="k">for</span> <span class="o">{</span>
        <span class="n">notC</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">PropsF</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="nf">wire</span><span class="o">(</span><span class="kc">false</span><span class="o">)),</span> <span class="s">"not"</span><span class="o">)</span>
        <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">Props</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="nf">inverter</span><span class="o">(</span><span class="n">c</span><span class="o">,</span> <span class="n">notC</span><span class="o">)),</span> <span class="s">"InverterA"</span><span class="o">)</span>
        <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">PropsF</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="nf">and</span><span class="o">(</span><span class="n">in</span><span class="o">,</span> <span class="n">notC</span><span class="o">,</span> <span class="n">out1</span><span class="o">)),</span> <span class="s">"AndGateA"</span><span class="o">)</span>
        <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">PropsF</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="nf">and</span><span class="o">(</span><span class="n">in</span><span class="o">,</span> <span class="n">c</span><span class="o">,</span> <span class="n">out0</span><span class="o">)),</span> <span class="s">"AndGateB"</span><span class="o">)</span>
    <span class="o">}</span> <span class="nf">yield</span> <span class="o">()</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Finally, let’s create a General Demultiplexer (Demux), which can handle multiple control signals and direct the input signal to one of the output lines. The Demux actor uses recursion to handle multiple control signals, dynamically creating a demux of any size by wiring Demux2 actors together. This approach illustrates the flexibility and power of combining actors and functional programming in Cats-Actors. Here’s the code for Demux:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">demux</span><span class="o">(</span><span class="n">in</span><span class="k">:</span> <span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">],</span> <span class="n">c</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">]],</span> <span class="n">out</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">ActorRef</span><span class="o">[</span><span class="kt">IO</span><span class="o">]])</span><span class="k">:</span> <span class="kt">Actor</span><span class="o">[</span><span class="kt">IO</span><span class="o">]</span> <span class="k">=</span> <span class="k">new</span> <span class="nc">Actor</span><span class="o">[</span><span class="kt">IO</span><span class="o">]</span> <span class="o">{</span>
    <span class="k">override</span> <span class="k">val</span> <span class="nv">preStart</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span> <span class="k">=</span> <span class="n">c</span> <span class="k">match</span> <span class="o">{</span>
        <span class="k">case</span> <span class="n">c_n</span> <span class="o">::</span> <span class="nc">Nil</span> <span class="k">=&gt;</span>
            <span class="nv">context</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">Props</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="nf">demux2</span><span class="o">(</span><span class="n">in</span><span class="o">,</span> <span class="n">c_n</span><span class="o">,</span> <span class="nv">out</span><span class="o">.</span><span class="py">head</span><span class="o">,</span> <span class="nf">out</span><span class="o">(</span><span class="mi">1</span><span class="o">)))).</span><span class="py">void</span>

        <span class="k">case</span> <span class="n">c_n</span> <span class="o">::</span> <span class="n">c_rest</span> <span class="k">=&gt;</span>
            <span class="k">for</span> <span class="o">{</span>
                <span class="n">out1</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">PropsF</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="nf">wire</span><span class="o">(</span><span class="kc">false</span><span class="o">)))</span>
                <span class="n">out0</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">PropsF</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="nf">wire</span><span class="o">(</span><span class="kc">false</span><span class="o">)))</span>
                <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">Props</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="nf">demux2</span><span class="o">(</span><span class="n">in</span><span class="o">,</span> <span class="n">c_n</span><span class="o">,</span> <span class="n">out1</span><span class="o">,</span> <span class="n">out0</span><span class="o">)))</span>
                <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">Props</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="nf">demux</span><span class="o">(</span><span class="n">out1</span><span class="o">,</span> <span class="n">c_rest</span><span class="o">,</span> <span class="nv">out</span><span class="o">.</span><span class="py">take</span><span class="o">(</span><span class="nv">out</span><span class="o">.</span><span class="py">size</span> <span class="o">/</span> <span class="mi">2</span><span class="o">))))</span>
                <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">context</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">Props</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="nf">demux</span><span class="o">(</span><span class="n">out0</span><span class="o">,</span> <span class="n">c_rest</span><span class="o">,</span> <span class="nv">out</span><span class="o">.</span><span class="py">drop</span><span class="o">(</span><span class="nv">out</span><span class="o">.</span><span class="py">size</span> <span class="o">/</span> <span class="mi">2</span><span class="o">))))</span>
            <span class="o">}</span> <span class="nf">yield</span> <span class="o">()</span>

        <span class="k">case</span> <span class="nc">Nil</span> <span class="k">=&gt;</span> <span class="nv">IO</span><span class="o">.</span><span class="py">unit</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Note how we can create a demux of any size by recursively wiring Demux2 actors. This exemplifies the power of Cats-Actors, allowing us to use actors and functional programming in unison, and even employ recursion to create dynamic structures.</p>

<blockquote>
  <p>One key advantage of Cats-Actors is its ability to create dynamic stream graphs without needing to manage the intricate details of wiring these streams manually. Cats-Actors is particularly beneficial when dealing with dynamic graphs of streams that need to be constructed or modified at runtime. This approach simplifies the development of dynamic, evolving systems, making it an excellent choice for complex and adaptable applications.</p>
</blockquote>

<h1 id="putting-it-all-together">Putting It All Together</h1>
<p>Now, let’s put all our components together and create a Logic Circuit Simulator. This main application will set up a simulation board to test a demultiplexer with two control inputs and four outputs.</p>

<p>Here’s the complete code for the Logic Circuit Simulator:</p>
<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">object</span> <span class="nc">LogicCircuitSimulator</span> <span class="k">extends</span> <span class="nc">IOApp</span> <span class="o">{</span>
  <span class="k">override</span> <span class="k">def</span> <span class="nf">run</span><span class="o">(</span><span class="n">args</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">String</span><span class="o">])</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">ExitCode</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
    <span class="nc">ActorSystem</span><span class="o">[</span><span class="kt">IO</span><span class="o">](</span><span class="s">"De-multiplexer Board Simulator"</span><span class="o">).</span><span class="py">use</span><span class="o">(</span><span class="n">system</span> <span class="k">=&gt;</span>
      <span class="k">for</span> <span class="o">{</span>
        <span class="n">in1</span> <span class="k">&lt;-</span> <span class="nv">system</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">PropsF</span><span class="o">(</span><span class="nf">wire</span><span class="o">(</span><span class="kc">false</span><span class="o">)),</span> <span class="s">"in1"</span><span class="o">)</span>
        <span class="n">c1</span> <span class="k">&lt;-</span> <span class="nv">system</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">PropsF</span><span class="o">(</span><span class="nf">wire</span><span class="o">(</span><span class="kc">false</span><span class="o">)),</span> <span class="s">"c1"</span><span class="o">)</span>
        <span class="n">c2</span> <span class="k">&lt;-</span> <span class="nv">system</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">PropsF</span><span class="o">(</span><span class="nf">wire</span><span class="o">(</span><span class="kc">false</span><span class="o">)),</span> <span class="s">"c2"</span><span class="o">)</span>
        <span class="n">out1</span> <span class="k">&lt;-</span> <span class="nv">system</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">PropsF</span><span class="o">(</span><span class="nf">wire</span><span class="o">(</span><span class="kc">false</span><span class="o">)),</span> <span class="s">"out1"</span><span class="o">)</span>
        <span class="n">out2</span> <span class="k">&lt;-</span> <span class="nv">system</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">PropsF</span><span class="o">(</span><span class="nf">wire</span><span class="o">(</span><span class="kc">false</span><span class="o">)),</span> <span class="s">"out2"</span><span class="o">)</span>
        <span class="n">out3</span> <span class="k">&lt;-</span> <span class="nv">system</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">PropsF</span><span class="o">(</span><span class="nf">wire</span><span class="o">(</span><span class="kc">false</span><span class="o">)),</span> <span class="s">"out3"</span><span class="o">)</span>
        <span class="n">out4</span> <span class="k">&lt;-</span> <span class="nv">system</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">PropsF</span><span class="o">(</span><span class="nf">wire</span><span class="o">(</span><span class="kc">false</span><span class="o">)),</span> <span class="s">"out4"</span><span class="o">)</span>

        <span class="n">allActors</span> <span class="k">=</span> <span class="nc">List</span><span class="o">(</span><span class="n">in1</span><span class="o">,</span> <span class="n">c1</span><span class="o">,</span> <span class="n">c2</span><span class="o">,</span> <span class="n">out1</span><span class="o">,</span> <span class="n">out2</span><span class="o">,</span> <span class="n">out3</span><span class="o">,</span> <span class="n">out4</span><span class="o">)</span>
        <span class="n">printTruthTable</span> <span class="k">=</span>
          <span class="k">for</span> <span class="o">{</span>
            <span class="n">outputs</span> <span class="k">&lt;-</span> <span class="nv">allActors</span><span class="o">.</span><span class="py">parTraverse</span><span class="o">(</span><span class="k">_</span> <span class="o">?[</span><span class="kt">Boolean</span><span class="o">]</span> <span class="nc">GetValue</span><span class="o">)</span>
            <span class="n">result</span> <span class="k">=</span> <span class="nv">allActors</span><span class="o">.</span><span class="py">zip</span><span class="o">(</span><span class="n">outputs</span><span class="o">).</span><span class="py">map</span> <span class="o">{</span>
              <span class="nf">case</span> <span class="o">(</span><span class="n">actor</span><span class="o">,</span> <span class="n">value</span><span class="o">)</span> <span class="k">=&gt;</span> <span class="n">s</span><span class="s">"${actor.path.name}::$value"</span>
            <span class="o">}.</span><span class="py">mkString</span><span class="o">(</span><span class="s">"\t"</span><span class="o">)</span>
            <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">IO</span><span class="o">.</span><span class="py">println</span><span class="o">(</span><span class="n">result</span><span class="o">)</span>
          <span class="o">}</span> <span class="nf">yield</span> <span class="o">()</span>

        <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">system</span><span class="o">.</span><span class="py">actorOf</span><span class="o">(</span><span class="nc">Props</span><span class="o">(</span><span class="nf">demux</span><span class="o">(</span><span class="n">in1</span><span class="o">,</span> <span class="nc">List</span><span class="o">(</span><span class="n">c2</span><span class="o">,</span> <span class="n">c1</span><span class="o">),</span> <span class="nc">List</span><span class="o">(</span><span class="n">out4</span><span class="o">,</span> <span class="n">out3</span><span class="o">,</span> <span class="n">out2</span><span class="o">,</span> <span class="n">out1</span><span class="o">))))</span>

        <span class="k">_</span> <span class="k">&lt;-</span> <span class="n">in1</span> <span class="o">!</span> <span class="kc">true</span>
        <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">printTruthTable</span><span class="o">.</span><span class="py">delayBy</span><span class="o">(</span><span class="mi">1</span> <span class="n">second</span><span class="o">)</span>

        <span class="k">_</span> <span class="k">&lt;-</span> <span class="n">c1</span> <span class="o">!</span> <span class="kc">true</span>
        <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">printTruthTable</span><span class="o">.</span><span class="py">delayBy</span><span class="o">(</span><span class="mi">1</span> <span class="n">second</span><span class="o">)</span>

        <span class="k">_</span> <span class="k">&lt;-</span> <span class="n">c1</span> <span class="o">!</span> <span class="kc">false</span>
        <span class="k">_</span> <span class="k">&lt;-</span> <span class="n">c2</span> <span class="o">!</span> <span class="kc">true</span>
        <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">printTruthTable</span><span class="o">.</span><span class="py">delayBy</span><span class="o">(</span><span class="mi">1</span> <span class="n">second</span><span class="o">)</span>

        <span class="k">_</span> <span class="k">&lt;-</span> <span class="n">c1</span> <span class="o">!</span> <span class="kc">true</span>
        <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">printTruthTable</span><span class="o">.</span><span class="py">delayBy</span><span class="o">(</span><span class="mi">1</span> <span class="n">second</span><span class="o">)</span>

        <span class="k">_</span> <span class="k">&lt;-</span> <span class="n">in1</span> <span class="o">!</span> <span class="kc">false</span>
        <span class="k">_</span> <span class="k">&lt;-</span> <span class="nv">printTruthTable</span><span class="o">.</span><span class="py">delayBy</span><span class="o">(</span><span class="mi">1</span> <span class="n">second</span><span class="o">)</span>
      <span class="o">}</span> <span class="nf">yield</span> <span class="o">()</span>
    <span class="o">).</span><span class="py">as</span><span class="o">(</span><span class="nv">ExitCode</span><span class="o">.</span><span class="py">Success</span><span class="o">)</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>In the main application, we first set up the board simulator to test a demultiplexer with two control inputs and four outputs. We create all the necessary wires for the input, control, and output signals. Notice how elegant it is to query all actors to retrieve their values in parallel using <code class="language-plaintext highlighter-rouge">allActors.parTraverse(_ ?[Boolean] GetValue)</code>.</p>

<p>We then create the demultiplexer, which routes the input signal based on the control signals. For instance, when we set <code class="language-plaintext highlighter-rouge">in1</code> to <code class="language-plaintext highlighter-rouge">true</code>, we expect <code class="language-plaintext highlighter-rouge">out4</code> to be <code class="language-plaintext highlighter-rouge">true</code>. Similarly, we can change the control signals <code class="language-plaintext highlighter-rouge">c1</code> and <code class="language-plaintext highlighter-rouge">c2</code> and observe the expected outputs. This dynamic manipulation and observation of the circuit’s state showcase how state changes propagate through the circuit and how the outputs change accordingly.</p>

<p>By printing the truth table, the program shows the state of all wires at each step, demonstrating the robustness and efficiency of our logic circuit simulator built with Cats-Actors. This powerful approach allows us to dynamically create and modify our circuit, demonstrating the harmony between functional programming and the actor model in Cats-Actors.</p>

<h1 id="conclusion">Conclusion</h1>
<p>In this tutorial, we’ve explored the synergy between the actor model and functional programming by building a robust logic circuit simulator using Cats-Actors. We’ve created basic components like wires and logic gates, and combined them into more complex structures such as half adders, full adders, and demultiplexers. Through this process, we’ve demonstrated how Cats-Actors enables us to build dynamic, reliable systems with ease.</p>

<p>The power of Cats-Actors lies in its ability to manage concurrency and state in a highly predictable and maintainable manner. By leveraging functional programming principles, we’ve shown how to create a system that is both scalable and fault-tolerant. This approach simplifies the development of complex, evolving systems, making it an excellent choice for various applications.</p>

<p>If you’re interested in learning more or contributing to the project, check out the <a href="https://github.com/suprnation/cats-actors">Cats-Actors GitHub repository</a>. This repository contains comprehensive documentation and additional examples to help you get started with building your own actor-based systems.</p>

<p>As always, stay safe, keep hacking!</p>]]></content><author><name>Mark Galea</name></author><summary type="html"><![CDATA[Functional programming and the actor model are two powerful paradigms in modern software development. They might seem like they’re in opposition, but in reality, they complement each other beautifully. Scala, as a versatile language, allows multiple paradigms to coexist, and Cats-Actors, a functional programming-based actor system, exemplifies this harmony. Cats-Actors is a reimagining of the actor paradigm model married with the functional paradigm.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://cloudmark.github.io/images/cats-actors/logo-small.png" /><media:content medium="image" url="http://cloudmark.github.io/images/cats-actors/logo-small.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Functional Programming to the max</title><link href="http://cloudmark.github.io/Functional-Programming-to-the-Max/" rel="alternate" type="text/html" title="Functional Programming to the max" /><published>2021-09-06T00:00:00+00:00</published><updated>2021-09-06T00:00:00+00:00</updated><id>http://cloudmark.github.io/Functional%20Programming%20to%20the%20Max</id><content type="html" xml:base="http://cloudmark.github.io/Functional-Programming-to-the-Max/"><![CDATA[<p><img class="title" src="/images/lambda.jpg" />
This post is an adaptation of the talk <a href="https://www.youtube.com/watch?v=sxudIMiOo68">FP to the max</a>, credit goes to <a href="https://twitter.com/jdegoes">John A De Goes</a>.  We will take a minimal example written in a procedural style and introduce functional programming techniques and principles to create a more principled application.  It is important to preface this post with a disclaimer which is <em>:warning:Do not try this on your codebase!!:warning:</em> - this example is an overkill and is only intended to help developers see how functional concepts can be applied on a small scale so that they can extrapolate these techniques on larger projects.</p>

<h1 id="number-guessing-game">Number Guessing Game</h1>
<p>The example we will use throughout this post is a number guessing game.  When the program starts it will ask the user for his/her name and on input the program will generate a random number between 1 and 5 and ask the user to guess the number.  If the user guesses the number correctly, the program will inform the user of his/her unique mind-reading abilities (incidentally, the user’s superpowers will work 20% of the time!), otherwise, the program will notify the telekinetic failure. Finally, once the game round is complete, the program will ask the user the choose between having another go or exiting. The complete source code is listed below:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">main</span><span class="o">(</span><span class="n">args</span><span class="k">:</span> <span class="kt">Array</span><span class="o">[</span><span class="kt">String</span><span class="o">])</span><span class="k">:</span> <span class="kt">Unit</span> <span class="o">=</span> <span class="o">{</span>
  <span class="nf">println</span><span class="o">(</span><span class="s">"What is your name?"</span><span class="o">)</span>
  <span class="k">val</span> <span class="nv">name</span><span class="k">:</span> <span class="kt">String</span> <span class="o">=</span> <span class="nf">readLine</span><span class="o">()</span>
  <span class="nf">println</span><span class="o">(</span><span class="n">s</span><span class="s">"Hello $name welcome to the game!"</span><span class="o">)</span>
  <span class="k">var</span> <span class="n">exec</span><span class="k">:</span> <span class="kt">Boolean</span> <span class="o">=</span> <span class="kc">true</span>
  <span class="nf">while</span> <span class="o">(</span><span class="n">exec</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">val</span> <span class="nv">num</span><span class="k">:</span> <span class="kt">Int</span> <span class="o">=</span> <span class="nv">scala</span><span class="o">.</span><span class="py">util</span><span class="o">.</span><span class="py">Random</span><span class="o">.</span><span class="py">nextInt</span><span class="o">(</span><span class="mi">5</span><span class="o">)</span> <span class="o">+</span> <span class="mi">1</span>
    <span class="nf">println</span><span class="o">(</span><span class="n">s</span><span class="s">"Dear $name, please guess a number from 1 to 5"</span><span class="o">)</span>
    <span class="k">val</span> <span class="nv">guess</span><span class="k">:</span> <span class="kt">Int</span> <span class="o">=</span> <span class="nf">readLine</span><span class="o">().</span><span class="py">toInt</span>
    <span class="nf">if</span> <span class="o">(</span><span class="n">guess</span> <span class="o">==</span> <span class="n">num</span><span class="o">)</span> <span class="nf">println</span><span class="o">(</span><span class="n">s</span><span class="s">"You guessed right, $name!"</span><span class="o">)</span>
    <span class="k">else</span> <span class="nf">println</span><span class="o">(</span><span class="n">s</span><span class="s">"You guessed wrong, $name the number was $num"</span><span class="o">)</span>
    <span class="nf">println</span><span class="o">(</span><span class="n">s</span><span class="s">"Do you want to continue $name?"</span><span class="o">)</span>
    <span class="nf">readLine</span><span class="o">()</span> <span class="k">match</span> <span class="o">{</span>
      <span class="k">case</span> <span class="s">"y"</span> <span class="k">=&gt;</span> <span class="n">exec</span> <span class="k">=</span> <span class="kc">true</span>
      <span class="k">case</span> <span class="s">"n"</span> <span class="k">=&gt;</span> <span class="n">exec</span> <span class="k">=</span> <span class="kc">false</span>
    <span class="o">}</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>So what’s “wrong” with such a program? To understand what we can improve, let us first detour and explain the three functional programming principles.</p>

<h1 id="functional-programming-properties">Functional Programming Properties</h1>
<p>Functional programs have three main properties:</p>

<ol>
  <li><strong>Total</strong> - Functions always return an output for every input.</li>
  <li><strong>Deterministic</strong> - Functions return the same output for the same input.</li>
  <li><strong>Pure</strong> - The only purpose of providing a function input is to compute the output.</li>
</ol>

<p>In contrast, procedural programs are:</p>

<ol>
  <li><strong>Partial</strong> - Procedures do not return values for some inputs (for example, they throw exceptions).</li>
  <li><strong>Non-Deterministic</strong> - Procedures return different outputs for the same input.</li>
  <li><strong>Impure</strong> - Procedures perform side-effects which mutate data or interact with the external world.</li>
</ol>

<p>Let’s have a look at some examples to see how these principles apply.</p>

<blockquote>
  <p><strong>Example 1: Print line to system output</strong></p>
  <div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">println</span><span class="o">(</span><span class="n">s</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span><span class="k">:</span> <span class="kt">Unit</span> <span class="o">=</span> <span class="o">???</span>
</code></pre></div>  </div>
  <p>The method <code class="language-plaintext highlighter-rouge">println</code> above is:</p>
  <ul>
    <li><strong><em>Total</em></strong> - it is defined for all inputs - the output is always unit</li>
    <li><strong><em>Deterministic</em></strong> - all inputs yield the same output - unit</li>
    <li><strong>Impure</strong> - under the hood <code class="language-plaintext highlighter-rouge">println</code> invokes some system calls to push things to the screen - this is not part of the computation.</li>
  </ul>
</blockquote>

<blockquote>
  <p><strong>Example 2: Parse integer</strong></p>
  <div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">parseInt</span><span class="o">(</span><span class="n">s</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span><span class="k">:</span> <span class="kt">Int</span> <span class="o">=</span> <span class="o">???</span> 
</code></pre></div>  </div>
  <p>The method <code class="language-plaintext highlighter-rouge">parseInt</code> above is:</p>
  <ul>
    <li><strong>Partial</strong> - not all strings are valid numbers, e.g. the input “hello world” would throw an exception</li>
    <li><strong><em>Deterministic</em></strong> - all inputs will give the same result or error</li>
    <li><strong><em>Pure</em></strong> - There are no side-effects or interactions apart from the conversion from a string to an integer.</li>
  </ul>
</blockquote>

<blockquote>
  <p><strong>Example 3: Generate a random number</strong></p>
  <div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">randomInt</span><span class="o">()</span><span class="k">:</span> <span class="kt">Int</span> <span class="o">=</span> <span class="o">???</span>
</code></pre></div>  </div>
  <p>The method <code class="language-plaintext highlighter-rouge">randomInt</code> above is:</p>
  <ul>
    <li><strong><em>Total</em></strong> - for every input we get an output</li>
    <li><strong>Non-Deterministic</strong> - by definition the return of a random function is non-deterministic</li>
    <li><strong>Impure</strong> - random numbers are generated by observing outside data that is not predictable or generated using pseudo-random streams, both of which are external to the computation.</li>
  </ul>
</blockquote>

<p>Having understood the properties of functional programs, we will now iterate over the source problem and convert it into an equivalent program that is more principled (i.e. follows more functional programming properties).</p>

<h1 id="number-guessing-game---first-iteration">Number Guessing Game - First Iteration</h1>
<p>In the first iteration of the program, we will directly address two partial functions.  The first partial function that we are going to address is</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">val</span> <span class="nv">guess</span><span class="k">:</span> <span class="kt">Int</span> <span class="o">=</span> <span class="nf">readLine</span><span class="o">().</span><span class="py">toInt</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">readLine().toInt</code> is a partial function since it is not defined for all inputs (some inputs will throw an exception).  One way to implement the total equivalent is to swap the return type from <code class="language-plaintext highlighter-rouge">Int</code> to <code class="language-plaintext highlighter-rouge">Option[Int]</code> to capture cases in which the input would throw an exception.  You can think of <code class="language-plaintext highlighter-rouge">Option[Int]</code> as a more honest type since it explicitly encodes those values which yield no result.</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">parseNumber</span><span class="o">(</span><span class="n">str</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span><span class="k">:</span> <span class="kt">Option</span><span class="o">[</span><span class="kt">Int</span><span class="o">]</span> <span class="k">=</span> <span class="nc">Try</span><span class="o">(</span><span class="nv">str</span><span class="o">.</span><span class="py">toInt</span><span class="o">).</span><span class="py">toOption</span>
</code></pre></div></div>

<p>The second partial function we will address in this section is</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">readLine</span><span class="o">()</span> <span class="k">match</span> <span class="o">{</span>
  <span class="k">case</span> <span class="s">"y"</span> <span class="k">=&gt;</span> <span class="n">exec</span> <span class="k">=</span> <span class="kc">true</span>
  <span class="k">case</span> <span class="s">"n"</span> <span class="k">=&gt;</span> <span class="n">exec</span> <span class="k">=</span> <span class="kc">false</span>
<span class="o">}</span>
</code></pre></div></div>

<p>This function is not total since it is only defined for two inputs, “y” and “n”, in all other cases, a <code class="language-plaintext highlighter-rouge">MatchError</code> is thrown.  We can convert this to a total function as follows:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">var</span> <span class="n">continue</span><span class="k">:</span> <span class="kt">Boolean</span> <span class="o">=</span> <span class="kc">false</span>
<span class="nf">while</span><span class="o">(</span><span class="n">continue</span><span class="o">)</span> <span class="o">{</span>
  <span class="n">continue</span> <span class="k">=</span> <span class="kc">false</span>
  <span class="nf">readLine</span><span class="o">()</span> <span class="k">match</span> <span class="o">{</span>
    <span class="k">case</span> <span class="s">"y"</span> <span class="k">=&gt;</span> <span class="n">exec</span> <span class="k">=</span> <span class="kc">true</span>
    <span class="k">case</span> <span class="s">"n"</span> <span class="k">=&gt;</span> <span class="n">exec</span> <span class="k">=</span> <span class="kc">false</span>
    <span class="k">case</span> <span class="k">_</span> <span class="k">=&gt;</span> <span class="n">continue</span> <span class="k">=</span> <span class="kc">true</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>The complete code after these two conversions is</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">main</span><span class="o">(</span><span class="n">args</span><span class="k">:</span> <span class="kt">Array</span><span class="o">[</span><span class="kt">String</span><span class="o">])</span><span class="k">:</span> <span class="kt">Unit</span> <span class="o">=</span> <span class="o">{</span>
  <span class="nf">println</span><span class="o">(</span><span class="s">"What is your name?"</span><span class="o">)</span>
  <span class="k">val</span> <span class="nv">name</span><span class="k">:</span> <span class="kt">String</span> <span class="o">=</span> <span class="nf">readLine</span><span class="o">()</span>
  <span class="nf">println</span><span class="o">(</span><span class="n">s</span><span class="s">"Hello $name welcome to the game!"</span><span class="o">)</span>
  <span class="k">var</span> <span class="n">exec</span><span class="k">:</span> <span class="kt">Boolean</span> <span class="o">=</span> <span class="kc">true</span>
  <span class="nf">while</span> <span class="o">(</span><span class="n">exec</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">val</span> <span class="nv">num</span><span class="k">:</span> <span class="kt">Int</span> <span class="o">=</span> <span class="nv">scala</span><span class="o">.</span><span class="py">util</span><span class="o">.</span><span class="py">Random</span><span class="o">.</span><span class="py">nextInt</span><span class="o">(</span><span class="mi">5</span><span class="o">)</span> <span class="o">+</span> <span class="mi">1</span>
    <span class="nf">println</span><span class="o">(</span><span class="n">s</span><span class="s">"Dear $name, please guess a number from 1 to 5"</span><span class="o">)</span>
    <span class="k">val</span> <span class="nv">guessOpt</span><span class="k">:</span> <span class="kt">Option</span><span class="o">[</span><span class="kt">Int</span><span class="o">]</span> <span class="k">=</span> <span class="nf">parseNumber</span><span class="o">(</span><span class="nf">readLine</span><span class="o">())</span>
    <span class="n">guessOpt</span> <span class="k">match</span> <span class="o">{</span>
      <span class="k">case</span> <span class="nc">None</span> <span class="k">=&gt;</span>
        <span class="nf">println</span><span class="o">(</span><span class="s">"Not a number!"</span><span class="o">)</span>
      <span class="k">case</span> <span class="nc">Some</span><span class="o">(</span><span class="n">guess</span><span class="o">)</span> <span class="k">=&gt;</span>
        <span class="nf">if</span> <span class="o">(</span><span class="n">guess</span> <span class="o">==</span> <span class="n">num</span><span class="o">)</span> <span class="nf">println</span><span class="o">(</span><span class="n">s</span><span class="s">"You guessed right, $name!"</span><span class="o">)</span>
        <span class="k">else</span> <span class="nf">println</span><span class="o">(</span><span class="n">s</span><span class="s">"You guessed wrong, $name the number was $num"</span><span class="o">)</span>
        <span class="nf">println</span><span class="o">(</span><span class="n">s</span><span class="s">"Do you want to continue $name?"</span><span class="o">)</span>
        <span class="k">var</span> <span class="n">continue</span><span class="k">:</span> <span class="kt">Boolean</span> <span class="o">=</span> <span class="kc">false</span>
        <span class="nf">while</span><span class="o">(</span><span class="n">continue</span><span class="o">)</span> <span class="o">{</span>
          <span class="n">continue</span> <span class="k">=</span> <span class="kc">false</span>
          <span class="nf">readLine</span><span class="o">()</span> <span class="k">match</span> <span class="o">{</span>
            <span class="k">case</span> <span class="s">"y"</span> <span class="k">=&gt;</span> <span class="n">exec</span> <span class="k">=</span> <span class="kc">true</span>
            <span class="k">case</span> <span class="s">"n"</span> <span class="k">=&gt;</span> <span class="n">exec</span> <span class="k">=</span> <span class="kc">false</span>
            <span class="k">case</span> <span class="k">_</span> <span class="k">=&gt;</span> <span class="n">continue</span> <span class="k">=</span> <span class="kc">true</span>
          <span class="o">}</span>
        <span class="o">}</span>
    <span class="o">}</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<h1 id="number-guessing-game---second-iteration">Number Guessing Game - Second Iteration</h1>
<p>The initial iteration of the program is already more principled than our original problem, and, in most cases, we would stop here.  For the sake of this exercise, however, we will address three more procedures: <code class="language-plaintext highlighter-rouge">println</code>, <code class="language-plaintext highlighter-rouge">readLine</code> and <code class="language-plaintext highlighter-rouge">Random.nextInt</code>.  How to convert such functions into pure functions has perplex the FP community for years. Fortunately, the solution was simple and elegant; let’s welcome the IO monad.  Let’s start this section by creating the IO monad from scratch.</p>

<h2 id="the-io-monad">The IO Monad</h2>
<div class="example">
<b>Disclaimer to the future FP reader</b> In this post, I will be taking a very informal approach to describing the IO Monad. If you feel that there is a better way to explain this section, please comment below.  It would be great if we as a community come together and help newcomers in the field! 
</div>

<p>You can think of the IO monad as a “container” that contains a description of a computation.   The computation itself might not be functional (in the functional programming sense), but the description itself is.  The basic definition of the IO Monad is as follows:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">case</span> <span class="k">class</span> <span class="nc">IO</span><span class="o">[</span><span class="kt">A</span><span class="o">](</span><span class="n">unsafeRun</span><span class="k">:</span> <span class="o">()</span> <span class="o">=&gt;</span> <span class="n">A</span><span class="o">)</span> <span class="o">{}</span>
</code></pre></div></div>

<p>You can see that the value of type <code class="language-plaintext highlighter-rouge">A</code> is deferred (the return of a function) by placing it into an <code class="language-plaintext highlighter-rouge">IO[A]</code> box, and only when the <code class="language-plaintext highlighter-rouge">unsafeRun</code> method is called, the value of type <code class="language-plaintext highlighter-rouge">A</code> is returned. Let’s have a look at an example.</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">object</span> <span class="nc">IOSample</span> <span class="o">{</span>
  <span class="k">def</span> <span class="nf">main</span><span class="o">(</span><span class="n">args</span><span class="k">:</span> <span class="kt">Array</span><span class="o">[</span><span class="kt">String</span><span class="o">])</span><span class="k">:</span> <span class="kt">Unit</span> <span class="o">=</span> <span class="o">{</span>
    <span class="k">val</span> <span class="nv">program</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span> <span class="k">=</span> <span class="nc">IO</span><span class="o">(()</span> <span class="k">=&gt;</span> <span class="nf">println</span><span class="o">(</span><span class="s">"Hello World"</span><span class="o">))</span>
    <span class="nf">println</span><span class="o">(</span><span class="n">program</span><span class="o">)</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Running the program above will result in the following output:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">IO</span><span class="o">(</span><span class="nv">com</span><span class="o">.</span><span class="py">suprnation</span><span class="o">.</span><span class="py">IOSample$$$Lambda$15</span><span class="o">/</span><span class="mh">0x0000000801162c40</span><span class="k">@</span><span class="mi">5</span><span class="n">b464ce8</span><span class="o">)</span>
</code></pre></div></div>

<p>As you can see, nothing happens - <code class="language-plaintext highlighter-rouge">program</code> is just a description that has an embedded <code class="language-plaintext highlighter-rouge">println</code> computation. So the above description is total, deterministic and pure, and is one value from the infinite <code class="language-plaintext highlighter-rouge">IO[Unit]</code> set.</p>

<p>To run this description, we need to invoke the <code class="language-plaintext highlighter-rouge">unsafeRun</code> method as follows:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">object</span> <span class="nc">IOSample</span> <span class="o">{</span>
  <span class="k">def</span> <span class="nf">main</span><span class="o">(</span><span class="n">args</span><span class="k">:</span> <span class="kt">Array</span><span class="o">[</span><span class="kt">String</span><span class="o">])</span><span class="k">:</span> <span class="kt">Unit</span> <span class="o">=</span> <span class="o">{</span>
    <span class="k">val</span> <span class="nv">program</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span> <span class="k">=</span> <span class="nc">IO</span><span class="o">(()</span> <span class="k">=&gt;</span> <span class="nf">println</span><span class="o">(</span><span class="s">"Hello World"</span><span class="o">))</span>
    <span class="nv">program</span><span class="o">.</span><span class="py">unsafeRun</span><span class="o">()</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>At this point the program transitions from pure to impure (as in not following the FP properties) and “Hello World” is printed to the console.</p>

<h2 id="transforming-io-map-and-flatmap">Transforming IO; <code class="language-plaintext highlighter-rouge">map</code> and <code class="language-plaintext highlighter-rouge">flatMap</code></h2>
<p>To compose <code class="language-plaintext highlighter-rouge">IO</code>, we will need two main methods: <code class="language-plaintext highlighter-rouge">map</code> and <code class="language-plaintext highlighter-rouge">flatMap</code> defined as follows:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">case</span> <span class="k">class</span> <span class="nc">IO</span><span class="o">[</span><span class="kt">A</span><span class="o">](</span><span class="n">unsafeRun</span><span class="k">:</span> <span class="o">()</span> <span class="o">=&gt;</span> <span class="n">A</span><span class="o">)</span> <span class="o">{</span> <span class="n">self</span> <span class="k">=&gt;</span>
    <span class="k">def</span> <span class="nf">map</span><span class="o">[</span><span class="kt">B</span><span class="o">](</span><span class="n">fn</span><span class="k">:</span> <span class="kt">A</span> <span class="o">=&gt;</span> <span class="n">B</span><span class="o">)</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">B</span><span class="o">]</span> <span class="k">=</span> <span class="nc">IO</span><span class="o">(()</span> <span class="k">=&gt;</span> <span class="nf">fn</span><span class="o">(</span><span class="nv">self</span><span class="o">.</span><span class="py">unsafeRun</span><span class="o">()))</span>
    <span class="k">def</span> <span class="nf">flatMap</span><span class="o">[</span><span class="kt">B</span><span class="o">](</span><span class="n">fn</span><span class="k">:</span> <span class="kt">A</span> <span class="o">=&gt;</span> <span class="nc">IO</span><span class="o">[</span><span class="kt">B</span><span class="o">])</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">B</span><span class="o">]</span> <span class="k">=</span> <span class="nc">IO</span><span class="o">(()</span> <span class="k">=&gt;</span> <span class="nf">fn</span><span class="o">(</span><span class="nv">self</span><span class="o">.</span><span class="py">unsafeRun</span><span class="o">()).</span><span class="py">unsafeRun</span><span class="o">())</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Visually if we think of <code class="language-plaintext highlighter-rouge">IO</code> as a box with a value inside, we can think of <code class="language-plaintext highlighter-rouge">map</code> as a function that swaps the value of the box by passing it through the function <code class="language-plaintext highlighter-rouge">fn</code> and <code class="language-plaintext highlighter-rouge">flatMap</code> as swapping the box based on the current value.  As an example let’s say we want to increment the value <code class="language-plaintext highlighter-rouge">val three = IO(() =&gt; 3)</code>.</p>

<p>We can achieve this by using the <code class="language-plaintext highlighter-rouge">map</code> function as follows:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">val</span> <span class="nv">three</span> <span class="k">=</span> <span class="nc">IO</span><span class="o">(()</span> <span class="k">=&gt;</span> <span class="mi">3</span><span class="o">)</span>
<span class="nv">three</span><span class="o">.</span><span class="py">map</span><span class="o">(</span><span class="n">v</span> <span class="k">=&gt;</span> <span class="n">v</span> <span class="o">+</span> <span class="mi">1</span><span class="o">)</span>
</code></pre></div></div>

<p>What if we want to return <code class="language-plaintext highlighter-rouge">true</code> when the value inside the box is even and <code class="language-plaintext highlighter-rouge">false</code> otherwise? In this case, we want to swap the box entirely, and hence we would use a <code class="language-plaintext highlighter-rouge">flatMap</code> as follows:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">val</span> <span class="nv">three</span> <span class="k">=</span> <span class="nc">IO</span><span class="o">(()</span> <span class="k">=&gt;</span> <span class="mi">3</span><span class="o">)</span>
<span class="nv">three</span><span class="o">.</span><span class="py">flatMap</span><span class="o">(</span><span class="n">v</span> <span class="k">=&gt;</span> <span class="nf">if</span> <span class="o">(</span><span class="n">v</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="nc">IO</span><span class="o">(()</span> <span class="k">=&gt;</span> <span class="kc">true</span><span class="o">)</span> <span class="k">else</span> <span class="nc">IO</span><span class="o">(()</span> <span class="k">=&gt;</span> <span class="kc">false</span><span class="o">))</span>
</code></pre></div></div>

<p>Before we go further, let’s define two helper methods on the <code class="language-plaintext highlighter-rouge">IO</code> companion object - <code class="language-plaintext highlighter-rouge">point</code> and <code class="language-plaintext highlighter-rouge">unit</code> - to help us package pure values in an <code class="language-plaintext highlighter-rouge">IO</code> box.</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">object</span> <span class="nc">IO</span> <span class="o">{</span>
    <span class="k">def</span> <span class="nf">point</span><span class="o">[</span><span class="kt">A</span><span class="o">](</span><span class="n">a</span><span class="k">:</span> <span class="kt">A</span><span class="o">)</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">A</span><span class="o">]</span> <span class="k">=</span> <span class="nc">IO</span><span class="o">(()</span> <span class="k">=&gt;</span> <span class="n">a</span><span class="o">)</span>
    <span class="k">def</span> <span class="nf">unit</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span> <span class="k">=</span> <span class="nv">IO</span><span class="o">.</span><span class="py">point</span><span class="o">(())</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Using these helper methods, we can simplify the example above as follows:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">val</span> <span class="nv">three</span> <span class="k">=</span> <span class="nv">IO</span><span class="o">.</span><span class="py">point</span><span class="o">(</span><span class="mi">3</span><span class="o">)</span>
<span class="nv">three</span><span class="o">.</span><span class="py">map</span><span class="o">(</span><span class="n">v</span> <span class="k">=&gt;</span> <span class="n">v</span> <span class="o">+</span> <span class="mi">1</span><span class="o">)</span>
<span class="nv">three</span><span class="o">.</span><span class="py">flatMap</span><span class="o">(</span><span class="n">v</span> <span class="k">=&gt;</span> <span class="nf">if</span> <span class="o">(</span><span class="n">v</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="nv">IO</span><span class="o">.</span><span class="py">point</span><span class="o">(</span><span class="kc">true</span><span class="o">)</span> <span class="k">else</span> <span class="nv">IO</span><span class="o">.</span><span class="py">point</span><span class="o">(</span><span class="kc">false</span><span class="o">))</span>
</code></pre></div></div>

<h2 id="for-comprehension">For comprehension</h2>
<p>Before we transform the original program, let’s do one final example of adding two <code class="language-plaintext highlighter-rouge">IO[Int]</code> together.  Given the following program</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">object</span> <span class="nc">IOArithmetic</span> <span class="o">{</span>
  <span class="k">def</span> <span class="nf">main</span><span class="o">(</span><span class="n">args</span><span class="k">:</span> <span class="kt">Array</span><span class="o">[</span><span class="kt">String</span><span class="o">])</span><span class="k">:</span> <span class="kt">Unit</span> <span class="o">=</span> <span class="o">{</span>
    <span class="k">val</span> <span class="nv">number1</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Int</span><span class="o">]</span> <span class="k">=</span> <span class="nv">IO</span><span class="o">.</span><span class="py">point</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span>
    <span class="k">val</span> <span class="nv">number2</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Int</span><span class="o">]</span> <span class="k">=</span> <span class="nv">IO</span><span class="o">.</span><span class="py">point</span><span class="o">(</span><span class="mi">2</span><span class="o">)</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>we cannot simply add the two numbers using <code class="language-plaintext highlighter-rouge">number1 + number2</code> but we need to use a combination of <code class="language-plaintext highlighter-rouge">flatMap</code> and <code class="language-plaintext highlighter-rouge">map</code> to sequence the computation.  The solution to this problem is as follows:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">object</span> <span class="nc">IOArithmetic</span> <span class="o">{</span>
  <span class="k">def</span> <span class="nf">main</span><span class="o">(</span><span class="n">args</span><span class="k">:</span> <span class="kt">Array</span><span class="o">[</span><span class="kt">String</span><span class="o">])</span><span class="k">:</span> <span class="kt">Unit</span> <span class="o">=</span> <span class="o">{</span>
    <span class="k">val</span> <span class="nv">number1</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Int</span><span class="o">]</span> <span class="k">=</span> <span class="nv">IO</span><span class="o">.</span><span class="py">point</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span>
    <span class="k">val</span> <span class="nv">number2</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Int</span><span class="o">]</span> <span class="k">=</span> <span class="nv">IO</span><span class="o">.</span><span class="py">point</span><span class="o">(</span><span class="mi">2</span><span class="o">)</span>

    <span class="nv">number1</span><span class="o">.</span><span class="py">flatMap</span><span class="o">(</span><span class="n">n1</span> <span class="k">=&gt;</span> <span class="o">{</span>
      <span class="nv">number2</span><span class="o">.</span><span class="py">map</span><span class="o">(</span><span class="n">n2</span> <span class="k">=&gt;</span> <span class="o">{</span>
        <span class="n">n1</span> <span class="o">+</span> <span class="n">n2</span>
      <span class="o">})</span>
    <span class="o">})</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>The use of <code class="language-plaintext highlighter-rouge">flatMap</code> and <code class="language-plaintext highlighter-rouge">map</code> to sequence computations is so common that Scala has some special syntactic sugar called <em>for comprehensions</em>. Thus, the above can be re-written as follows:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="o">{</span>
  <span class="n">n1</span> <span class="k">&lt;-</span> <span class="n">number1</span>
  <span class="n">n2</span> <span class="k">&lt;-</span> <span class="n">number2</span>
<span class="o">}</span> <span class="k">yield</span> <span class="n">n1</span> <span class="o">+</span> <span class="n">n2</span>
</code></pre></div></div>

<p>Moving forward, we will prefer this style rather than explicitly writing <code class="language-plaintext highlighter-rouge">flatMap</code> and <code class="language-plaintext highlighter-rouge">map</code> but remember that both are equivalent and it is just syntactic sugar :cake:.</p>

<h1 id="final-conversion">Final Conversion</h1>
<p>Armed with the IO Monad, let’s crank up the function knob and finalise the conversion.  We will start by wrapping up the <code class="language-plaintext highlighter-rouge">println</code>, <code class="language-plaintext highlighter-rouge">readLine</code> and <code class="language-plaintext highlighter-rouge">Random.nextInt</code> within <code class="language-plaintext highlighter-rouge">IO</code> as follows:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">putStrLn</span><span class="o">(</span><span class="n">message</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span> <span class="k">=</span> <span class="nc">IO</span><span class="o">(()</span> <span class="k">=&gt;</span> <span class="nf">println</span><span class="o">(</span><span class="n">message</span><span class="o">))</span>
<span class="k">def</span> <span class="nf">getStrLn</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">String</span><span class="o">]</span> <span class="k">=</span> <span class="nc">IO</span><span class="o">(()</span> <span class="k">=&gt;</span> <span class="nf">readLine</span><span class="o">())</span>
<span class="k">def</span> <span class="nf">randomNumber</span><span class="o">(</span><span class="n">upper</span><span class="k">:</span> <span class="kt">Int</span><span class="o">)</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Int</span><span class="o">]</span> <span class="k">=</span> <span class="nc">IO</span><span class="o">(()</span> <span class="k">=&gt;</span> <span class="nv">scala</span><span class="o">.</span><span class="py">util</span><span class="o">.</span><span class="py">Random</span><span class="o">.</span><span class="py">nextInt</span><span class="o">(</span><span class="n">upper</span><span class="o">))</span>
</code></pre></div></div>

<p>Next, we will convert the original program using <code class="language-plaintext highlighter-rouge">flatMap</code> and <code class="language-plaintext highlighter-rouge">map</code>.  The conversion is reasonably mechanical but to illustrate our conversion strategy, let’s transform the first three lines of the procedural program.</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">println</span><span class="o">(</span><span class="s">"What is your name?"</span><span class="o">)</span>
<span class="k">val</span> <span class="nv">name</span><span class="k">:</span> <span class="kt">String</span> <span class="o">=</span> <span class="nf">readLine</span><span class="o">()</span>
<span class="nf">println</span><span class="o">(</span><span class="n">s</span><span class="s">"Hello $name welcome to the game!"</span><span class="o">)</span>
</code></pre></div></div>

<p>These three lines can be written using a for-comprehension as follows:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="o">{</span>
   <span class="k">_</span>    <span class="k">&lt;-</span> <span class="nf">putStrLn</span><span class="o">(</span><span class="s">"What is your name?"</span><span class="o">)</span>
   <span class="n">name</span> <span class="k">&lt;-</span> <span class="n">getStrLn</span>
   <span class="k">_</span>    <span class="k">&lt;-</span> <span class="nf">putStrLn</span><span class="o">(</span><span class="n">s</span><span class="s">"Hello $name welcome to the game!"</span><span class="o">)</span>
<span class="o">}</span> <span class="nf">yield</span> <span class="o">()</span>
</code></pre></div></div>

<p>In a sense, this program is reminiscent of the procedural counterpart, but there is one key difference - this program is just a <em>description</em>.  We will need to call <code class="language-plaintext highlighter-rouge">unsafeRun</code> to execute this description which will unwrap the descriptions and perform the underlying computations.  At this point our program violates the functional properties defined above and crosses the pure to impure boundary.</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">val</span> <span class="nv">program</span> <span class="k">=</span> <span class="k">for</span> <span class="o">{</span>
   <span class="k">_</span>    <span class="k">&lt;-</span> <span class="nf">putStrLn</span><span class="o">(</span><span class="s">"What is your name?"</span><span class="o">)</span>
   <span class="n">name</span> <span class="k">&lt;-</span> <span class="n">getStrLn</span>
   <span class="k">_</span>    <span class="k">&lt;-</span> <span class="nf">putStrLn</span><span class="o">(</span><span class="n">s</span><span class="s">"Hello $name welcome to the game!"</span><span class="o">)</span>
<span class="o">}</span> <span class="nf">yield</span> <span class="o">()</span>
<span class="nv">program</span><span class="o">.</span><span class="py">unsafeRun</span><span class="o">()</span>
</code></pre></div></div>

<p>The transformed number guessing game is as follows:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">main</span><span class="o">(</span><span class="n">args</span><span class="k">:</span> <span class="kt">Array</span><span class="o">[</span><span class="kt">String</span><span class="o">])</span><span class="k">:</span> <span class="kt">Unit</span> <span class="o">=</span> <span class="o">{</span>
    <span class="k">def</span> <span class="nf">checkContinue</span><span class="o">(</span><span class="n">name</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Boolean</span><span class="o">]</span> <span class="k">=</span> <span class="k">for</span> <span class="o">{</span>
      <span class="k">_</span> <span class="k">&lt;-</span> <span class="nf">putStrLn</span><span class="o">(</span><span class="n">s</span><span class="s">"Do you want to continue $name?"</span><span class="o">)</span>
      <span class="n">input</span> <span class="k">&lt;-</span> <span class="n">getStrLn</span>
      <span class="n">cont</span> <span class="k">&lt;-</span>  <span class="nv">input</span><span class="o">.</span><span class="py">toLowerCase</span><span class="o">()</span> <span class="k">match</span> <span class="o">{</span>
          <span class="k">case</span> <span class="s">"y"</span> <span class="k">=&gt;</span> <span class="nv">IO</span><span class="o">.</span><span class="py">point</span><span class="o">(</span><span class="kc">true</span><span class="o">)</span>
          <span class="k">case</span> <span class="s">"n"</span> <span class="k">=&gt;</span> <span class="nv">IO</span><span class="o">.</span><span class="py">point</span><span class="o">(</span><span class="kc">false</span><span class="o">)</span>
          <span class="k">case</span> <span class="k">_</span> <span class="k">=&gt;</span> <span class="nf">checkContinue</span><span class="o">(</span><span class="n">name</span><span class="o">)</span>
        <span class="o">}</span>
    <span class="o">}</span> <span class="k">yield</span> <span class="n">cont</span>

    <span class="k">def</span> <span class="nf">gameLoop</span><span class="o">(</span><span class="n">name</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span> <span class="k">=</span> <span class="k">for</span> <span class="o">{</span>
      <span class="n">num</span> <span class="k">&lt;-</span> <span class="nf">randomNumber</span><span class="o">(</span><span class="mi">5</span><span class="o">).</span><span class="py">map</span><span class="o">(</span><span class="k">_</span> <span class="o">+</span> <span class="mi">1</span><span class="o">)</span>
      <span class="k">_</span>   <span class="k">&lt;-</span> <span class="nf">putStrLn</span><span class="o">(</span><span class="n">s</span><span class="s">"Dear $name, please guess a number from 1 to 5"</span><span class="o">)</span>
      <span class="n">input</span>   <span class="k">&lt;-</span> <span class="n">getStrLn</span>
      <span class="k">_</span>       <span class="k">&lt;-</span> <span class="nf">parseNumber</span><span class="o">(</span><span class="n">input</span><span class="o">)</span> <span class="k">match</span> <span class="o">{</span>
          <span class="k">case</span> <span class="nc">None</span> <span class="k">=&gt;</span> <span class="nf">putStrLn</span><span class="o">(</span><span class="s">"Not a number!"</span><span class="o">)</span>
          <span class="k">case</span> <span class="nc">Some</span><span class="o">(</span><span class="n">guess</span><span class="o">)</span> <span class="k">=&gt;</span>
            <span class="nf">if</span> <span class="o">(</span><span class="n">guess</span> <span class="o">==</span> <span class="n">num</span><span class="o">)</span> <span class="nf">putStrLn</span><span class="o">(</span><span class="n">s</span><span class="s">"You guessed right, $name!"</span><span class="o">)</span>
            <span class="k">else</span> <span class="nf">putStrLn</span><span class="o">(</span><span class="n">s</span><span class="s">"You guessed wrong, $name the number was $num"</span><span class="o">)</span>
        <span class="o">}</span>
      <span class="n">cont</span> <span class="k">&lt;-</span> <span class="nf">checkContinue</span><span class="o">(</span><span class="n">name</span><span class="o">)</span>
      <span class="k">_</span>    <span class="k">&lt;-</span> <span class="nf">if</span> <span class="o">(</span><span class="n">cont</span><span class="o">)</span> <span class="nf">gameLoop</span><span class="o">(</span><span class="n">name</span><span class="o">)</span> <span class="k">else</span> <span class="nv">IO</span><span class="o">.</span><span class="py">unit</span>
    <span class="o">}</span> <span class="nf">yield</span> <span class="o">()</span>

    <span class="k">val</span> <span class="nv">program</span><span class="k">:</span> <span class="kt">IO</span><span class="o">[</span><span class="kt">Unit</span><span class="o">]</span> <span class="k">=</span> <span class="k">for</span> <span class="o">{</span>
      <span class="k">_</span>     <span class="k">&lt;-</span> <span class="nf">putStrLn</span><span class="o">(</span><span class="s">"What is your name?"</span><span class="o">)</span>
      <span class="n">name</span>  <span class="k">&lt;-</span> <span class="n">getStrLn</span>
      <span class="k">_</span>     <span class="k">&lt;-</span> <span class="nf">putStrLn</span><span class="o">(</span><span class="n">s</span><span class="s">"Hello $name welcome to the game!"</span><span class="o">)</span>
      <span class="k">_</span>     <span class="k">&lt;-</span> <span class="nf">gameLoop</span><span class="o">(</span><span class="n">name</span><span class="o">)</span>
    <span class="o">}</span> <span class="nf">yield</span> <span class="o">()</span>

    <span class="nv">program</span><span class="o">.</span><span class="py">unsafeRun</span><span class="o">()</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Note that loops in functional programs are transformed into tail-recursive functions.  Note also that even though our functions are tail-recursive, our <code class="language-plaintext highlighter-rouge">IO</code> implementation is not, and this program will lead to stack overflow issues.  Multiple libraries implement a stack safe <code class="language-plaintext highlighter-rouge">IO</code>; we opted for simplicity to showcase how functional concepts relate. If you are going to use <code class="language-plaintext highlighter-rouge">IO</code> in production, I strongly recommend using <a href="https://typelevel.org/cats-effect/">Cats Effect</a>  or <a href="https://zio.dev/">ZIO</a>.</p>

<h1 id="conclusion">Conclusion</h1>
<p>This post transformed a procedural program into a functional program abiding to the three functional principles.  The final transformation is still not the end of the road to functional-town; we could expand this example further to categorise different types of <code class="language-plaintext highlighter-rouge">IO</code> (tag-less final), but we will leave that for another post.  For now, the take-home message is this:</p>

<p><em>Think of functional programming as a tool in your toolbox. You can always adjust the level of purity in your codebase to fit your comfort level.  What’s important is that whatever you do, try to be more principled.</em></p>

<p>As always, stay safe, keep hacking.</p>]]></content><author><name>Mark Galea</name></author><summary type="html"><![CDATA[This post is an adaptation of the talk FP to the max, credit goes to John A De Goes. We will take a minimal example written in a procedural style and introduce functional programming techniques and principles to create a more principled application. It is important to preface this post with a disclaimer which is :warning:Do not try this on your codebase!!:warning: - this example is an overkill and is only intended to help developers see how functional concepts can be applied on a small scale so that they can extrapolate these techniques on larger projects.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://cloudmark.github.io/images/lambda.jpg" /><media:content medium="image" url="http://cloudmark.github.io/images/lambda.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Node Management in GKE</title><link href="http://cloudmark.github.io/Node-Management-In-GKE/" rel="alternate" type="text/html" title="Node Management in GKE" /><published>2019-06-28T00:00:00+00:00</published><updated>2019-06-28T00:00:00+00:00</updated><id>http://cloudmark.github.io/Node-Management-In-GKE</id><content type="html" xml:base="http://cloudmark.github.io/Node-Management-In-GKE/"><![CDATA[<p><img class="title" src="/images/gke/gke.png" /> It’s been one heck of a week! I’m back from the Google Cloud Summit in Milan - #GoogleCloudSummit - where Mattia (@mattiagnd) and I spoke about <em>Node management in GKE</em>.  In this blog I would like to take some points discussed in that presentation and really outline some key takeaways; specifically what happens during an upgrade and what steps we (as clients of GKE) can take in order to manage disruptions.</p>

<h1 id="managing-the-fleet---gke-upgrades">Managing the fleet - GKE Upgrades</h1>
<p>One thing I’m really proud of at Suprnation is the fact that for the past three years we had very few crashes.  Even more impressive is the fact that our systems auto-recovered from such crashes.  Such an outcome is the result of an earlier decision to go reactive - see the <a href="https://www.reactivemanifesto.org/">reactive manifesto</a> - and the “let it crash” philosophy ingrained throughout our system.</p>

<p>Reactive Systems are typically composed of smaller components which cooperate together to achieve a common goal.  Deploying these small components is challenging; how do we isolate, schedule, configure and supervise these components? This is where Kubernetes comes in; it addresses all of these issues. Specifically we use Google Kubernetes Engine, the hosted Kubernetes engine offered by Google.</p>

<p>When using Kubernetes, systems administrators can focus on managing the fleet rather than manage individual components.  One challenging aspect of managing a fleet is upgrades.  On one hand upgrades give us access to the latest features, but on the other hand they disrupt our business.  So what goes on during an upgrade? Well let’s visualise the upgrade sequence.</p>

<p><img class="center" src="/images/gke/upgrade-1.png" /></p>

<p>Node by node, each node is drained, a new VM is created and GKE will wait for the VM to start running.  Once running, GKE will register the node with the master and become ready.  Once ready, the workload is resumed.  During this period - <em>disruption period</em> - your business might (and probably will) experience disruptions.</p>

<p>Can we do better? One feature which is coming up in the next release for GKE is <em>surge-upgrades</em>.  If we look at the previous disruption period we can see that certain things can be moved out.  Specifically, an extra VM - called a surge VM - can be created before draining the node. By creating an extra VM in this manner we can see that the disruption period shortens and is equal to the time it requires Kubernetes to reschedule your workload from node-to-node.  Visually this looks as follows</p>

<p><img class="center" src="/images/gke/upgrade-2.png" /></p>

<p>Surge upgrades will really help us reduce disruptions faced by our clients but this is not a silver bullet.  There is only so much magic Google can do in order to make sure that our applications are reliable.  There are things which we can ourselves in order to protect ourselves against disruptions.  So what are disruptions?</p>

<h1 id="workload-disruptions">Workload Disruptions</h1>
<p>Let’s create a simple application and deploy this on a cluster in order to understand better what workload disruptions are.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">http</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">http</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">os</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">os</span><span class="dl">'</span><span class="p">);</span>

<span class="kd">var</span> <span class="nx">handler</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">request</span><span class="p">,</span> <span class="nx">response</span><span class="p">)</span> <span class="p">{</span>
  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">Received request from </span><span class="dl">"</span> <span class="o">+</span> <span class="nx">request</span><span class="p">.</span><span class="nx">connection</span><span class="p">.</span><span class="nx">remoteAddress</span><span class="p">);</span>
  <span class="nx">response</span><span class="p">.</span><span class="nx">writeHead</span><span class="p">(</span><span class="mi">200</span><span class="p">);</span>
  <span class="nx">response</span><span class="p">.</span><span class="nx">end</span><span class="p">(</span><span class="dl">"</span><span class="s2">Hit </span><span class="dl">"</span> <span class="o">+</span> <span class="nx">os</span><span class="p">.</span><span class="nx">hostname</span><span class="p">()</span> <span class="o">+</span> <span class="dl">"</span><span class="se">\n</span><span class="dl">"</span><span class="p">);</span>
<span class="p">};</span>

<span class="nx">http</span><span class="p">.</span><span class="nx">createServer</span><span class="p">(</span><span class="nx">handler</span><span class="p">).</span><span class="nx">listen</span><span class="p">(</span><span class="mi">8080</span><span class="p">);</span>
</code></pre></div></div>

<p>As you can see from the code at the top we are creating a simple server which responds to a client request.  We package this application, deploy it on a three-node cluster and expose it via a service by using the following commands</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> kubectl run platform <span class="nt">--labels</span><span class="o">=</span><span class="s2">"app=platform"</span> <span class="nt">--image</span><span class="o">=</span>platform:v1 <span class="nt">--port</span><span class="o">=</span>8080
<span class="o">&gt;</span> kubectl expose deployment platform <span class="nt">--type</span><span class="o">=</span>LoadBalancer <span class="nt">--port</span><span class="o">=</span>8080 <span class="nt">--name</span> platform-http
</code></pre></div></div>

<p>Visually, this is what we have achieved</p>

<p><img class="center" style="width: 480px" src="/images/gke/gke-1.png" /></p>

<p>So what’s happening here? The client will hit the HTTP endpoint and the service will forward the request to one of the available pods to get serviced.  If no pods are available the client will fail to connect.</p>

<p>So let’s run an upgrade scenario.  As we mentioned previously, during an upgrade a node is taken down and all pods running on that node are evicted.  What this means is that our application will start throwing errors since the pod is evicted but requests are still hitting the endpoint.  Of course Kubernetes reschedules the pod and the situation recovers but there is this inevitable period where our application will surely serve errors if hit.  Visually this scenario looks as follows</p>

<p><img class="center" style="width: 480px" src="/images/gke/gke-2.png" /></p>

<h2 id="replicas">Replicas</h2>
<p>So what can we do to mitigate this situation? One obvious thing to do here is to increase the number of replicas that we have.  Let’s update the deployment to scale up to 3 replicas.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">apiVersion</span><span class="pi">:</span> <span class="s">extensions/v1beta1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Deployment</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">labels</span><span class="pi">:</span>
    <span class="na">app</span><span class="pi">:</span> <span class="s">platform</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">platform</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">replicas</span><span class="pi">:</span> <span class="m">3</span>
  <span class="na">selector</span><span class="pi">:</span>
    <span class="na">matchLabels</span><span class="pi">:</span>
      <span class="na">app</span><span class="pi">:</span> <span class="s">platform</span>
  <span class="na">template</span><span class="pi">:</span>
    <span class="na">spec</span><span class="pi">:</span>
      <span class="na">containers</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">image</span><span class="pi">:</span> <span class="s">platform:v1</span>
        <span class="na">name</span><span class="pi">:</span> <span class="s">platform</span>
        <span class="na">ports</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="na">containerPort</span><span class="pi">:</span> <span class="m">8080</span>
          <span class="na">protocol</span><span class="pi">:</span> <span class="s">TCP</span>

</code></pre></div></div>

<p>Alternatively we can use the command</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> kubectl scale deployment platform <span class="nt">--replicas</span><span class="o">=</span>3
</code></pre></div></div>

<p>Immediately we have three pods scheduled and running.  One important question to ask here is but <em>Where are these pods running?</em> In this case we can see that we have one pod running on node 1 and two pods running on node 2.  Let’s really digest what this means in an upgrade scenario.</p>

<p><img class="center" style="width: 480px" src="/images/gke/gke-3.png" /></p>

<p>When node 1 is upgrading, the pod is evicted. In contrast to what we had before our clients are still being serviced since we have 2/3 of our capacity available.</p>

<p><img class="center" style="width: 480px" src="/images/gke/gke-4-2.png" /></p>

<p>Once again the pod is rescheduled to run on a different node; in this case let’s assume it’s node 3.</p>

<p><img class="center" style="width: 480px" src="/images/gke/gke-4-3.png" /></p>

<p>When we upgrade node 2, we end up in a situation where we lose 2/3 of our serving capacity. The clients are still being served by the pod on node 3 but under high load this situation might be uncomfortable.</p>

<p><img class="center" style="width: 480px" src="/images/gke/gke-5-2.png" /></p>

<p>Once again, the two pods are rescheduled by Kubernetes and this situations recovers.</p>

<p><img class="center" style="width: 480px" src="/images/gke/gke-5-3.png" /></p>

<p>This is clearly not good enough. So, what can we do further?</p>

<h2 id="pod-anti-affinity-rules">Pod anti-affinity rules</h2>
<p>What we can do in this case is tell the scheduler “Hey, I know what I’m doing, try to schedule those particular replicas on different nodes”. Which is to say that we plan to use <a href="https://kubernetes.io/docs/concepts/configuration/assign-pod-node/">pod anti-affinity</a>.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># File: affinity-patch.yaml</span>
<span class="na">affinity</span><span class="pi">:</span>
   <span class="na">podAntiAffinity</span><span class="pi">:</span>
     <span class="na">requiredDuringSchedulingIgnoredDuringExecution</span><span class="pi">:</span>
     <span class="pi">-</span> <span class="na">labelSelector</span><span class="pi">:</span>
         <span class="na">matchLabels</span><span class="pi">:</span>
           <span class="na">app</span><span class="pi">:</span> <span class="s">platform</span>
       <span class="na">topologyKey</span><span class="pi">:</span> <span class="s2">"</span><span class="s">kubernetes.io/hostname"</span>

</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> kubectl patch deployment platform <span class="nt">--patch</span> <span class="s2">"</span><span class="si">$(</span><span class="nb">cat </span>affinity-patch.yaml<span class="si">)</span><span class="s2">"</span>
</code></pre></div></div>

<p>Once we update our deployment to use pod anti-affinity the scheduler distributes the pods evenly across the nodes.</p>

<p><img class="center" style="width: 480px" src="/images/gke/gke-6.png" /></p>

<p>Here, you can rely on the fact that 2/3 of the client capacity will always be available during an upgrade.</p>

<h2 id="take-away-1---redundancy">Take away #1 - Redundancy</h2>
<p>Replicas and Pod Anti-Affinity rules lead us to our first take away - redundancy.  There are many things which GKE does (such as surge upgrades) but we have to help ourselves by giving ourselves a little bit of slack.  Here we are going to use the simplest formula from SRE - N+1 - which informally translates to “give yourself some breathing room”.  Not only that but also use this breathing room as an advantage.  You can think of your application as different fault domains that you want to separate and run individually so if part of your application fails the others can survive and serve traffic.</p>

<h1 id="protection">Protection</h1>
<p>So, is redundancy enough? Let’s have a look.  Ralph (a.k.a Wreck It Ralph since the incident) joined the team and was working on a script.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="nx">node</span> <span class="k">in</span> <span class="s2">`kubectl get nodes -o jsonpath='{range.items[*]}{.metadata.name} '`</span>
<span class="k">do</span>
	<span class="nx">drain</span><span class="o">=</span><span class="dl">"</span><span class="s2">kubectl drain $node --ignore-daemonsets &amp;</span><span class="dl">"</span>
	<span class="nb">eval</span> <span class="nx">$drain</span>
<span class="nx">done</span>
</code></pre></div></div>

<p>As it turns out this script ended up draining the cluster causing a total outage; Ralph cordoned all the nodes and also evicted all the pods.</p>

<p><img class="center" style="width: 480px" src="/images/gke/gke-7.png" /></p>

<p>What can we do to protect our pods?</p>

<h2 id="pod-disruption-budgets">Pod disruption budgets</h2>
<p>Here we can see that this is an honest mistake but the key takeaway here is that no amount of redundancy could have saved us.</p>

<p>What can we do to protect ourselves from this situation? Kubernetes is such a huge universe that there are many mechanisms.  One simple thing we can do here is to add a <a href="https://kubernetes.io/docs/concepts/workloads/pods/disruptions/">pod disruption budget</a>.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># pod-disruption-budget-platform.yaml</span>
<span class="na">apiVersion</span><span class="pi">:</span> <span class="s">policy/v1beta1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">PodDisruptionBudget</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">platform-pdb</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">minAvailable</span><span class="pi">:</span> <span class="m">2</span>
  <span class="na">selector</span><span class="pi">:</span>
    <span class="na">matchLabels</span><span class="pi">:</span>
      <span class="na">app</span><span class="pi">:</span> <span class="s">platform</span>

</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> kubectl create <span class="nt">-f</span> pod-disruption-budget-platform.yaml
</code></pre></div></div>

<p>A pod disruption budget is a place where you say to Kubernetes “OK, these are the pods that I want to protect”.  In this case the rule we want to apply is the <code class="language-plaintext highlighter-rouge">minAvailable</code>.  What this means is that at any point in time there should be at least 2 pods available.  There are other rules like <code class="language-plaintext highlighter-rouge">maxUnavailable</code>, which specifies how many at a time can be unavailable.</p>

<p>If Ralph tries to drain everything again he will get these error messages.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>error when evicting pod "platform-68ddf77fc8-44hch" (will retry after 5s):
Cannot evict pod as it would violate the pod's disruption budget.

error when evicting pod "platform-578f5c9499-vrgtq" (will retry after 5s):
Cannot evict pod as it would violate the pod's disruption budget.
</code></pre></div></div>

<p>The scheduler here is telling us that it cannot evict the pod because it would violate the rules.</p>

<p>Let’s look at the current situation of pods and nodes below.</p>

<p><img class="center" style="width: 480px" src="/images/gke/gke-8.png" /></p>

<p>As you can see, we still did some damage here.  We got rid of one pod from node 1 and that all nodes have been cordoned but what’s important here is that there is no total outage.  We are still serving traffic and we have time to recover.</p>

<h2 id="take-away-2---protection">Take away #2 - Protection</h2>
<p>So redundancy is not enough. You have to put some protection if you are extra paranoid and it’s good to be extra paranoid for sensitive resources.</p>

<h1 id="liveness-and-readiness-probes">Liveness and Readiness Probes</h1>
<p>Kubernetes does not know what an application running inside a pod is doing - it’s a black box.  If a pod crashes Kubernetes will automatically restart it but at times applications stop working without their underlying process crashing.  For example, out of memory exceptions in Java or wrong application code.  Let’s have a look</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">requestCount</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

<span class="kd">var</span> <span class="nx">handler</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">request</span><span class="p">,</span> <span class="nx">response</span><span class="p">)</span> <span class="p">{</span>
  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">Received request from </span><span class="dl">"</span> <span class="o">+</span> <span class="nx">request</span><span class="p">.</span><span class="nx">connection</span><span class="p">.</span><span class="nx">remoteAddress</span><span class="p">);</span>
  <span class="nx">requestCount</span><span class="o">++</span><span class="p">;</span>
  <span class="k">if</span> <span class="p">(</span><span class="nx">requestCount</span> <span class="o">&gt;</span> <span class="mi">5</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">response</span><span class="p">.</span><span class="nx">writeHead</span><span class="p">(</span><span class="mi">500</span><span class="p">);</span>
    <span class="nx">response</span><span class="p">.</span><span class="nx">end</span><span class="p">(</span><span class="dl">"</span><span class="s2">I'm not well!</span><span class="dl">"</span><span class="p">);</span>
    <span class="k">return</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="nx">response</span><span class="p">.</span><span class="nx">writeHead</span><span class="p">(</span><span class="mi">200</span><span class="p">);</span>
  <span class="nx">response</span><span class="p">.</span><span class="nx">end</span><span class="p">(</span><span class="dl">"</span><span class="s2">I’m healthy!);
};
</span></code></pre></div></div>

<p>One of our developers accidentally made changes to the handler logic of our application.  After 5 request our application will reply with HTTP status code 500.  This is clearly not what we wanted.  After approximately 15 requests all of our replicas will start reporting 500 errors.</p>

<p><img class="center" style="width: 960px" src="/images/gke/gke-9.png" /></p>

<p>From a Kubernetes point-of-view the application is healthy and no pods are restarted.  But we can do better than this.  By giving Kubernetes some insight into our pods Kubernetes can help us out.  We do this specifically with the <a href="https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/">readiness and the liveness probe</a>.</p>

<ul>
  <li>
    <p><strong>Liveness probe</strong> determines whether your application is healthy enough.  If the application is not healthy, Kubernetes will restart the pod.</p>
  </li>
  <li>
    <p><strong>Readiness probe</strong> allows Kubernetes to check whether your application is ready to receive traffic but will not restart the pod.</p>
  </li>
</ul>

<p>In case of our simple application we will use an HTTP probe to determine whether the application is healthy (liveness)</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">livenessProbe</span><span class="pi">:</span>
  <span class="na">httpGet</span><span class="pi">:</span>
    <span class="na">path</span><span class="pi">:</span> <span class="s">/</span>
    <span class="na">port</span><span class="pi">:</span> <span class="m">8080</span>
  <span class="na">initialDelaySeconds</span><span class="pi">:</span> <span class="m">3</span>
  <span class="na">periodSeconds</span><span class="pi">:</span> <span class="m">3</span>
</code></pre></div></div>

<p>As soon as the pod starts returning errors, the pod will fail the liveness check and will eventually be restarted.</p>

<h2 id="take-away-3---insights">Take away #3 - Insights</h2>
<p>So take away number three, help Kubernetes help you by giving Kubernetes insight into when your application is ready and available.</p>

<h1 id="additional-protection-mechanisms">Additional Protection Mechanisms</h1>
<p>There are other features in GKE which are worth mentioning.</p>

<ul>
  <li>
    <p><strong>Surge Upgrades</strong> First feature, which we already discussed, is <strong>surge upgrades</strong>.  Surge upgrades will really reduce the disruption times by creating an extra VM before draining old nodes.</p>
  </li>
  <li>
    <p><strong>Enhanced Maintenance Windows</strong>  Google has a feature called auto-upgrades which automatically updates worker nodes.  Unfortunately this feature is rarely used since this takes a lot of control from us.  As application administrators we want to be fully in control when an upgrade happens since we want to really reduce the impact to our business.  Enhanced Maintenance windows allow us to specify that we want to avoid upgrades during inappropriate times such as weekends, Black Friday or Cyber Mondays.  Furthermore, enhanced maintenance windows allow us to postpone (snooze) a schedule for a short period of time.</p>
  </li>
  <li>
    <p><strong>Canary Clusters</strong> This enables us to create canary clusters and link them to our production clusters.  This will indicate to GKE to roll out new versions to the canary cluster first, allowing us to run automated tests.  Roll out to production clusters will be conditioned on the results of these tests.</p>
  </li>
</ul>

<h1 id="conclusion">Conclusion</h1>
<p>In this blog post we looked at how we can control disruptions during node upgrades. In summary we should really focus on three take aways</p>

<ul>
  <li><strong>Redundancy</strong> - give yourself some slack by adding more replicas and using pod anti-affinity rules</li>
  <li><strong>Protection</strong> - put protection mechanisms in place for pods which you want to protect</li>
  <li><strong>Insights</strong> - give Kubernetes a bit more insight into your pods via liveness and readiness probes.</li>
</ul>

<p>There are also some interesting features coming up which you should look out for such as surge upgrades and enhanced maintenance windows which will help us further control disruptions.  As always, stay safe, keep hacking.</p>]]></content><author><name>Mark Galea</name></author><summary type="html"><![CDATA[It’s been one heck of a week! I’m back from the Google Cloud Summit in Milan - #GoogleCloudSummit - where Mattia (@mattiagnd) and I spoke about Node management in GKE. In this blog I would like to take some points discussed in that presentation and really outline some key takeaways; specifically what happens during an upgrade and what steps we (as clients of GKE) can take in order to manage disruptions.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://cloudmark.github.io/images/gke/gke.png" /><media:content medium="image" url="http://cloudmark.github.io/images/gke/gke.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Performant Functional Programming to the max with ZIO</title><link href="http://cloudmark.github.io/A-Journey-To-Zio/" rel="alternate" type="text/html" title="Performant Functional Programming to the max with ZIO" /><published>2019-05-18T00:00:00+00:00</published><updated>2019-05-18T00:00:00+00:00</updated><id>http://cloudmark.github.io/A-Journey-To-Zio</id><content type="html" xml:base="http://cloudmark.github.io/A-Journey-To-Zio/"><![CDATA[<p><img class="title" src="/images/zio/zio.png" /> I have been doing functional programming for quite some time in the small - <code class="language-plaintext highlighter-rouge">map</code>, <code class="language-plaintext highlighter-rouge">filter</code>, <code class="language-plaintext highlighter-rouge">flatMap</code>, <code class="language-plaintext highlighter-rouge">for</code> comprehensions, catz etc.  While I was sold on the great benefits of FP I’ve struggled to transition to doing FP in the large without hitting runtime overheads.  This is where <a href="https://github.com/scalaz/scalaz-zio">ZIO</a> comes in the picture.  ZIO makes programming in the large simple and provides the ability to interop with other parts of the broader functional ecosystem.  In this blog post I will describe a fictitious business problem, implement it in an imperative way and rewrite the application in a functional “equivalent” using ZIO.</p>

<h1 id="acme-corp">Acme Corp</h1>
<p>Acme Corporation is a company that sells a variety of items - for a full catalogue <a href="http://www.acme.com/catalog/acme.html">click here </a>.  Customers log in via their email address and order products.  Wile E. Coyote, the Product Owner, also wants customers to be able to retrieve a summary of their product purchases via their email address.</p>

<p>Throughout our code samples, we will model our domain using these case classes: <code class="language-plaintext highlighter-rouge">User</code>, <code class="language-plaintext highlighter-rouge">Product</code> and <code class="language-plaintext highlighter-rouge">PurchaseHistory</code>.  <code class="language-plaintext highlighter-rouge">User</code> represents a logged in user, <code class="language-plaintext highlighter-rouge">Product</code> represents a purchased product and <code class="language-plaintext highlighter-rouge">PurchaseHistory</code> represents the product purchase summary for a logged in user.</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">case</span> <span class="k">class</span> <span class="nc">User</span><span class="o">(</span><span class="n">id</span><span class="k">:</span> <span class="kt">Long</span><span class="o">,</span> <span class="n">email</span><span class="k">:</span> <span class="kt">String</span><span class="o">,</span> <span class="n">name</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span>
<span class="k">case</span> <span class="k">class</span> <span class="nc">Product</span><span class="o">(</span><span class="n">id</span><span class="k">:</span> <span class="kt">Long</span><span class="o">,</span> <span class="n">description</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span>
<span class="k">case</span> <span class="k">class</span> <span class="nc">PurchaseHistory</span><span class="o">(</span><span class="n">email</span><span class="k">:</span> <span class="kt">String</span><span class="o">,</span> <span class="n">name</span><span class="k">:</span> <span class="kt">String</span><span class="o">,</span> <span class="n">purchases</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">Product</span><span class="o">])</span>
</code></pre></div></div>

<h1 id="imperative-solution">Imperative Solution</h1>
<p>Wile’s product vision can be implemented imperatively as follows</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">object</span> <span class="nc">ImperativeApp</span> <span class="o">{</span>
  <span class="k">private</span><span class="o">[</span><span class="kt">this</span><span class="o">]</span> <span class="k">def</span> <span class="nf">getProductsForUser</span><span class="o">(</span><span class="n">userId</span><span class="k">:</span> <span class="kt">Long</span><span class="o">)</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">Product</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
    <span class="n">userId</span> <span class="k">match</span> <span class="o">{</span>
      <span class="k">case</span> <span class="mi">1</span> <span class="k">=&gt;</span> <span class="nc">List</span><span class="o">(</span><span class="nc">Product</span><span class="o">(</span><span class="mi">1L</span><span class="o">,</span> <span class="s">"Bird Seeds"</span><span class="o">),</span> <span class="nc">Product</span><span class="o">(</span><span class="mi">2L</span><span class="o">,</span> <span class="s">"Artificial Rock"</span><span class="o">))</span>
      <span class="k">case</span> <span class="k">_</span> <span class="k">=&gt;</span> <span class="nv">List</span><span class="o">.</span><span class="py">empty</span><span class="o">[</span><span class="kt">Product</span><span class="o">]</span>
    <span class="o">}</span>
  <span class="o">}</span>

  <span class="k">private</span><span class="o">[</span><span class="kt">this</span><span class="o">]</span> <span class="k">def</span> <span class="nf">searchUserAccount</span><span class="o">(</span><span class="n">email</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span><span class="k">:</span> <span class="kt">User</span> <span class="o">=</span> <span class="o">{</span>
    <span class="n">email</span> <span class="k">match</span> <span class="o">{</span>
      <span class="k">case</span> <span class="s">"wile@acme.com"</span> <span class="k">=&gt;</span> <span class="nc">User</span><span class="o">(</span><span class="mi">1L</span><span class="o">,</span> <span class="s">"wile@acme.com"</span><span class="o">,</span> <span class="s">"Will"</span><span class="o">)</span>
      <span class="k">case</span> <span class="k">_</span> <span class="k">=&gt;</span>
        <span class="nv">Logger</span><span class="o">.</span><span class="py">log</span><span class="o">(</span><span class="n">s</span><span class="s">"User $email is not in the database"</span><span class="o">)</span>
        <span class="k">throw</span> <span class="k">new</span> <span class="nc">RuntimeException</span><span class="o">(</span><span class="s">"User not found!"</span><span class="o">)</span>
    <span class="o">}</span>
  <span class="o">}</span>

  <span class="k">def</span> <span class="nf">getAllUserData</span><span class="o">(</span><span class="n">email</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span><span class="k">:</span> <span class="kt">PurchaseHistory</span> <span class="o">=</span> <span class="o">{</span>
    <span class="nv">Logger</span><span class="o">.</span><span class="py">log</span><span class="o">(</span><span class="n">s</span><span class="s">"Searching For User Account $email"</span><span class="o">)</span>
    <span class="k">val</span> <span class="nv">user</span> <span class="k">=</span> <span class="nf">searchUserAccount</span><span class="o">(</span><span class="n">email</span><span class="o">)</span>
    <span class="k">val</span> <span class="nv">products</span> <span class="k">=</span> <span class="nf">getProductsForUser</span><span class="o">(</span><span class="nv">user</span><span class="o">.</span><span class="py">id</span><span class="o">)</span>
    <span class="nc">PurchaseHistory</span><span class="o">(</span><span class="nv">user</span><span class="o">.</span><span class="py">email</span><span class="o">,</span> <span class="nv">user</span><span class="o">.</span><span class="py">name</span><span class="o">,</span> <span class="n">products</span><span class="o">)</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>The method <code class="language-plaintext highlighter-rouge">getAllUserData</code> is a method which given a user’s email address will first search for the user in the Acme database - <code class="language-plaintext highlighter-rouge">searchUserAccount</code> - and if present, loads all the purchased products for the user - <code class="language-plaintext highlighter-rouge">getProductsForUser</code>. We can run our program as follows</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">main</span><span class="o">(</span><span class="n">args</span><span class="k">:</span> <span class="kt">Array</span><span class="o">[</span><span class="kt">String</span><span class="o">])</span><span class="k">:</span> <span class="kt">Unit</span> <span class="o">=</span> <span class="o">{</span>
  <span class="k">try</span> <span class="o">{</span>
    <span class="k">val</span> <span class="nv">PurchaseHistory</span> <span class="k">=</span> <span class="nf">getAllUserData</span><span class="o">(</span><span class="s">"wile@acme.com"</span><span class="o">)</span>
    <span class="nv">Logger</span><span class="o">.</span><span class="py">log</span><span class="o">(</span><span class="n">s</span><span class="s">"Retrieved $PurchaseHistory"</span><span class="o">)</span>
  <span class="o">}</span> <span class="k">catch</span> <span class="o">{</span>
    <span class="k">case</span> <span class="n">e</span><span class="k">:</span> <span class="kt">Throwable</span> <span class="o">=&gt;</span> <span class="nv">Logger</span><span class="o">.</span><span class="py">log</span><span class="o">(</span><span class="n">s</span><span class="s">"Error Occurred $e"</span><span class="o">)</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Note that we have to wrap our calls with a <code class="language-plaintext highlighter-rouge">try/catch</code>, because our implementation throws exceptions.  Try <code class="language-plaintext highlighter-rouge">beepbeep@acme.com</code> and see what happens - as always Acme products explode! :boom: :fire:</p>

<h1 id="whats-the-problem-doc">What’s the problem doc?</h1>
<p>Imperative programming is all about procedures.  Procedures are</p>

<ul>
  <li><strong>Partial</strong> - Procedures do not return values for some inputs (e.g. at times they throw exceptions).</li>
  <li><strong>Non-Deterministic</strong> - Procedures return different outputs for the same input. This typically implies share state.</li>
  <li><strong>Impure</strong> - Procedures perform side-effects which mutate data or interact with the outside world.</li>
</ul>

<p>In the imperative implementation, <code class="language-plaintext highlighter-rouge">searchUserAccount</code> is partial and impure. Partial since it throws exceptions for any email which is not <code class="language-plaintext highlighter-rouge">wile@acme.com</code> and impure since it interacts with the logging environment which can have additional side-effects (e.g. transfer logs to a remote server). Compare this with <code class="language-plaintext highlighter-rouge">getProductsForUser</code> which is total (not partial), deterministic and pure.</p>

<p>Imperative programs are harder to reason about since it is impossible to determine from the signature what is happening inside.  In the implementation above, <code class="language-plaintext highlighter-rouge">searchUserAccount</code> declares that it always returns a <code class="language-plaintext highlighter-rouge">User</code> given an <code class="language-plaintext highlighter-rouge">email</code> which is clearly not the case.</p>

<p>Functional programming is all about pure functions.  Pure functions have three properties:</p>

<ul>
  <li><strong>Total</strong> - Return a value for every possible input.</li>
  <li><strong>Deterministic</strong> - Return the same value for the same input.</li>
  <li><strong>Inculpable</strong> - No (direct) interactions with the world or program state.</li>
</ul>

<p>Together these properties give us an incredible ability to reason about programs. <a href="https://leanpub.com/fpmortals">Functional Programming for Mortals</a> is an excellent resource if you are interested in learning further about the benefits of these properties.   Let’s see how we can refactor our program to get these desired properties.</p>

<h1 id="modelling-effects-with-monad-transformers">Modelling Effects with Monad Transformers</h1>
<p>One approach which has been recommended in Scala community is to model such problems using <a href="http://book.realworldhaskell.org/read/monad-transformers.html">Monad Transformers</a>.  I’m including this technique in this blog for one reason - <strong>to avoid it!</strong> This technique should be avoided since it leads to slow performance and large heap-churns.  <em>If you are using Monad Transformers today please stop and read on <a href="http://degoes.net/articles/rotating-effects">Effect Rotation</a>.  Note that this technique is still better than imperative, so if you are using this technique today in production don’t despair! (I’m in that spot exactly)</em></p>

<p>Let’s look at the update program</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">type</span> <span class="kt">Error</span> <span class="o">=</span> <span class="nc">String</span>
<span class="k">type</span> <span class="kt">Log</span> <span class="o">=</span> <span class="nc">Vector</span><span class="o">[</span><span class="kt">String</span><span class="o">]</span>

<span class="k">object</span> <span class="nc">MonadTransformerApp</span> <span class="o">{</span>
  <span class="k">private</span><span class="o">[</span><span class="kt">this</span><span class="o">]</span> <span class="k">def</span> <span class="nf">getProductsForUser</span><span class="o">(</span><span class="n">userId</span><span class="k">:</span> <span class="kt">Long</span><span class="o">)</span><span class="k">:</span>
    <span class="kt">SourcedEitherT</span><span class="o">[</span><span class="kt">Log</span>, <span class="kt">Error</span>, <span class="kt">List</span><span class="o">[</span><span class="kt">Product</span><span class="o">]]</span> <span class="k">=</span> <span class="o">{</span>
    <span class="n">userId</span> <span class="k">match</span> <span class="o">{</span>
      <span class="k">case</span> <span class="mi">1</span> <span class="k">=&gt;</span> <span class="nc">List</span><span class="o">(</span><span class="nc">Product</span><span class="o">(</span><span class="mi">1L</span><span class="o">,</span> <span class="s">"Bird Seeds"</span><span class="o">),</span> <span class="nc">Product</span><span class="o">(</span><span class="mi">2L</span><span class="o">,</span> <span class="s">"Artificial Rock"</span><span class="o">)).</span><span class="py">pureT</span>
      <span class="k">case</span> <span class="k">_</span> <span class="k">=&gt;</span> <span class="nv">List</span><span class="o">.</span><span class="py">empty</span><span class="o">[</span><span class="kt">Product</span><span class="o">].</span><span class="py">pureT</span>
    <span class="o">}</span>
  <span class="o">}</span>

  <span class="k">private</span><span class="o">[</span><span class="kt">this</span><span class="o">]</span> <span class="k">def</span> <span class="nf">searchUserAccount</span><span class="o">(</span><span class="n">email</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span><span class="k">:</span>
    <span class="kt">SourcedEitherT</span><span class="o">[</span><span class="kt">Log</span>, <span class="kt">Error</span>, <span class="kt">User</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
    <span class="n">email</span> <span class="k">match</span> <span class="o">{</span>
      <span class="k">case</span> <span class="s">"wile@acme.com"</span> <span class="k">=&gt;</span> <span class="nc">User</span><span class="o">(</span><span class="mi">1L</span><span class="o">,</span> <span class="s">"wile@acme.com"</span><span class="o">,</span> <span class="s">"Will"</span><span class="o">).</span><span class="py">pureT</span>
      <span class="k">case</span> <span class="k">_</span> <span class="k">=&gt;</span> <span class="k">for</span> <span class="o">{</span>
        <span class="k">_</span> <span class="k">&lt;-</span> <span class="nc">Vector</span><span class="o">(</span><span class="n">s</span><span class="s">"User $email is not in the database"</span><span class="o">).</span><span class="py">logT</span>
        <span class="n">error</span> <span class="k">&lt;-</span> <span class="s">"User not in our database.  "</span><span class="o">.</span><span class="py">raiseT</span><span class="o">[</span><span class="kt">Log</span>, <span class="kt">User</span><span class="o">]</span>
      <span class="o">}</span> <span class="k">yield</span> <span class="n">error</span>
    <span class="o">}</span>
  <span class="o">}</span>

  <span class="k">def</span> <span class="nf">getAllUserData</span><span class="o">(</span><span class="n">email</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span><span class="k">:</span>
    <span class="kt">SourcedEitherT</span><span class="o">[</span><span class="kt">Log</span>, <span class="kt">Error</span>, <span class="kt">PurchaseHistory</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
    <span class="k">for</span> <span class="o">{</span>
      <span class="k">_</span> <span class="k">&lt;-</span> <span class="nc">Vector</span><span class="o">(</span><span class="n">s</span><span class="s">"Searching For User Account $email"</span><span class="o">).</span><span class="py">logT</span>
      <span class="n">user</span> <span class="k">&lt;-</span> <span class="nf">searchUserAccount</span><span class="o">(</span><span class="n">email</span><span class="o">)</span>
      <span class="k">_</span> <span class="k">&lt;-</span> <span class="nc">Vector</span><span class="o">(</span><span class="n">s</span><span class="s">"Searching For Products For Account $email"</span><span class="o">).</span><span class="py">logT</span>
      <span class="n">products</span> <span class="k">&lt;-</span> <span class="nf">getProductsForUser</span><span class="o">(</span><span class="nv">user</span><span class="o">.</span><span class="py">id</span><span class="o">)</span>
    <span class="o">}</span> <span class="k">yield</span> <span class="nc">PurchaseHistory</span><span class="o">(</span><span class="nv">user</span><span class="o">.</span><span class="py">email</span><span class="o">,</span> <span class="nv">user</span><span class="o">.</span><span class="py">name</span><span class="o">,</span> <span class="n">products</span><span class="o">)</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>So what’s the advantage? Well for one our functions are pure; they are total, deterministic and inculpable.  As an example <code class="language-plaintext highlighter-rouge">searchUserAccount</code> now always returns a value (could be an error value) and does not interact directly with the log environment.</p>

<p>In contrast to our previous implementation the types here are honest e.g.</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">private</span><span class="o">[</span><span class="kt">this</span><span class="o">]</span> <span class="k">def</span> <span class="nf">searchUserAccount</span><span class="o">(</span><span class="n">email</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span><span class="k">:</span> <span class="kt">SourcedEitherT</span><span class="o">[</span><span class="kt">Log</span>, <span class="kt">Error</span>, <span class="kt">User</span><span class="o">]</span>
</code></pre></div></div>

<p>The above declares that the function will log via a <code class="language-plaintext highlighter-rouge">Writer</code> of type <code class="language-plaintext highlighter-rouge">Log</code> and return an <code class="language-plaintext highlighter-rouge">Error</code> on failure  or a <code class="language-plaintext highlighter-rouge">User</code> on success. Such honesty allows us to reason clearly about our business logic and refactor with confidence.  Additionally, this new implementation avoids throwing and catching exceptions which is broken in async environments.</p>

<p>For completeness I’m including the details of the <code class="language-plaintext highlighter-rouge">SourcedEitherT</code> stack together with the helper functions used.  Seriously though, don’t try this at home (or work)!</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">type</span> <span class="kt">SourcedEitherT</span><span class="o">[</span><span class="kt">Raw</span>, <span class="kt">Err</span>, <span class="kt">Value</span><span class="o">]</span> <span class="k">=</span> <span class="nc">EitherT</span><span class="o">[</span><span class="kt">Writer</span><span class="o">[</span><span class="kt">Raw</span>, <span class="kt">?</span><span class="o">]</span>, <span class="kt">Err</span>, <span class="kt">Value</span><span class="o">]</span>
<span class="k">type</span> <span class="kt">Error</span> <span class="o">=</span> <span class="nc">String</span>
<span class="k">type</span> <span class="kt">Log</span> <span class="o">=</span> <span class="nc">Vector</span><span class="o">[</span><span class="kt">String</span><span class="o">]</span>

<span class="c1">// Monad Transforms are painful!</span>
<span class="k">implicit</span> <span class="k">class</span> <span class="nc">SourcedEitherSyntax</span><span class="o">[</span><span class="kt">A</span><span class="o">](</span><span class="n">a</span><span class="k">:</span> <span class="kt">A</span><span class="o">)</span> <span class="o">{</span>
  <span class="k">def</span> <span class="nf">logT</span><span class="o">[</span><span class="kt">Err</span><span class="o">]</span><span class="k">:</span> <span class="kt">EitherT</span><span class="o">[</span><span class="kt">Writer</span><span class="o">[</span><span class="kt">A</span>, <span class="kt">?</span><span class="o">]</span>, <span class="kt">Error</span>, <span class="kt">Unit</span><span class="o">]</span> <span class="k">=</span> <span class="nc">EitherT</span><span class="o">[</span><span class="kt">Writer</span><span class="o">[</span><span class="kt">A</span>, <span class="kt">?</span><span class="o">]</span>, <span class="kt">Error</span>, <span class="kt">Unit</span><span class="o">](</span><span class="nc">Writer</span><span class="o">(</span><span class="n">a</span><span class="o">,</span> <span class="o">().</span><span class="py">asRight</span><span class="o">[</span><span class="kt">Error</span><span class="o">]))</span>

  <span class="k">def</span> <span class="nf">pureT</span><span class="o">[</span><span class="kt">Log</span>, <span class="kt">Err</span><span class="o">](</span><span class="k">implicit</span> <span class="n">evidence</span><span class="k">:</span> <span class="kt">Monoid</span><span class="o">[</span><span class="kt">Log</span><span class="o">])</span><span class="k">:</span> <span class="kt">EitherT</span><span class="o">[</span><span class="kt">Writer</span><span class="o">[</span><span class="kt">Log</span>, <span class="kt">?</span><span class="o">]</span>, <span class="kt">Error</span>, <span class="kt">A</span><span class="o">]</span> <span class="k">=</span> <span class="nc">EitherT</span><span class="o">[</span><span class="kt">Writer</span><span class="o">[</span><span class="kt">Log</span>, <span class="kt">?</span><span class="o">]</span>, <span class="kt">Error</span>, <span class="kt">A</span><span class="o">](</span><span class="nc">Writer</span><span class="o">(</span><span class="nc">Monoid</span><span class="o">[</span><span class="kt">Log</span><span class="o">].</span><span class="py">empty</span><span class="o">,</span> <span class="nv">a</span><span class="o">.</span><span class="py">asRight</span><span class="o">[</span><span class="kt">Error</span><span class="o">]))</span>

  <span class="k">def</span> <span class="nf">raiseT</span><span class="o">[</span><span class="kt">Log</span>, <span class="kt">Result</span><span class="o">](</span><span class="k">implicit</span> <span class="n">evidence</span><span class="k">:</span> <span class="kt">Monoid</span><span class="o">[</span><span class="kt">Log</span><span class="o">])</span><span class="k">:</span> <span class="kt">EitherT</span><span class="o">[</span><span class="kt">Writer</span><span class="o">[</span><span class="kt">Log</span>, <span class="kt">?</span><span class="o">]</span>, <span class="kt">A</span>, <span class="kt">Result</span><span class="o">]</span> <span class="k">=</span> <span class="nc">EitherT</span><span class="o">[</span><span class="kt">Writer</span><span class="o">[</span><span class="kt">Log</span>, <span class="kt">?</span><span class="o">]</span>, <span class="kt">A</span>, <span class="kt">Result</span><span class="o">](</span><span class="nc">Writer</span><span class="o">(</span><span class="nc">Monoid</span><span class="o">[</span><span class="kt">Log</span><span class="o">].</span><span class="py">empty</span><span class="o">,</span> <span class="nv">a</span><span class="o">.</span><span class="py">asLeft</span><span class="o">[</span><span class="kt">Result</span><span class="o">]))</span>
<span class="o">}</span>
</code></pre></div></div>

<h1 id="modelling-effects-with-zio">Modelling Effects with ZIO</h1>
<p>So a couple of weeks back I was happy coding away using Monad Stacks! Then ZIO happened! ZIO uses <em>horizontal effects</em> - Effect Rotation - instead of <em>vertical effects</em> which allow us to create functional code without the undesired runtime overheads. Additionally the ZIO version is concurrent-safe which means that we can freely mix concurrent / parallel operations.  Thank you <a href="https://twitter.com/jdegoes">@jdegoes</a> for explaining this technique. Let’s update the code</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">object</span> <span class="nc">ZIOApp</span> <span class="o">{</span>
  <span class="k">private</span><span class="o">[</span><span class="kt">this</span><span class="o">]</span> <span class="k">def</span> <span class="nf">getProductsForUser</span><span class="o">(</span><span class="n">userId</span><span class="k">:</span> <span class="kt">Long</span><span class="o">)</span><span class="k">:</span> <span class="kt">MyZIO</span><span class="o">[</span><span class="kt">Log</span>, <span class="kt">Error</span>, <span class="kt">List</span><span class="o">[</span><span class="kt">Product</span><span class="o">]]</span> <span class="k">=</span>
    <span class="n">userId</span> <span class="k">match</span> <span class="o">{</span>
      <span class="k">case</span> <span class="mi">1</span> <span class="k">=&gt;</span> <span class="nv">ZIO</span><span class="o">.</span><span class="py">succeed</span><span class="o">(</span><span class="nc">List</span><span class="o">(</span><span class="nc">Product</span><span class="o">(</span><span class="mi">1L</span><span class="o">,</span> <span class="s">"Bird Seeds"</span><span class="o">),</span> <span class="nc">Product</span><span class="o">(</span><span class="mi">2L</span><span class="o">,</span> <span class="s">"Artificial Rock"</span><span class="o">)))</span>
      <span class="k">case</span> <span class="k">_</span> <span class="k">=&gt;</span> <span class="nv">ZIO</span><span class="o">.</span><span class="py">succeed</span><span class="o">(</span><span class="nv">List</span><span class="o">.</span><span class="py">empty</span><span class="o">[</span><span class="kt">Product</span><span class="o">])</span>
    <span class="o">}</span>

  <span class="k">private</span><span class="o">[</span><span class="kt">this</span><span class="o">]</span> <span class="k">def</span> <span class="nf">searchUserAccount</span><span class="o">(</span><span class="n">email</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span><span class="k">:</span> <span class="kt">MyZIO</span><span class="o">[</span><span class="kt">Log</span>, <span class="kt">Error</span>, <span class="kt">User</span><span class="o">]</span> <span class="k">=</span>
    <span class="n">email</span> <span class="k">match</span> <span class="o">{</span>
      <span class="k">case</span> <span class="s">"wile@acme.com"</span> <span class="k">=&gt;</span> <span class="nv">ZIO</span><span class="o">.</span><span class="py">succeed</span><span class="o">(</span><span class="nc">User</span><span class="o">(</span><span class="mi">1L</span><span class="o">,</span> <span class="s">"wile@acme.com"</span><span class="o">,</span> <span class="s">"Will"</span><span class="o">))</span>
      <span class="k">case</span> <span class="k">_</span> <span class="k">=&gt;</span> <span class="nf">log</span><span class="o">(</span><span class="n">s</span><span class="s">"User $email is not in the database"</span><span class="o">)</span> <span class="o">*&gt;</span> <span class="nv">ZIO</span><span class="o">.</span><span class="py">fail</span><span class="o">(</span><span class="s">"User not in our database."</span><span class="o">)</span>
    <span class="o">}</span>

  <span class="k">def</span> <span class="nf">getAllUserData</span><span class="o">(</span><span class="n">email</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span><span class="k">:</span> <span class="kt">MyZIO</span><span class="o">[</span><span class="kt">Log</span>, <span class="kt">Error</span>, <span class="kt">PurchaseHistory</span><span class="o">]</span> <span class="k">=</span>
    <span class="k">for</span> <span class="o">{</span>
      <span class="k">_</span>         <span class="k">&lt;-</span> <span class="nf">log</span><span class="o">(</span><span class="n">s</span><span class="s">"Searching For User Account $email"</span><span class="o">)</span>
      <span class="n">user</span>      <span class="k">&lt;-</span> <span class="nf">searchUserAccount</span><span class="o">(</span><span class="n">email</span><span class="o">)</span>
      <span class="k">_</span>         <span class="k">&lt;-</span> <span class="nf">log</span><span class="o">(</span><span class="n">s</span><span class="s">"Searching For Products For Account $email"</span><span class="o">)</span>
      <span class="n">products</span>  <span class="k">&lt;-</span> <span class="nf">getProductsForUser</span><span class="o">(</span><span class="nv">user</span><span class="o">.</span><span class="py">id</span><span class="o">)</span>
    <span class="o">}</span> <span class="k">yield</span> <span class="nc">PurchaseHistory</span><span class="o">(</span><span class="nv">user</span><span class="o">.</span><span class="py">email</span><span class="o">,</span> <span class="nv">user</span><span class="o">.</span><span class="py">name</span><span class="o">,</span> <span class="n">products</span><span class="o">)</span>

<span class="o">}</span>
</code></pre></div></div>

<p>where <code class="language-plaintext highlighter-rouge">MyZIO</code> and the other helper methods are defined as</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">trait</span> <span class="nc">Writer</span><span class="o">[</span><span class="kt">W</span><span class="o">]</span> <span class="o">{</span>
  <span class="k">def</span> <span class="nf">writer</span><span class="k">:</span> <span class="kt">Ref</span><span class="o">[</span><span class="kt">Vector</span><span class="o">[</span><span class="kt">W</span><span class="o">]]</span>
<span class="o">}</span>

<span class="c1">// Writer helpers:</span>
<span class="k">def</span> <span class="nf">log</span><span class="o">[</span><span class="kt">W</span><span class="o">](</span><span class="n">w</span><span class="k">:</span> <span class="kt">W</span><span class="o">)</span><span class="k">:</span> <span class="kt">ZIO</span><span class="o">[</span><span class="kt">Writer</span><span class="o">[</span><span class="kt">W</span><span class="o">]</span>, <span class="kt">Nothing</span>, <span class="kt">Unit</span><span class="o">]</span> <span class="k">=</span> <span class="nv">ZIO</span><span class="o">.</span><span class="py">accessM</span><span class="o">[</span><span class="kt">Writer</span><span class="o">[</span><span class="kt">W</span><span class="o">]](</span><span class="nv">_</span><span class="o">.</span><span class="py">writer</span><span class="o">.</span><span class="py">update</span><span class="o">(</span><span class="n">vector</span> <span class="k">=&gt;</span> <span class="n">vector</span> <span class="o">:+</span> <span class="n">w</span><span class="o">)).</span><span class="py">unit</span>
<span class="k">def</span> <span class="nf">getLogs</span><span class="o">[</span><span class="kt">W</span><span class="o">]</span><span class="k">:</span> <span class="kt">ZIO</span><span class="o">[</span><span class="kt">Writer</span><span class="o">[</span><span class="kt">W</span><span class="o">]</span>, <span class="kt">Nothing</span>, <span class="kt">Vector</span><span class="o">[</span><span class="kt">W</span><span class="o">]]</span> <span class="k">=</span> <span class="nv">ZIO</span><span class="o">.</span><span class="py">accessM</span><span class="o">[</span><span class="kt">Writer</span><span class="o">[</span><span class="kt">W</span><span class="o">]](</span><span class="nv">_</span><span class="o">.</span><span class="py">writer</span><span class="o">.</span><span class="py">get</span><span class="o">)</span>
<span class="k">def</span> <span class="nf">clearLogs</span><span class="o">[</span><span class="kt">W</span><span class="o">]</span><span class="k">:</span> <span class="kt">ZIO</span><span class="o">[</span><span class="kt">Writer</span><span class="o">[</span><span class="kt">W</span><span class="o">]</span>, <span class="kt">Nothing</span>, <span class="kt">Unit</span><span class="o">]</span> <span class="k">=</span> <span class="nv">ZIO</span><span class="o">.</span><span class="py">accessM</span><span class="o">[</span><span class="kt">Writer</span><span class="o">[</span><span class="kt">W</span><span class="o">]](</span><span class="nv">_</span><span class="o">.</span><span class="py">writer</span><span class="o">.</span><span class="py">set</span><span class="o">(</span><span class="nc">Vector</span><span class="o">()))</span>

<span class="c1">// Types and Helpers</span>
<span class="k">type</span> <span class="kt">MyZIO</span><span class="o">[</span><span class="kt">W</span>, <span class="kt">E</span>, <span class="kt">A</span><span class="o">]</span> <span class="k">=</span> <span class="nc">ZIO</span><span class="o">[</span><span class="kt">Writer</span><span class="o">[</span><span class="kt">W</span><span class="o">]</span>, <span class="kt">E</span>, <span class="kt">A</span><span class="o">]</span>
</code></pre></div></div>

<p>ZIO helps us create descriptions of what our program should do (rather than do it!).  Describing what a program should instead of doing it is powerful, extremely powerful.  To illustrate why, let’s update our program to handle a flaky connection with the database when searching for the user account - <code class="language-plaintext highlighter-rouge">searchUserAccount</code>.</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">getAllUserData</span><span class="o">(</span><span class="n">email</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span><span class="k">:</span> <span class="kt">MyZIO</span><span class="o">[</span><span class="kt">Log</span>, <span class="kt">Error</span>, <span class="kt">PurchaseHistory</span><span class="o">]</span> <span class="k">=</span>
    <span class="k">for</span> <span class="o">{</span>
      <span class="k">_</span>         <span class="k">&lt;-</span> <span class="nf">log</span><span class="o">(</span><span class="n">s</span><span class="s">"Searching For User Account $email"</span><span class="o">)</span>
      <span class="n">user</span>      <span class="k">&lt;-</span> <span class="nf">searchUserAccount</span><span class="o">(</span><span class="n">email</span><span class="o">).</span><span class="py">retry</span><span class="o">(</span><span class="nv">Schedule</span><span class="o">.</span><span class="py">recurs</span><span class="o">(</span><span class="mi">10</span><span class="o">))</span>
      <span class="k">_</span>         <span class="k">&lt;-</span> <span class="nf">log</span><span class="o">(</span><span class="n">s</span><span class="s">"Searching For Products For Account $email"</span><span class="o">)</span>
      <span class="n">products</span>  <span class="k">&lt;-</span> <span class="nf">getProductsForUser</span><span class="o">(</span><span class="nv">user</span><span class="o">.</span><span class="py">id</span><span class="o">)</span>
    <span class="o">}</span> <span class="k">yield</span> <span class="nc">PurchaseHistory</span><span class="o">(</span><span class="nv">user</span><span class="o">.</span><span class="py">email</span><span class="o">,</span> <span class="nv">user</span><span class="o">.</span><span class="py">name</span><span class="o">,</span> <span class="n">products</span><span class="o">)</span>
</code></pre></div></div>

<p>That’s it! Our program will now retry the <code class="language-plaintext highlighter-rouge">searchUserAccount</code> 10 times before failing.  There are more powerful combinators in the ZIO library which allow us to compose and modify program descriptions.</p>

<p>So, how do we run these descriptions? ZIO comes packaged with a <code class="language-plaintext highlighter-rouge">DefaultRuntime</code> which takes a pure program description and executes its effects onto the world via the <code class="language-plaintext highlighter-rouge">unsafeRun</code> method.</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">main</span><span class="o">(</span><span class="n">args</span><span class="k">:</span> <span class="kt">Array</span><span class="o">[</span><span class="kt">String</span><span class="o">])</span><span class="k">:</span> <span class="kt">Unit</span> <span class="o">=</span> <span class="o">{</span>
  <span class="k">val</span> <span class="nv">runtime</span> <span class="k">=</span> <span class="k">new</span> <span class="nc">DefaultRuntime</span><span class="o">{}</span>

  <span class="k">val</span> <span class="nv">program</span> <span class="k">=</span> <span class="k">for</span> <span class="o">{</span>
    <span class="k">_</span>                   <span class="k">&lt;-</span> <span class="nf">getAllUserData</span><span class="o">(</span><span class="s">"wile@acme.com"</span><span class="o">)</span>
    <span class="n">logForValidSearch</span>   <span class="k">&lt;-</span> <span class="n">getLogs</span><span class="o">[</span><span class="kt">String</span><span class="o">]</span>
    <span class="k">_</span>                   <span class="k">&lt;-</span> <span class="nv">console</span><span class="o">.</span><span class="py">putStrLn</span><span class="o">(</span><span class="nv">logForValidSearch</span><span class="o">.</span><span class="py">mkString</span><span class="o">(</span><span class="s">"\n"</span><span class="o">))</span>
  <span class="o">}</span> <span class="nf">yield</span> <span class="o">()</span>

  <span class="nv">runtime</span><span class="o">.</span><span class="py">unsafeRun</span><span class="o">(</span><span class="k">for</span> <span class="o">{</span>
    <span class="n">wref</span>    <span class="k">&lt;-</span> <span class="nv">Ref</span><span class="o">.</span><span class="py">make</span><span class="o">[</span><span class="kt">Vector</span><span class="o">[</span><span class="kt">String</span><span class="o">]](</span><span class="nc">Vector</span><span class="o">())</span>
    <span class="n">result</span>  <span class="k">&lt;-</span> <span class="nv">program</span><span class="o">.</span><span class="py">provide</span><span class="o">(</span><span class="k">new</span> <span class="nv">console</span><span class="o">.</span><span class="py">Console</span><span class="o">.</span><span class="py">Live</span> <span class="k">with</span> <span class="nc">Writer</span><span class="o">[</span><span class="kt">String</span><span class="o">]</span> <span class="o">{</span> <span class="k">def</span> <span class="nf">writer</span> <span class="k">=</span> <span class="n">wref</span>  <span class="o">})</span>
  <span class="o">}</span> <span class="k">yield</span> <span class="n">result</span><span class="o">)</span>
<span class="o">}</span>
</code></pre></div></div>

<h1 id="conclusion">Conclusion</h1>
<p>In this post we have looked at how we can convert an imperative program into a pure functional “equivalent” using two techniques; Monad Transformers and Effect Rotation (via ZIO).  ZIO is more than just an Effect Rotation implementation.  ZIO is a library for asynchronous and concurrent programming powered by highly-scalable, non-blocking fibers that never waste or leak resources.  ZIO will be one of the most influential libraries in the functional ecosystem. The community is also super helpful and welcoming.  Get started today - head over the <a href="https://scalaz.github.io/scalaz-zio/">project microsite</a> and the <a href="https://gitter.im/ZIO/Core">gitter channel</a>.  As always…stay safe and keep hacking!</p>]]></content><author><name>Mark Galea</name></author><summary type="html"><![CDATA[I have been doing functional programming for quite some time in the small - map, filter, flatMap, for comprehensions, catz etc. While I was sold on the great benefits of FP I’ve struggled to transition to doing FP in the large without hitting runtime overheads. This is where ZIO comes in the picture. ZIO makes programming in the large simple and provides the ability to interop with other parts of the broader functional ecosystem. In this blog post I will describe a fictitious business problem, implement it in an imperative way and rewrite the application in a functional “equivalent” using ZIO.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://cloudmark.github.io/images/zio/zio.png" /><media:content medium="image" url="http://cloudmark.github.io/images/zio/zio.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Why Kubernetes? Google Cloud Event Follow-up</title><link href="http://cloudmark.github.io/Google-Cloud-Event/" rel="alternate" type="text/html" title="Why Kubernetes? Google Cloud Event Follow-up" /><published>2019-04-19T00:00:00+00:00</published><updated>2019-04-19T00:00:00+00:00</updated><id>http://cloudmark.github.io/Google-Cloud-Event</id><content type="html" xml:base="http://cloudmark.github.io/Google-Cloud-Event/"><![CDATA[<p><img class="title" src="/images/googlecloudevent/event.jpg" />
This April Google organised the first Google Cloud Event here in Malta.  During that event I presented our reasons, as a company, for moving to Kubernetes. Many have reached out after the presentation to discuss further and some suggested publishing our motivations online for reference.  So here I am typing away :grimacing:!</p>

<h1 id="cathedrals-vs-baazars">Cathedrals vs Baazars</h1>
<p>Back in 2006 the world was definitely a simpler place.  Large deployments consisted of a couple of servers, API response times were measured in seconds and customers were tolerant to hours of downtime.  Today, large deployments consist of hundreds (even thousands) of servers, customers demand sub-second response times and downtimes are not tolerated at all.</p>

<p>Since 2006 systems have grown significantly larger making scale-up infeasible.  New requirements require new architectures; big monoliths need to be broken down into smaller independent components called <strong>microservices</strong> in order to be developed, maintained and scaled independently (scaled-out).</p>

<h1 id="reactive-applications">Reactive applications</h1>
<p>If the previous section resonated with the <a href="https://www.reactivemanifesto.org/">reactive manifesto</a>, you are right, it sure does.  Around 2014, I started following content from Jonas Bonér (@jboner), Roland Kuhn (@rolandkuhn) and Martin Odersky (@odersky) and the seeds of reactive systems were planted.</p>

<p>But what are reactive applications?  Merriam Webster dictionary defines reactive as readily responding to stimulus.  In the case of reactive applications this specifically means four things:</p>

<ol>
  <li><strong>React to events</strong>: reactive systems consist of a number of loosely coupled systems that need to communicate together asynchronously via messages.</li>
  <li><strong>React to load</strong>: reactive systems need to handle non-uniform loads with huge variances.</li>
  <li><strong>Reactive to failure</strong>: the ‘let it crash’ philosophy is ‘built-in’ into reactive system rather than patched on top. Failure is not an exceptional event but assumed.</li>
  <li><strong>React to users</strong>: as a result of systems which communicate asynchronously, react to load and react to failure we can create systems which respond to users in a timely manner.</li>
</ol>

<h1 id="microservices-microservices-everywhere">Microservices, microservices everywhere</h1>
<p>So, the vision was clear. We wanted to create microservices which</p>
<ul>
  <li>cooperate together asynchronously via messages,</li>
  <li>scale independently to buffer load and optimise costs, and</li>
  <li>react to failure without manual intervention.</li>
</ul>

<p><em>We also wanted to develop microservices in a functional paradigm but that’s a story for some another time :smile:</em>.</p>

<p>From a developer’s POV, moving to reactive systems (and microservices) 
is easy.  Microservices are easy to understand hence easier to develop, understand and maintain.</p>

<p>From a DevOps perspective microservices are hard. Hard to:</p>
<ul>
  <li><strong>Isolate</strong>:  how do we make sure that microservices do not step on each other’s toes?</li>
  <li><strong>Schedule</strong>:  how do we schedule micorservices across a number of nodes?</li>
  <li><strong>Configure</strong>: how do we configure services so that they can communicate with each other? How do we expose services to the outside world?</li>
  <li><strong>Supervise</strong>:  how do we supervise microservices to know that they are alive?</li>
  <li><strong>Recover (from failure)</strong>: how do we handle failure?</li>
</ul>

<p>Ok great, vision - check! Mental map - check! First stop down microservices lane was isolation!</p>

<h1 id="isolating-running-apps">Isolating Running Apps</h1>
<p>Google was the first company to face this problem at scale and created two technologies (cgroups and namespaces) which would unlock container orchestration engines.  Looking back, there were (and still are) three main techniques available:</p>

<ol>
  <li>
    <p><strong>Naive Approach</strong> (<em>faith is a requirement</em>): Applications are deployed on a couple of machines and are assumed to be homogeneous; same libraries, same environment. Assuming that <strong>all</strong> microservices developed have the same requirements is naive and limiting.</p>
  </li>
  <li>
    <p><strong>VM Approach</strong> (<em>thou shall be wasteful</em>):  To solve the divergence problem, most people turn to VMs.  The main drawback with VMs is that as components get smaller (and the number of components increase) hardware resources are not fully utilised.  VMs also create a huge workload for system administrators.</p>
  </li>
  <li>
    <p><strong>Containers Approach</strong> (<em>thou shall be resourceful):  The ultimate solution and the solution we ended up using is _linux containers</em>.  Using containers we run processes on a host operating system and isolate these processes through the use of <em>namespaces</em>.  Resources utilised by an applications are restricted through the use of <em>cgroups</em>.</p>
  </li>
</ol>

<h1 id="kubernetes">Kubernetes</h1>
<p>Having found a solution to the problem of isolation, we focused on scheduling, configuring, supervision and failure recovery. It turned out that <a href="https://kubernetes.io/">Kubernetes</a> solved all of these problems. Hard to believe right? Let’s see how Kubernetes helps us solve Scheduling, Configuring, Supervision and Failure recovery.</p>

<h2 id="scheduling">Scheduling</h2>
<h3 id="creating-containers">Creating Containers</h3>
<p>When we discuss scheduling we typically think of deploying a container (or pod in Kubernetes lingo) on some server.  Assuming that we have the image <code class="language-plaintext highlighter-rouge">repository/platform:v1</code> how do we deploy 5 instances of this application across our available nodes? One way of doing this in Kubernetes is via a <em>deployment resources</em>.  First we create a file <code class="language-plaintext highlighter-rouge">deployment.yaml</code> (although the name is not important)</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># File: deployment.yaml</span>
<span class="na">apiVersion</span><span class="pi">:</span> <span class="s">apps/v1beta1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Deployment</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">platform</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">replicas</span><span class="pi">:</span> <span class="s">5</span> 
  <span class="na">template</span><span class="pi">:</span>
    <span class="na">metadata</span><span class="pi">:</span>
      <span class="na">name</span><span class="pi">:</span> <span class="s">platform</span>
      <span class="na">labels</span><span class="pi">:</span>
        <span class="na">app</span><span class="pi">:</span> <span class="s">platform</span>
    <span class="na">spec</span><span class="pi">:</span>
      <span class="na">containers</span><span class="pi">:</span>
    <span class="err"> </span><span class="pi">:</span> <span class="na">image</span><span class="pi">:</span> <span class="s">repository/platform:v1</span>
        <span class="s">name</span><span class="err">:</span> <span class="s">platform</span>
</code></pre></div></div>

<p>and submit the deployment resources to the Kubernetes master via the control plane</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> kubectl create <span class="nt">-f</span> deployment.yaml
</code></pre></div></div>

<p>The Kubernetes master will orchestrate all the Kubernetes worker nodes to achieve the desired state (5 platform pods).</p>

<h3 id="scaling">Scaling</h3>
<p>Ok great! Our application is really performing well and now we want to scale-up to handle heavier loads.  With Kubernetes this is easy - we update the <code class="language-plaintext highlighter-rouge">spec.replicas</code> field from <code class="language-plaintext highlighter-rouge">5</code> to say <code class="language-plaintext highlighter-rouge">10</code>,</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># File: deployment.yaml</span>
<span class="na">apiVersion</span><span class="pi">:</span> <span class="s">apps/v1beta1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Deployment</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">platform</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">replicas</span><span class="pi">:</span> <span class="m">10</span> <span class="c1"># Change number of replicas</span>
  <span class="na">template</span><span class="pi">:</span>
    <span class="na">metadata</span><span class="pi">:</span>
      <span class="na">name</span><span class="pi">:</span> <span class="s">platform</span>
      <span class="na">labels</span><span class="pi">:</span>
        <span class="na">app</span><span class="pi">:</span> <span class="s">platform</span>
    <span class="na">spec</span><span class="pi">:</span>
      <span class="na">containers</span><span class="pi">:</span>
    <span class="err"> </span><span class="pi">:</span> <span class="na">image</span><span class="pi">:</span> <span class="s">repository/platform:v1</span> <span class="c1"># Still circle thingies!</span>
        <span class="na">name</span><span class="pi">:</span> <span class="s">platform</span>
</code></pre></div></div>

<p>submit this to the Kubernetes master</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> kubectl apply <span class="nt">-f</span> deployment.yaml 
</code></pre></div></div>

<p>and voila! We scaled our application.  Alternatively we could have achieved the above by simply running the command</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> kubectl scale deployment platform <span class="nt">--replicas</span><span class="o">=</span>10
</code></pre></div></div>

<p>A hand-wavy explanation of what just happened;  Kubernetes identified a mismatch between the desired state (10 application instances) and the actual state (5 application instances) and resolved the mismatch by orchestrating more pods across the available nodes.  If you are interested in Kubernetes internals I would highly recommend the book <em>Kubernetes in Action</em> by Marko Lukša (@markoluksa).  Another great resource to learn Kubernetes is the <a href="http://www.github.com/kubernetes">github repository</a>; kubernetes is an open source project and reading the codebase can be quite educational.</p>

<h3 id="rolling-updates">Rolling Updates</h3>
<p>One thing in which Kubernetes really shines is rolling updates.  So imagine the following scenario; we have deployed version 1 of our application, things are going great and we are ready to roll out version 2.  How do we do this without incurring any downtime? In Kubernetes, we simply update the field <code class="language-plaintext highlighter-rouge">spec.template.spec.containers.image</code> field from <code class="language-plaintext highlighter-rouge">repository/platform:v1</code> to <code class="language-plaintext highlighter-rouge">repository/platform:v2</code></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># File: deployment.yaml</span>
<span class="na">apiVersion</span><span class="pi">:</span> <span class="s">apps/v1beta1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Deployment</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">platform</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">replicas</span><span class="pi">:</span> <span class="m">3</span>
  <span class="na">template</span><span class="pi">:</span>
    <span class="na">metadata</span><span class="pi">:</span>
      <span class="na">name</span><span class="pi">:</span> <span class="s">platform</span>
      <span class="na">labels</span><span class="pi">:</span>
        <span class="na">app</span><span class="pi">:</span> <span class="s">platform</span>
    <span class="na">spec</span><span class="pi">:</span>
      <span class="na">containers</span><span class="pi">:</span>
    <span class="err"> </span><span class="pi">:</span> <span class="na">image</span><span class="pi">:</span> <span class="s">repository/platform:v2</span> <span class="c1"># Change image</span>
        <span class="na">name</span><span class="pi">:</span> <span class="s">platform</span>
</code></pre></div></div>

<p>inform the Kubernetes master of our desired state</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> kubectl apply <span class="nt">-f</span> deployment.yaml
</code></pre></div></div>

<p>and Kubernetes will automatically start scaling up new deployments and scaling down the old deployments until all pods are on the latest version.  <em>There is also a big bang approach but typically you would want to phase out the deployment to avoid downtime</em>.</p>

<h2 id="configuring">Configuring</h2>
<p>Having discussed scheduling, we shall now focus on how we can configure our pods to communicate with each other and how we can communicate with pods from the outside word.</p>

<h3 id="accessing-pods-within-the-cluster">Accessing Pods within the cluster</h3>
<p>One requirement of reactive systems is that they are able to communicate with each other asynchronously.  Given that pods are ephermal: remember <em>let it crash</em>, how do we contact our pods from other pods if they are moving targets? In order to understand how we do this let us first create a CMS Deploymnent resource and spin up three nodes!</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># File: cms.yaml</span>
<span class="na">apiVersion</span><span class="pi">:</span> <span class="s">apps/v1beta1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Deployment</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">cms</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">replicas</span><span class="pi">:</span> <span class="m">3</span>
  <span class="na">template</span><span class="pi">:</span>
    <span class="na">metadata</span><span class="pi">:</span>
      <span class="na">name</span><span class="pi">:</span> <span class="s">cms</span>
      <span class="na">labels</span><span class="pi">:</span>
        <span class="na">app</span><span class="pi">:</span> <span class="s">cms</span>
    <span class="na">spec</span><span class="pi">:</span>
      <span class="na">containers</span><span class="pi">:</span>
    <span class="err"> </span><span class="pi">:</span> <span class="na">image</span><span class="pi">:</span> <span class="s">repository/cms:v1</span>
        <span class="s">name</span><span class="err">:</span> <span class="s">cms</span>
</code></pre></div></div>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> kubectl create <span class="nt">-f</span> cms.yaml
</code></pre></div></div>

<p>How do we allow our previously created <code class="language-plaintext highlighter-rouge">platform</code> pods to communicate with our newly created <code class="language-plaintext highlighter-rouge">cms</code> pods? In a non-Kubernetes world, a sysadmin would need to configure each cms and platform container manually but when using Kubernetes we utilize a <em>service resource</em></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># File: service.yaml</span>
<span class="na">apiVersion</span><span class="pi">:</span> <span class="s">v1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Service</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">cms-service</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">ports</span><span class="pi">:</span>
    <span class="na">name</span><span class="pi">:</span> <span class="s">http</span>
    <span class="na">port</span><span class="pi">:</span> <span class="m">80</span>
    <span class="na">targetPort</span><span class="pi">:</span> <span class="m">8080</span>
  <span class="na">selector</span><span class="pi">:</span>
    <span class="na">app</span><span class="pi">:</span> <span class="s">cms</span>
</code></pre></div></div>

<p>and ask Kubernetes to expose our service.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> kubectl create <span class="nt">-f</span> service.yaml
</code></pre></div></div>

<p>Our <code class="language-plaintext highlighter-rouge">platform</code> pods can communicate with the <code class="language-plaintext highlighter-rouge">cms</code> pods via the <code class="language-plaintext highlighter-rouge">http://cms/</code> endpoint. You can think of the <em>service resources</em> as a load-balancer that distributes load between the available pods identified by the <code class="language-plaintext highlighter-rouge">spec.selector.app</code> field.</p>

<h3 id="accessing-pods-from-outside-the-cluster">Accessing Pods from outside the cluster</h3>
<p>Platforms which can only be accessed from within the cluster are boring. Let’s expose our platform externally. In order to do this we will use the same <em>service resource</em> and specify <code class="language-plaintext highlighter-rouge">LoadBalancer</code> in the <code class="language-plaintext highlighter-rouge">spec.type</code> field</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># File: external_service.yaml</span>
<span class="na">apiVersion</span><span class="pi">:</span> <span class="s">v1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Service</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">platform-loadbalancer</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">type</span><span class="pi">:</span> <span class="s">LoadBalancer</span> <span class="c1"># Expose it to the outside</span>
  <span class="na">ports</span><span class="pi">:</span>
<span class="err"> </span><span class="pi">:</span> <span class="na">port</span><span class="pi">:</span> <span class="m">80</span>
    <span class="na">targetPort</span><span class="pi">:</span> <span class="m">8080</span>
 <span class="err"> </span><span class="na">selector</span><span class="pi">:</span>
    <span class="na">app</span><span class="pi">:</span> <span class="s">platform</span>
</code></pre></div></div>

<p>and submit this <em>service resources</em> to the Kubernetes master</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> kubectl create <span class="nt">-f</span> external_service.yaml
</code></pre></div></div>

<p>This small change in the spec metadata instructs the underlying cloud provider (in our case Google Cloud) to create an external load-balancer, assign a static IP, create the required firewall rules and re-direct traffic hitting the external IP internally to pods inside the Kubernetes cluster.</p>

<p>To get the external IP address we use</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> kubectl get svc platform-loadbalancer
</code></pre></div></div>

<p><em>Wow, a lot has happened with this simple addition! This is in fact one of the main advantages of using Kubernetes on a Cloud Provider.</em></p>

<h2 id="supervision-and-failure">Supervision and Failure</h2>
<p>We are making progress but how do we deal with Supervision and Failure recovery? Well we don’t, Kubernetes does.  Kubernetes runs a closed loop which constantly compares our desired state with the actual state and if a mismatch is detected Kubernetes resolves the mismatch.   For example, if we specify that we want 5 platform instances running, Kubernetes will make sure that 5 instances are running.  If one instance stops working (or responding) Kubernetes will automatically restart the pod and reschedule it.  If a whole node dies, all pods deployed on that node will be rescheduled on a newly selected healthy node.</p>

<h1 id="back-our-vision">Back our vision!</h1>
<p>Let’s review what we achieved. Using containerisation at the base, we used Kubernetes to orchestrate applications without requiring manual intervention.</p>

<p>These applications are able to communicate with each other via <em>services</em>.  These applications are able to <strong>react to load</strong> since it is easy to scale and do rolling-updates with Kubernetes.  Finally, Kubernetes enables us to <strong>react to failure</strong> by monitoring all resources in a tight loop.</p>

<h1 id="conclusion">Conclusion</h1>
<p>Kubernetes is key in enabling our vision of creating reactive systems. When we started using Kubernetes we could not have imagined the impact it would have on our daily development process.  Three years on, we deploy multiple times a day with confidence without worrying about downtimes. If you are starting the journey to Kubernetes you are making a great choice! Stay safe and keep hacking!</p>]]></content><author><name>Mark Galea</name></author><summary type="html"><![CDATA[This April Google organised the first Google Cloud Event here in Malta. During that event I presented our reasons, as a company, for moving to Kubernetes. Many have reached out after the presentation to discuss further and some suggested publishing our motivations online for reference. So here I am typing away :grimacing:!]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://cloudmark.github.io/images/googlecloudevent/google-cloud-logo.jpg" /><media:content medium="image" url="http://cloudmark.github.io/images/googlecloudevent/google-cloud-logo.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Computation Context - Walk the Line</title><link href="http://cloudmark.github.io/Computational-Context/" rel="alternate" type="text/html" title="Computation Context - Walk the Line" /><published>2019-02-03T00:00:00+00:00</published><updated>2019-02-03T00:00:00+00:00</updated><id>http://cloudmark.github.io/Computational-Context</id><content type="html" xml:base="http://cloudmark.github.io/Computational-Context/"><![CDATA[<p><img class="title" src="/images/context/tight.jpg" />
One question which often crops up when mentioning Functional Programming (FP) is “But what’s the point of using FP? Why would I change from an Imperative Programming (IP) paradigm to FP if both solve the same class of problems?”.  To the uninitiated FP represents a surface level refactor to use “newer methods” such as <code class="language-plaintext highlighter-rouge">map</code>, <code class="language-plaintext highlighter-rouge">flatMap</code> and <code class="language-plaintext highlighter-rouge">filter</code> with a sprinkle of classes such as <code class="language-plaintext highlighter-rouge">Option(al)</code> and <code class="language-plaintext highlighter-rouge">Either</code> but obviously this is not the case.</p>

<p>Hopefully by this post I will motivate the move from IP to FP by going through the concept of computational context.  To illustrate this concept I will use the <strong>Walk the Line</strong> example presented in <a href="http://learnyouahaskell.com/a-fistful-of-monads#walk-the-line">Learn You A Haskell For Greater Good!</a>.</p>

<p>Let’s start by describing the problem.</p>

<h1 id="walk-the-line">Walk the line</h1>

<p><em>This example is adapted from <a href="http://learnyouahaskell.com/a-fistful-of-monads#walk-the-line">Learn You A Haskell For Greater Good!</a>.  All credit goes to Miran Lipovača (@bonus500).  Thank you for creating such a great and fun book and thank you for introducing me to Haskell.</em></p>

<p><img class="step minimal" style="width: 280px" src="/images/context/pierre.png" /></p>

<blockquote>
  <p>Pierre has decided to take a break from his job at the fish farm and try tightrope walking. He’s not that bad at it, but he does have one problem: birds keep landing on his balancing pole! They come and they take a short rest, chat with their avian friends and then take off in search of breadcrumbs. This wouldn’t bother him so much if the number of birds on the left side of the pole was always equal to the number of birds on the right side. But sometimes, all the birds decide that they like one side better and so they throw him off balance, which results in an embarrassing tumble for Pierre (he’s using a safety net).
Let’s say that he keeps his balance if the number of birds on the left side of the pole and on the right side of the pole is within three. So if there’s one bird on the right side and four birds on the left side, he’s okay. But if a fifth bird lands on the left side, then he loses his balance and takes a dive.
We’re going to simulate birds landing on and flying away from the pole and see if Pierre is still at it after a certain number of birdy arrivals and departures. For instance, we want to see what happens to Pierre if first one bird arrives on the left side, then four birds occupy the right side and then the bird that was on the left side decides to fly away.</p>
</blockquote>

<h1 id="imperative-attempt---throw-exceptions-on-failure">Imperative Attempt - Throw exceptions on failure</h1>
<p>One way of dealing with failure in the imperative toolbox is through exceptions.  The Pierre scenario would be implemented as follows:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">case</span> <span class="k">class</span> <span class="nc">Pole</span><span class="o">(</span><span class="n">left</span><span class="k">:</span> <span class="kt">Int</span><span class="o">,</span> <span class="n">right</span><span class="k">:</span> <span class="kt">Int</span><span class="o">)</span> <span class="o">{</span>
  <span class="k">def</span> <span class="nf">landLeft</span><span class="o">(</span><span class="n">n</span><span class="k">:</span> <span class="kt">Int</span><span class="o">)</span><span class="k">:</span> <span class="kt">Pole</span> <span class="o">=</span> <span class="o">{</span>
    <span class="nf">assert</span><span class="o">(</span><span class="nv">Math</span><span class="o">.</span><span class="py">abs</span><span class="o">((</span><span class="n">left</span> <span class="o">+</span> <span class="n">n</span><span class="o">)</span> <span class="o">-</span> <span class="n">right</span><span class="o">)</span> <span class="o">&lt;=</span> <span class="mi">3</span><span class="o">)</span>
    <span class="nc">Pole</span><span class="o">(</span><span class="n">left</span> <span class="o">+</span> <span class="n">n</span><span class="o">,</span> <span class="n">right</span><span class="o">)</span>
  <span class="o">}</span>

  <span class="k">def</span> <span class="nf">landRight</span><span class="o">(</span><span class="n">n</span><span class="k">:</span> <span class="kt">Int</span><span class="o">)</span><span class="k">:</span> <span class="kt">Pole</span> <span class="o">=</span> <span class="o">{</span>
    <span class="nf">assert</span><span class="o">(</span><span class="nv">Math</span><span class="o">.</span><span class="py">abs</span><span class="o">((</span><span class="n">right</span> <span class="o">+</span> <span class="n">n</span><span class="o">)</span> <span class="o">-</span> <span class="n">left</span><span class="o">)</span> <span class="o">&lt;=</span> <span class="mi">3</span><span class="o">)</span>
    <span class="nc">Pole</span><span class="o">(</span><span class="n">left</span><span class="o">,</span> <span class="n">right</span> <span class="o">+</span> <span class="n">n</span><span class="o">)</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Let’s first visit a happy Pierre moment; one bird lands on the left :bird:, and four birds land on the right :bird: :bird: :bird: :bird:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">val</span> <span class="nv">pierreIsOk</span> <span class="k">=</span> <span class="nc">Pole</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">).</span><span class="py">landLeft</span><span class="o">(</span><span class="mi">1</span><span class="o">).</span><span class="py">landRight</span><span class="o">(</span><span class="mi">4</span><span class="o">)</span>
<span class="nf">println</span><span class="o">(</span><span class="n">pierreIsOk</span><span class="o">)</span> <span class="c1">// Pole(1, 4)</span>
</code></pre></div></div>

<p>Can you feel the tension? Just one more bird to tumble Pierre’s hopes and dreams! (which is exactly what we will do!)</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">try</span> <span class="o">{</span>
    <span class="nv">pierreIsOk</span><span class="o">.</span><span class="py">landRight</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span> <span class="c1">// Pole(1, 4)</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">{</span>
    <span class="k">case</span> <span class="k">_:</span> <span class="kt">Throwable</span> <span class="o">=&gt;</span> <span class="nf">println</span><span class="o">(</span><span class="s">"Oops Pierre tumbled!"</span><span class="o">)</span>
<span class="o">}</span>
</code></pre></div></div>

<p>As imperative developers this feels normal; we do a couple of operations, sandwich things between <code class="language-plaintext highlighter-rouge">try</code>-<code class="language-plaintext highlighter-rouge">catch</code> blocks and continue processing (or throw more exceptions).  The problem here is that <code class="language-plaintext highlighter-rouge">landLeft</code> and <code class="language-plaintext highlighter-rouge">landRight</code> are dishonest about their return type in that they do not indicate potential failure.  To make matters worse, <code class="language-plaintext highlighter-rouge">landLeft</code> and <code class="language-plaintext highlighter-rouge">landRight</code> expose a fluent API which suggests that operations can be chained or sequenced again without being clear of potential failures.  Using such a “technique” one can only ensure that a function is honest by going through its code. This is definitely unfeasible in large code bases.</p>

<h1 id="imperative-attempt---return-null">Imperative Attempt - return null</h1>
<p>Another popular “technique” to deal with failure is by using <code class="language-plaintext highlighter-rouge">null</code>s to capture failure.</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">case</span> <span class="k">class</span> <span class="nc">Pole</span><span class="o">(</span><span class="n">left</span><span class="k">:</span> <span class="kt">Int</span><span class="o">,</span> <span class="n">right</span><span class="k">:</span> <span class="kt">Int</span><span class="o">)</span> <span class="o">{</span>
  <span class="k">def</span> <span class="nf">landLeft</span><span class="o">(</span><span class="n">n</span><span class="k">:</span> <span class="kt">Int</span><span class="o">)</span><span class="k">:</span> <span class="kt">Pole</span> <span class="o">=</span> <span class="o">{</span>
    <span class="nf">if</span> <span class="o">(</span><span class="nv">Math</span><span class="o">.</span><span class="py">abs</span><span class="o">((</span><span class="n">left</span> <span class="o">+</span> <span class="n">n</span><span class="o">)</span> <span class="o">-</span> <span class="n">right</span><span class="o">)</span> <span class="o">&lt;=</span> <span class="mi">3</span><span class="o">)</span> <span class="o">{</span>
      <span class="nc">Pole</span><span class="o">(</span><span class="n">left</span> <span class="o">+</span> <span class="n">n</span><span class="o">,</span> <span class="n">right</span><span class="o">)</span>
    <span class="o">}</span> <span class="k">else</span> <span class="kc">null</span>
  <span class="o">}</span>

  <span class="k">def</span> <span class="nf">landRight</span><span class="o">(</span><span class="n">n</span><span class="k">:</span> <span class="kt">Int</span><span class="o">)</span><span class="k">:</span> <span class="kt">Pole</span> <span class="o">=</span> <span class="o">{</span>
    <span class="nf">if</span> <span class="o">(</span><span class="nv">Math</span><span class="o">.</span><span class="py">abs</span><span class="o">((</span><span class="n">right</span> <span class="o">+</span> <span class="n">n</span><span class="o">)</span> <span class="o">-</span> <span class="n">left</span><span class="o">)</span> <span class="o">&lt;=</span> <span class="mi">3</span><span class="o">)</span> <span class="o">{</span>
      <span class="nc">Pole</span><span class="o">(</span><span class="n">left</span><span class="o">,</span> <span class="n">right</span> <span class="o">+</span> <span class="n">n</span><span class="o">)</span>
   <span class="o">}</span> <span class="k">else</span> <span class="kc">null</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>This “technique” is even more dishonest than the exception counterpart since it leads to runtime NPE.</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">val</span> <span class="nv">pierreIsOk</span> <span class="k">=</span> <span class="nc">Pole</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">).</span><span class="py">landLeft</span><span class="o">(</span><span class="mi">1</span><span class="o">).</span><span class="py">landRight</span><span class="o">(</span><span class="mi">4</span><span class="o">)</span>
<span class="k">val</span> <span class="nv">pierreIsNull</span> <span class="k">=</span> <span class="nv">pierreIsOk</span><span class="o">.</span><span class="py">landRight</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span> <span class="c1">// null</span>
<span class="k">val</span> <span class="nv">boom</span> <span class="k">=</span> <span class="nv">pierreIsNull</span><span class="o">.</span><span class="py">landRight</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span> <span class="c1">// NPE  </span>
</code></pre></div></div>

<p>The problem here is again dishonesty in the return type.  The return type in this case is telling us that we should expect a <code class="language-plaintext highlighter-rouge">Pole</code> yet at times we get <code class="language-plaintext highlighter-rouge">null</code>.  Dealing with <code class="language-plaintext highlighter-rouge">null</code>s through <code class="language-plaintext highlighter-rouge">if</code>s makes our code difficult to read and does not allow us to sequence operations correctly.  <code class="language-plaintext highlighter-rouge">if</code>s break the cognitive flow and expose function internals which should not have leaked.</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">val</span> <span class="nv">pierreIsOk</span> <span class="k">=</span> <span class="nc">Pole</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">).</span><span class="py">landLeft</span><span class="o">(</span><span class="mi">1</span><span class="o">).</span><span class="py">landRight</span><span class="o">(</span><span class="mi">4</span><span class="o">)</span>
<span class="k">val</span> <span class="nv">pierreIsNull</span> <span class="k">=</span> <span class="nv">pierreIsOk</span><span class="o">.</span><span class="py">landRight</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span> <span class="c1">// null</span>
<span class="nf">if</span> <span class="o">(</span><span class="n">pierreIsNull</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="o">???</span> <span class="c1">// Do other things</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
 <span class="nv">pierreIsNull</span><span class="o">.</span><span class="py">landRight</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span> <span class="c1">// NPE</span>
<span class="o">}</span>
</code></pre></div></div>

<h1 id="imperative-attempt---ignorance-is-bliss">Imperative Attempt - Ignorance is bliss</h1>
<p>Ok, so we tried with exceptions, then we tried with <code class="language-plaintext highlighter-rouge">null</code>s but we still failed to come to a sensible solution.  How about we return the same <code class="language-plaintext highlighter-rouge">Pole</code> when the condition is unsuccessful?</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">case</span> <span class="k">class</span> <span class="nc">Pole</span><span class="o">(</span><span class="n">left</span><span class="k">:</span> <span class="kt">Int</span><span class="o">,</span> <span class="n">right</span><span class="k">:</span> <span class="kt">Int</span><span class="o">)</span> <span class="o">{</span>
  <span class="k">def</span> <span class="nf">landLeft</span><span class="o">(</span><span class="n">n</span><span class="k">:</span> <span class="kt">Int</span><span class="o">)</span><span class="k">:</span> <span class="kt">Pole</span> <span class="o">=</span> <span class="o">{</span>
    <span class="nf">if</span><span class="o">(</span><span class="nv">Math</span><span class="o">.</span><span class="py">abs</span><span class="o">((</span><span class="n">left</span> <span class="o">+</span> <span class="n">n</span><span class="o">)</span> <span class="o">-</span> <span class="n">right</span><span class="o">)</span> <span class="o">&lt;=</span> <span class="mi">3</span><span class="o">)</span> <span class="o">{</span>
      <span class="nc">Pole</span><span class="o">(</span><span class="n">left</span> <span class="o">+</span> <span class="n">n</span><span class="o">,</span> <span class="n">right</span><span class="o">)</span>
    <span class="o">}</span> <span class="k">else</span> <span class="k">this</span>
  <span class="o">}</span>

  <span class="k">def</span> <span class="nf">landRight</span><span class="o">(</span><span class="n">n</span><span class="k">:</span> <span class="kt">Int</span><span class="o">)</span><span class="k">:</span> <span class="kt">Pole</span> <span class="o">=</span> <span class="o">{</span>
    <span class="nf">if</span> <span class="o">(</span><span class="nv">Math</span><span class="o">.</span><span class="py">abs</span><span class="o">((</span><span class="n">right</span> <span class="o">+</span> <span class="n">n</span><span class="o">)</span> <span class="o">-</span> <span class="n">left</span><span class="o">)</span> <span class="o">&lt;=</span> <span class="mi">3</span><span class="o">)</span> <span class="o">{</span>
      <span class="nc">Pole</span><span class="o">(</span><span class="n">left</span><span class="o">,</span> <span class="n">right</span> <span class="o">+</span> <span class="n">n</span><span class="o">)</span>
    <span class="o">}</span> <span class="k">else</span> <span class="k">this</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Let’s try this out starting with 1 bird on the left and 4 birds on the right and let one more bird land on the right hand side.</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">println</span><span class="o">(</span><span class="n">pierreIsOk</span><span class="o">)</span> <span class="c1">// Pole(1,4)</span>
<span class="nf">println</span><span class="o">(</span><span class="nv">pierreIsOk</span><span class="o">.</span><span class="py">landRight</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span> <span class="c1">// Pole(1, 4)</span>
</code></pre></div></div>

<p>Great! We do not get odd exceptions or null pointers so things should be fine! Except that they are not fine.  Let’s look at what happens if we chain more operations after Pierre tumbles up in the air.</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">println</span><span class="o">(</span><span class="n">pierreIsOk</span><span class="o">)</span> <span class="c1">// Pole(1,4)</span>
<span class="k">val</span> <span class="nv">tumbledPierre</span> <span class="k">=</span> <span class="nv">pierreIsOk</span><span class="o">.</span><span class="py">landRight</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span> <span class="c1">// Pole(1, 4)</span>
<span class="k">val</span> <span class="nv">whatHappened</span> <span class="k">=</span> <span class="nv">tumbledPierre</span><span class="o">.</span><span class="py">landLeft</span><span class="o">(</span><span class="mi">1</span><span class="o">).</span><span class="py">landRight</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span> <span class="c1">// Pole(2, 5)</span>
</code></pre></div></div>

<p>Operations are still allowed to be sequenced - it’s as though the context of the computation is not carried forward.  Pierre is magically back on the tight rope as if he never tumbled.  This is clearly incorrect and I’d dare say more dangerous than the other two solutions.  Here we have potential data corruption and an error which is very hard to track.</p>

<h1 id="functional-for-the-win---the-option-context">Functional for the win - The <code class="language-plaintext highlighter-rouge">Option</code> Context</h1>
<p>Let’s now implement Pierre’s scenario using <code class="language-plaintext highlighter-rouge">Option</code> to represent the presence or absence of a <code class="language-plaintext highlighter-rouge">Pole</code>.</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">object</span> <span class="nc">Pierre</span> <span class="o">{</span>
  <span class="k">type</span> <span class="kt">Pole</span> <span class="o">=</span> <span class="o">(</span><span class="nc">Int</span><span class="o">,</span> <span class="nc">Int</span><span class="o">)</span>

  <span class="k">def</span> <span class="nf">landLeft</span><span class="o">(</span><span class="n">bird</span><span class="k">:</span> <span class="kt">Int</span><span class="o">)(</span><span class="n">source</span><span class="k">:</span> <span class="kt">Pole</span><span class="o">)</span><span class="k">:</span> <span class="kt">Option</span><span class="o">[</span><span class="kt">Pole</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
    <span class="nf">val</span> <span class="o">(</span><span class="n">left</span><span class="o">,</span> <span class="n">right</span><span class="o">)</span> <span class="k">=</span> <span class="n">source</span>
    <span class="nf">if</span> <span class="o">(</span><span class="nv">Math</span><span class="o">.</span><span class="py">abs</span><span class="o">((</span><span class="n">left</span> <span class="o">+</span> <span class="n">bird</span><span class="o">)</span> <span class="o">-</span> <span class="n">right</span><span class="o">)</span> <span class="o">&lt;=</span> <span class="mi">3</span><span class="o">)</span> <span class="o">{</span>
      <span class="nc">Option</span><span class="o">((</span><span class="n">left</span> <span class="o">+</span> <span class="n">bird</span><span class="o">,</span> <span class="n">right</span><span class="o">))</span>
    <span class="o">}</span> <span class="k">else</span> <span class="nv">Option</span><span class="o">.</span><span class="py">empty</span>
  <span class="o">}</span>

  <span class="k">def</span> <span class="nf">landRight</span><span class="o">(</span><span class="n">bird</span><span class="k">:</span> <span class="kt">Int</span><span class="o">)(</span><span class="n">source</span><span class="k">:</span> <span class="kt">Pole</span><span class="o">)</span><span class="k">:</span> <span class="kt">Option</span><span class="o">[</span><span class="kt">Pole</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
    <span class="nf">val</span> <span class="o">(</span><span class="n">left</span><span class="o">,</span> <span class="n">right</span><span class="o">)</span> <span class="k">=</span> <span class="n">source</span>
    <span class="nf">if</span> <span class="o">(</span><span class="nv">Math</span><span class="o">.</span><span class="py">abs</span><span class="o">((</span><span class="n">right</span> <span class="o">+</span> <span class="n">bird</span><span class="o">)</span> <span class="o">-</span> <span class="n">left</span><span class="o">)</span> <span class="o">&lt;=</span> <span class="mi">3</span><span class="o">)</span> <span class="o">{</span>
      <span class="nc">Option</span><span class="o">((</span><span class="n">left</span><span class="o">,</span> <span class="n">right</span> <span class="o">+</span> <span class="n">bird</span><span class="o">))</span>
    <span class="o">}</span> <span class="k">else</span> <span class="nv">Option</span><span class="o">.</span><span class="py">empty</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Looking at the return type for <code class="language-plaintext highlighter-rouge">landLeft</code> and <code class="language-plaintext highlighter-rouge">landRight</code> we can immediately deduce that there could be potential failure; the return type is <code class="language-plaintext highlighter-rouge">Option[Pole]</code> indicating that the computation <strong>may have</strong> a <code class="language-plaintext highlighter-rouge">Pole</code> rather than <strong>there will always be</strong> a <code class="language-plaintext highlighter-rouge">Pole</code>.  Ok, so we used <code class="language-plaintext highlighter-rouge">Option</code>, bravo! :neckbeard: but what’s the big deal?  What we gain with <code class="language-plaintext highlighter-rouge">Option</code> is a computational context in which a set of operations can be sequenced.  To understand the difference let’s sequence the same bird landings and observe what happens</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">val</span> <span class="nv">result</span> <span class="k">=</span> <span class="k">for</span> <span class="o">{</span>
    <span class="n">pierreOk</span> <span class="k">&lt;-</span> <span class="nc">Pole</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span> <span class="mi">4</span><span class="o">).</span><span class="py">pure</span><span class="o">[</span><span class="kt">Option</span><span class="o">]</span> <span class="c1">// Some(Pole(1, 4))</span>
    <span class="n">pierreFall</span> <span class="k">&lt;-</span> <span class="nv">pierreOk</span><span class="o">.</span><span class="py">landRight</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span> <span class="c1">// Empty</span>
    <span class="n">willPierreResurrect</span> <span class="k">&lt;-</span> <span class="nv">pierreFall</span><span class="o">.</span><span class="py">landLeft</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span> <span class="c1">// Empty </span>
    <span class="n">result</span> <span class="k">=</span> <span class="nv">willPierreResurrect</span><span class="o">.</span><span class="py">landRight</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span> <span class="c1">// Empty</span>
<span class="o">}</span> <span class="k">yield</span> <span class="nv">resultpierreOk</span><span class="o">.</span><span class="py">landRight</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span>  <span class="c1">// Empty</span>
</code></pre></div></div>

<p>In this case, the value of <code class="language-plaintext highlighter-rouge">result</code> is <code class="language-plaintext highlighter-rouge">Empty</code> rather than <code class="language-plaintext highlighter-rouge">Some(Pole(2, 5))</code>.  The <code class="language-plaintext highlighter-rouge">Option</code> “remembers” that an operation has failed - <code class="language-plaintext highlighter-rouge">pierreOk.landRight(1)</code> - and carries this forward.  Once a computation evaluates to an <code class="language-plaintext highlighter-rouge">Empty</code> value, all further computations will yield an <code class="language-plaintext highlighter-rouge">Empty</code> value.  Pretty cool huh? So in the functional equivalent, we gain honesty of types and we also create a safe context in which operations can be sequenced.</p>

<h1 id="conclusion">Conclusion</h1>
<p>In this post we have outlined the journey of Pierre as a tight rope enthusiast and have simulated his scenario using both the imperative and functional paradigm.  Through the use of FP we have managed to sequence birds landing safely and to make a more honest API.  Hopefully this can motivate some of you to get interested in FP.  Stay safe and keep hacking!</p>]]></content><author><name>Mark Galea</name></author><summary type="html"><![CDATA[One question which often crops up when mentioning Functional Programming (FP) is “But what’s the point of using FP? Why would I change from an Imperative Programming (IP) paradigm to FP if both solve the same class of problems?”. To the uninitiated FP represents a surface level refactor to use “newer methods” such as map, flatMap and filter with a sprinkle of classes such as Option(al) and Either but obviously this is not the case.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://cloudmark.github.io/images/context/tight.png" /><media:content medium="image" url="http://cloudmark.github.io/images/context/tight.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Lambda Calculus is Dead! Long live Lambda Calculus!</title><link href="http://cloudmark.github.io/Lambda-Calculus/" rel="alternate" type="text/html" title="Lambda Calculus is Dead! Long live Lambda Calculus!" /><published>2018-03-05T00:00:00+00:00</published><updated>2018-03-05T00:00:00+00:00</updated><id>http://cloudmark.github.io/Lambda-Calculus</id><content type="html" xml:base="http://cloudmark.github.io/Lambda-Calculus/"><![CDATA[<p><img class="title" src="/images/lambda/haskell.png" /><br />
Introduced by Alonzo Church in the 1930s, $\lambda$-calculus can be considered as the smallest computation programming language of the world. Reading through the various tutorials one can find various examples which showcase its universality; addition, conditional operators, equality and inequality and recursion.  One thing which always intrigued me is how applicable is $\lambda$-calculus to everyday problems such as finding the set of URLs in a sitemap or a set of alternate language urls? <em>The question is obviously rhetorical since we know that $\lambda$-calculus is Turing complete!</em> Can we model a “modern” problem in terms of $\lambda$-calculus and will such a problem still feel natural? The answer is yes! In this post we are going to apply $\lambda$-calculus in an SEO domain, specifically to construct a Sitemap and to find the hreflang for a language.</p>

<h1 id="lambda-calculus">$\lambda$-Calculus</h1>
<div class="example">
    <b>Disclaimer to a future math reader!</b> If you are mathsy and you might feel like pulling your hair out after reading this (mathematical loose hand-wavy) document, rather than going on an epic rant about how useless I am please help out! After all I’m not a Mathematician 🙂 but I'd love to learn! 
</div>

<p>The central concept in $\lambda$-calculus is an <strong>expression</strong>.  An <strong>expression</strong> is defined recursively as follows (not pure $\lambda$-calculus):</p>

\[\begin{eqnarray*}
\texttt{&lt;expression&gt;}&amp;=&amp;\texttt{&lt;name&gt;}|\texttt{&lt;cons&gt;}|\texttt{&lt;function&gt;}|\texttt{&lt;application&gt;}\\
\texttt{&lt;function&gt;}&amp;=&amp;\lambda\texttt{&lt;name&gt;}.\texttt{&lt;expression&gt;}\\
\texttt{&lt;application&gt;}&amp;=&amp;\texttt{&lt;expression&gt;}\texttt{&lt;expression&gt;}
\end{eqnarray*}\]

<p>where</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">name</code>, also referred to as a variable, is an identifier which for our purposes will be any sequence of <em>italic lowercase letters</em> e.g.  <em>lang</em>, <em>slug</em>.</li>
  <li><code class="language-plaintext highlighter-rouge">cons</code> is a constant which for our purposes will be represented by a sequence of lowercase letters e.g.  <code class="language-plaintext highlighter-rouge">en</code>, <code class="language-plaintext highlighter-rouge">fi</code>, <code class="language-plaintext highlighter-rouge">sv</code>.</li>
</ul>

<p>Having defined an <strong>expression</strong> let us look at some examples:</p>

\[\begin{eqnarray*}
&amp;\texttt{en}\\
&amp;\texttt{sv}\\
&amp;\textit{lang}\\
&amp;\lambda\textit{lang}.  \textit{lang}\\
&amp;(\lambda\textit{lang}.\textit{lang})(\lambda\textit{slug}.\textit{slug})\\
&amp;(\lambda\textit{lang}.\textit{lang})\texttt{en} \\
\end{eqnarray*}\]

<p>Notation-wise we will use the following rules:</p>
<ul>
  <li>Variables are listed after the $\lambda$ e.g.  <em>lang</em> is a variable in $\lambda\textit{lang}.\textit{lang}$</li>
  <li>An application is always associated to the left such that $E_1 \dots E_{n} \equiv (((E_1 E_2) E_3) \dots E_n)$</li>
  <li>$\lambda$ binds to the right as far as possible: $\lambda \textit{l}.\textit{l} \textit{l} \equiv \lambda \textit{l}.(\textit{l} \textit{l}) \not\equiv (\lambda \textit{l}.\textit{l})\textit{l}$</li>
  <li>Outermost parenthesis are omitted: $E_1 \ldots E_2 \equiv (E_1 \ldots E_2)$</li>
</ul>

<h2 id="free-and-bound-variables">Free and Bound Variables</h2>
<p>In $\lambda$-calculus all names are local to definition.  In the function $\lambda \textit{x}.\textit{x}$ we say that $\textit{x}$ is “bound” since its occurrence in the body of the definition is preceded by $\lambda \textit{x}$.  A name not preceded by $\lambda$ is called a “free variable”.</p>

<p>The set of free variables can be defined recursively:</p>

\[\begin{eqnarray*}
  &amp;FV(&lt;cons&gt;) &amp;=&amp; \emptyset \\
  &amp;FV(&lt;name&gt;) &amp;=&amp; {&lt;name&gt;} \\
  &amp;FV(&lt;exp_1&gt; &lt;exp_2&gt;) &amp;=&amp; FV(&lt;exp_1&gt;) \cup FV(&lt;exp_2&gt;) \\
  &amp;FV(\lambda &lt;name&gt;.  &lt;exp&gt;) &amp;=&amp; FV(&lt;exp&gt;) \setminus \{&lt;name&gt;\}
\end{eqnarray*}\]

<p>Similarly, the set of bound variables can be defined recursively:</p>

\[\begin{eqnarray*}
  &amp;BV(&lt;cons&gt;) &amp;=&amp; {&lt;cons&gt;} \\
  &amp;BV(&lt;name&gt;) &amp;=&amp; \emptyset \\
  &amp;BV(&lt;exp_1&gt; &lt;exp_2&gt;) &amp;=&amp; BV(&lt;exp_1&gt;) \cup BV(&lt;exp_2&gt;) \\
  &amp;BV(\lambda &lt;name&gt;.  &lt;exp&gt;) &amp;=&amp; BV(&lt;exp&gt;) \cup \{&lt;name&gt;\}
\end{eqnarray*}\]

<h2 id="beta-reduction">$\beta$-Reduction</h2>
<p>In $\lambda$-calculus there is one computational rule called $\beta-$reduction: $((\lambda\textit{x}.s)\texttt{t})$ can be reduced to $\textit{s}[\texttt{t}/\textit{x}]$, the result of replacing the arguments $\texttt{t}$ for the formal parameter $\textit{x}$ in $s$. 
<em>Note: It is assumed that no substitution will mix free and bound identifiers and hence we will omit the discussion of $\alpha$-reduction.</em> Some examples are:</p>

\[\begin{eqnarray*}
((\lambda \textit{lang}.\textit{lang})\texttt{en}) \rightarrow_{\beta} \texttt{en} \\
((\lambda\textit{x}.\textit{x})(\lambda\textit{x}.\textit{x})) \rightarrow_{\beta} (\lambda\textit{x}.\textit{x})
\end{eqnarray*}\]

<p>A more complex example would be the following:</p>

\[\begin{eqnarray*}
&amp;((\lambda \textit{lang}.  (\lambda \textit{slug}.  \textit{lang} \ \textit{slug})) `en`)\texttt{lobby} \\
&amp;((\lambda \boxed{\textit{lang}}.  (\lambda \textit{slug}.\boxed{\textit{lang}}\textit{slug}))\boxed{\texttt{en}})\texttt{lobby} \\
&amp;(\lambda \textit{slug}.\texttt{en}\ \textit{slug})\texttt{lobby} \\
&amp;(\lambda \boxed{\textit{slug}}.\texttt{en}\ \boxed{\textit{slug}})\boxed{\texttt{lobby}} \\
&amp;(\texttt{en}\ \texttt{lobby}) \\
\end{eqnarray*}\]

<p>Some $\lambda-$expressions have a non-deterministic reduction.  Let us take as an example the $\lambda$-expression $(\lambda x.x x)((\lambda y.y)z)$.  This $\lambda$-expression has two possible reductions</p>

\[\begin{eqnarray*}
&amp; (\lambda x.x x)((\lambda y.y)z) \\
&amp; (\lambda x.x x)(\lambda z.z) \\ 
&amp; (\lambda z.z)(\lambda z.z) \\ 
&amp; (\lambda z.z)    
\end{eqnarray*}\]

<p>and</p>

\[\begin{eqnarray*}
&amp; (\lambda x.x x)((\lambda y.y)z) \\
&amp; ((\lambda y.y)z)((\lambda y.y)z) \\ 
&amp; (\lambda z.z)(\lambda z.z) \\ 
&amp; (\lambda z.z)    
\end{eqnarray*}\]

<p>On the other end of the spectrum we find expressions that do not have a single reduction sequence.  As an example consider</p>

\[\begin{eqnarray*}
(\textit{x}(\lambda \textit{y}.\textit{y}))
\end{eqnarray*}\]

<p>For the purposes of our discussion we will only consider $\lambda$-expressions of the form</p>

\[\begin{equation*}
(\lambda n_1\lambda n_2\ldots\lambda n_{k} \cdot n_1n_2\ldots n_{k})c_1c_2\ldots c_{k}
\end{equation*}\]

<p>where $n_1\ldots n_{k}$ are the parameters of the lambda functions and $c_1\ldots c_{k}$ are the arguments of the function.  Each individual argument $c_{k}$ can be either a name or constant.  It can be shown that expressions of this form are <strong>deterministic</strong> and <strong>fully normalised</strong> (cannot be reduced further).  Specifically, it will take $k$ $\beta-$reductions to normalise the $\lambda$-expression.</p>

\[\begin{eqnarray*}
&amp; (\lambda n_1\lambda n_2\ldots\lambda n_{k} \cdot n_1n_2\ldots n_{k})c_1c_2\ldots c_{k} \\
&amp; (\lambda n_2\ldots\lambda n_{k} \cdot c_1n_2\ldots n_{k})c_2\ldots c_{k}[c_1|n_1] \\ 
&amp; (\lambda n_3\ldots\lambda n_{k} \cdot c_1c_2\ldots n_{k})c_3\ldots c_{k}[c_2|n_2] \\
&amp; \dots \\
&amp; (c_1c_2\ldots c_{k})[c_{k}|n_{k}] \\    
\end{eqnarray*}\]

<h2 id="context">Context</h2>
<p>Given a $\lambda$-expression of the form</p>

\[\begin{equation*}
   (\lambda n_1\lambda n_2\ldots\lambda n_{k} \cdot n_1n_2\ldots n_{k})c_1c_2\ldots c_{k}
   \end{equation*}\]

<p>we will refer to the sequence of reductions $c_1c_2\ldots c_{k}$ as the <strong>context</strong> of the $\lambda-$expression.  In this context the item $c_{k}$ is called a variable.  The <em>variable</em> $c_{k}$ can take on two possible values: a <em>name</em> or a <code class="language-plaintext highlighter-rouge">constant</code>.  If $c_{k}$ is a <em>name</em> we will say that the variable $c_{k}$ is a <em>free variable</em> since the normalised expression will contain such a name $c_{k}$ in the set of free variables.  If $c_{k}$ is a <code class="language-plaintext highlighter-rouge">constant</code> we will say that the variable $c_{k}$ is a <em>bound variable</em> since the normalised expression will contain such a constant $c_{k}$ in the set of bound variables.  As an example let us consider the following:</p>

\[\begin{eqnarray*}
   &amp; (\lambda n_1\lambda n_2\cdot n_1n_2) \textit{a}\ \texttt{lobby} \\
   &amp; (\lambda n_2\cdot \textit{a}\ n_2) \texttt{lobby}[\textit{a}|n_1] \\
   &amp; \textit{a}\ \texttt{lobby}[\texttt{lobby}|n_2]\\
   &amp; \textit{a}\ \texttt{lobby}
   \end{eqnarray*}\]

<p>In this case the variable $c_1$ is the name $\textit{a}$ and the variable $c_2$ is the constant $\texttt{lobby}$.  The normalised expression is $\textit{a}\ \texttt{lobby}$.  It is clear that the free variable $\textit{a}$ is a free variable in the normalised $\lambda-$expression $\textit{a}\ \texttt{lobby}$ and that $\texttt{lobby}$ is a bound variable.</p>

<p>When all $c_1\ldots c_{k}$ variables are <em>free</em> we will refer to the lambda expression as a <em>free lambda expression</em>.  When all $c_1\ldots c_{k}$ variables are <em>bound</em> we will refer to the lambda expression as a <em>bound lambda expression</em>.  When the context contains a mix of free and bound variables we will refer to the lambda expression as a <em>partial lambda expression</em>.</p>

<p>Given a context $c_1\ldots c_{k}$, the $\lambda-$expression required to normalise to the context is</p>

\[(\lambda n_1\ldots\lambda n_{k} \cdot n_1\ldots n_{k})c_1\ldots c_{k}\]

<p>Similarly, given a normalised expression $c_1\ldots c_{k}$ one can always find the source context and the source $\lambda-$expression which reduced to the normalised expression.  To make such a conversion explicit we will use the function $\omega(c_1\ldots,c_{k})$</p>

\[\begin{eqnarray*}
   \omega(c_1\ldots c_{k}) &amp;=&amp; (\lambda n_1\ldots\lambda n_{k} \cdot n_1\ldots n_{k})c_1\ldots c_{k}
 \end{eqnarray*}\]

<h1 id="expression-tree">Expression Tree</h1>
<p>Starting with a $\lambda$-expression at the root, one can visualise all the reduction steps leading to the normalised expression in a tree.  As an example let us consider how the reduction sequence for $(\lambda \textit{lang}.  \textit{lang}) \texttt{en}$ can be represented.</p>

<p><img class="step minimal" style="width: 280px" src="/images/lambda/1.png" /></p>

<p>A more complex example would be the following</p>

<p><img class="step minimal" style="width: 450px" src="/images/lambda/2.png" /></p>

<p>In general, the generic $\lambda-$expression</p>

\[\begin{eqnarray*}
&amp; (\lambda n_1\lambda n_2\ldots\lambda n_{k} \cdot n_1n_2\ldots n_{k})c_1c_2\ldots c_{k} \\    
\end{eqnarray*}\]

<p>can be represented as follows</p>

<p><img class="step minimal" style="width: 550px" src="/images/lambda/3.png" /></p>

<p>Notation-wise we will use $\psi((\lambda n_1\ldots\lambda n_{k} \cdot n_1\ldots n_{k})c_1\ldots c_{k})$ or $\psi(\omega(c_1\ldots c_{k}))$ to refer to the sequence of reductions i.e.  expression tree.</p>

<h1 id="expression-sets">Expression Sets</h1>
<p>Reduction trees discussed in the previous section represent the normalisation steps for a given expression $\omega(c_1c_2\ldots c_{k})$ where $c_1,\ldots,c_{k}$ is in a given configuration.  If $c_{1} \in  \mathcal{C}_{1}, c_{2} \in \mathcal{C}_{2}, \ldots, c_{k} \in \mathcal{C}_{k}$ we can build the set of all expression trees by normalising all expressions in the set</p>

\[\begin{eqnarray*}
\mathcal{RS} = \{ \omega(c_1c_2\ldots c_{k}) | (c_1, c_2, \ldots, c_{k}) \in \mathcal{C}_{1} \times \mathcal{C}_{2} \times \ldots \times \mathcal{C}_{k}\}
\end{eqnarray*}\]

<p>You can think of $\mathcal{C}_{k}$ as the type for variable $c_{k}$.  As an example let us consider the expression $((\lambda \textit{lang}.  (\lambda \textit{slug}.  \textit{lang}\ \textit{slug}))c_1c_2$.  Where $c_1 \in \{ \texttt{en}, \texttt{fi} \}$ and $c_2 \in \{ \texttt{lobby} \}$.  The reduction set $\mathcal{RS}$ would contain two trees</p>

<p><img class="step minimal" style="width: 700px" src="/images/lambda/4.png" /></p>

<p>If $c_1 \in \{\texttt{e}, \texttt{f}\}$ and $c_2 \in \{\texttt{l}, \texttt{g}\}$ the reduction set $\mathcal{RS}$ would contain four trees</p>

<p><img class="step minimal" style="width: 700px" src="/images/lambda/5.png" /></p>

<p>Given that each expression tree has only one reduction sequence to normalisation we will merge all expression trees in a single tree by omitting the context.  As an example let us consider the $\lambda-$expression set</p>

\[\begin{eqnarray*}
&amp; (\lambda \textit{lang}.  (\lambda \textit{slug}.  \textit{lang}\ \textit{slug}))c_1c_2
\end{eqnarray*}\]

<p>where $c_1 \in \{ \texttt{en},\texttt{fi}\}$ and $c_2 \in \{ \texttt{lobby}, \texttt{games}\}$.</p>

<p>The expression set can be represented as</p>

<p><img class="step minimal" style="width: 700px" src="/images/lambda/6.png" /></p>

<p>It is important to note that an <em>expression set</em> tree is just a <em>visualisation aide</em>.  Mentally, one should always expand each node in the tree to the set of $\lambda-$expressions.  At each level the set of $\lambda-$expressions being represented can be found by mapping all descendant leaf-nodes using $\omega(c_1c_2\ldots c_{k})$ defined in the previous section.  As an example the root node in the expression set $\lambda \textit{l}.\lambda \textit{s}.\textit{l}\ \textit{s}$ has four descendant leaf nodes</p>

\[\begin{eqnarray*} 
&amp;\{\omega(\texttt{en}\ \texttt{lobby}),\omega(\texttt{fi}\ \texttt{lobby}),\omega(\texttt{en}\ \texttt{games}),\omega(\texttt{fi}\ \texttt{games})\}
\end{eqnarray*}\]

<p>and hence represents the set</p>

\[\begin{eqnarray*} 
&amp;\{\lambda \textit{l}.\lambda \textit{s}.\textit{l}\textit{s}\ \texttt{en}\ \texttt{lobby},
\lambda \textit{l}.\lambda \textit{s}.\textit{l}\textit{s}\ \texttt{fi}\ \texttt{lobby}, 
\lambda \textit{l}.\lambda \textit{s}.\textit{l}\textit{s}\ \texttt{en}\ \texttt{games},
\lambda \textit{l}.\lambda \textit{s}.\textit{l}\textit{s}\ \texttt{fi}\ \texttt{games} \}
\end{eqnarray*}\]

<h2 id="freeboundpartial-reduction-sets">Free/Bound/Partial Reduction Sets</h2>
<p>Leaf nodes in a reduction set represent normalised expressions.  If <strong>all</strong> leaf expressions (normalised expressions) are bound expressions we say that the reduction set is a <em>bound reduction set</em>.  The example below illustrates a bound reduction set.</p>

<p><img class="step minimal" style="width: 350px" src="/images/lambda/7.png" /></p>

<p>If <strong>some</strong> normalised expressions are bound we say that the reduction set is a <em>partial reduction set</em>.  The example below illustrates a partial reduction set.</p>

<p><img class="step minimal" style="width: 370px" src="/images/lambda/8.png" /></p>

<p>If <strong>no</strong> normalised expressions are bound  - that is all leaf expressions are free - we say that the reduction set is a <em>free reduction set</em>.  The example below illustrates a free reduction set.</p>

<p><img class="step minimal" style="width: 290px" src="/images/lambda/9.png" /></p>

<h1 id="serialisation-and-de-serialisation">Serialisation and de-serialisation</h1>
<h2 id="serialisation">Serialisation</h2>
<p>Given a $\lambda-$expression of the form</p>

\[\begin{eqnarray*}
(\lambda n_1\lambda n_2\lambda n_3\ldots\lambda n_{k} \cdot n_1n_2n_3\ldots n_{k})c_1c_2c_3\ldots c_{k}
\end{eqnarray*}\]

<p>we can serialise the normalised reduction $c_1\ldots c_{k}$ by means of a <strong>bijective</strong> function $f$ which takes a context configuration and maps it to a string $s$.  The function $f$ has to be bijective, as later on, we will need to deserialise the string back to the context.</p>

\[\begin{eqnarray*}
f: \mathcal{C}_{1} \times \ldots \times \mathcal{C}_{k} \rightarrow \mathcal{S} 
\end{eqnarray*}\]

<p>One implementation of serialisation function $f$ is to join the context using the / character.  As we have two types of variables, free and bound, we need to distinguish between these different types so during deserialisation, the context can be correctly reconstructed.  In order to distinguish between free and bound variables we will prefix free variables with the colon prefix.</p>

<p>Let’s serialise the following expression</p>

\[\begin{eqnarray*}
(\lambda \textit{n}_1.  (\lambda \textit{n}_2.  \textit{n}_1\ \textit{n}_2) \textit{lang})\texttt{slots}
\end{eqnarray*}\]

<p>The normalised context for this expression is</p>

\[\begin{eqnarray*}
&amp;c_1=\textit{lang}\\
&amp;c_2=\texttt{slots}
\end{eqnarray*}\]

<p>The result of serialising the above expression is</p>

\[\begin{eqnarray*}
f(\textit{lang }\texttt{slots}) = /\colon lang/slots/
\end{eqnarray*}\]

<p>One other implementation of a serialisation function is $f_{int}$ which takes a context and serialises the context into an internationalised string. As an example consider 
\(\begin{eqnarray*}
(\lambda \textit{n}_1.  (\lambda \textit{n}_2.  \textit{n}_1\ \textit{n}_2) \texttt{fi})\texttt{slots}
\end{eqnarray*}\)</p>

<p>The context for this expression is</p>

\[\begin{eqnarray*}
&amp;c_1=\texttt{fi}\\
&amp;c_2=\texttt{slots}
\end{eqnarray*}\]

<p>The result of serialising the above expression is 
\(\begin{equation*}
f_{int}(\texttt{fi slots}) = /fi/kolikkopelit/
\end{equation*}\)</p>

<p>where the constant <code class="language-plaintext highlighter-rouge">slots</code> in Finnish is serialised to <em>kolikkopelit</em>.</p>

<h2 id="deserialisation">Deserialisation</h2>
<p>Deserialisation maps a string representation back to the context.</p>

\[\begin{eqnarray*}
\bar{f}: \mathcal{S} \rightarrow \mathcal{C}_{1} \times \ldots \times \mathcal{C}_{k} 
\end{eqnarray*}\]

<p>One implementation of the $\bar{f}$ function obtains the original context using the context extraction function $ce$</p>

\[\begin{eqnarray*}
ce(/c_1/c_2/\dots /c_k/) = c_1c_2\dots c_k
\end{eqnarray*}\]

<p>and reconstructs the original expression using the $\omega$ function</p>

\[\begin{eqnarray*}
\bar{f}(/c_1/c_2/\dots /c_k/)&amp;=&amp;\omega(ce(/c_1/c_2/\dots /c_k)) 
\end{eqnarray*}\]

<p>Given a serialisation</p>

\[\begin{eqnarray*}
&amp;/\colon lang/lobby/ \\
&amp;\bar{f}(/\colon lang/lobby/) = (\lambda n_1\lambda n_2\cdot n_1n_2)\textit{lang}\ \texttt{lobby}
\end{eqnarray*}\]

<h1 id="search">Search</h1>
<p>Search enables us to find a particular expression tree in an expression set.  In order to create a search function we will first define a match function for expressions.  The match function takes a source (<em>source</em>) $\lambda$-expression and a search $\lambda$-expression (<em>se</em>) and returns a true if</p>

\[\begin{eqnarray*}
match(source, se) = BV(source) \supseteq BV(se)
\end{eqnarray*}\]

<p>As an example let us match $\lambda l.\texttt{en}$ to itself</p>

\[\begin{eqnarray*}
&amp; match(\lambda l.\texttt{en},\ \lambda l.\texttt{en}) \\ 
&amp; BV(\lambda l.\texttt{en}) \supseteq BV(\lambda l.\texttt{en}) \\
&amp; \{ l, \texttt{en} \} \supseteq \{ l, \texttt{en} \} \\
&amp; true
\end{eqnarray*}\]

<p>Having defined match for expression we will move up the abstraction hierarchy and define matching on expression trees.  Let’s overload the $match$ function so that it now takes a source expression tree and a search expression tree and calls match on the source and search expression trees.</p>

<p>Let us $match$ the expression tree $\psi(((\lambda \textit{l}.  (\lambda \textit{s}.  \textit{l}\ \textit{s})) \texttt{en})\texttt{lobby})$ to itself.</p>

\[\begin{eqnarray*}
&amp; match(\psi(\omega(\texttt{en lobby})),\ \psi(\omega(\texttt{en lobby}))) \\
&amp; match(\texttt{en lobby},\ \texttt{en lobby}) \\ 
&amp; BV(\texttt{en lobby}) \supseteq BV(\texttt{en lobby}) \\
&amp; \{ \texttt{en}, \texttt{lobby} \} \supseteq \{ \texttt{en}, \texttt{lobby} \} \\
&amp; true
\end{eqnarray*}\]

<p>Having defined match for expression tree we will move up (once again) the abstraction hierarchy and define a $search$ function for expression sets.  Since the expression set $\mathcal{RS}$ represents a set of expression trees, searching through an expression set is simply the act of matching each element of the expression set with the search expression tree <em>se</em>.</p>

\[\begin{equation*}
\mathcal{RS}_{match}(se) = \{ t \in \mathcal{RS}, match(t, se) \}
\end{equation*}\]

<h1 id="search-properties">Search Properties</h1>
<p>In this section we shall look at two search properties: the search identity and freed context identity.</p>

<div class="example">
  <b>Search Identity</b> Searching for a context equal to a normalised expression $\textit{e}$ present in an expression set $\mathcal{RS}$ will yield the result set $\mathcal{RS}_{match} = \{ \psi(\omega(\textit{e})) \}$.
  </div>
<p><br /></p>
<div class="example">
    <b>Freed Context Identity</b>
  Starting from a normalised expression $\textit{e}$ present in the expression set $\mathcal{RS}$ and freeing one or more `constants` will yield the results set $\mathcal{RS}_{match}$ which includes $\psi(\textit{e})$ i.e. $\mathcal{RS}_{match} \supseteq \{ \psi(\omega(\textit{e})) \}$ .  
</div>

<h2 id="search-identity">Search identity</h2>
<p>The number of normalised expression nodes a set can have is dependant on the context.  Specifically it is the cartesian product of all contexts $\mathcal{C}_{1}\ldots \mathcal{C}_{k}$.  The set of normalised expressions in a bound expression set $\mathcal{RS}$ implies that there is one and only one reduction to any $c’ \in \mathcal{C}_{1} \times \ldots \times \mathcal{C}_{k}$.  Thus, any search starting from a bound context $c’$ will find the same normalised node $c’$.  We call this the <strong>search identity</strong>.</p>

<p>Let’s for instance search for</p>

\[\begin{eqnarray*}
\psi((\lambda \textit{l}.  \lambda \textit{s}.  \textit{l}\ \textit{s})\texttt{en}\ \texttt{lobby})
\end{eqnarray*}\]

<p>on the expression set</p>

\[\begin{eqnarray*}
\mathcal{RS} = (\lambda \textit{l}.  \lambda \textit{s}.  \textit{l}\ \textit{s}){c}_1{c}_2
\end{eqnarray*}\]

<p>where $c_1 \in \{\texttt{en}, \texttt{fi}\}$ and $c_2 \in \{\texttt{lobby}, \texttt{games}\}$.</p>

\[\begin{eqnarray*}
search(\mathcal{RS}, \psi((\lambda \textit{l}.  \lambda \textit{s}.  \textit{l}\ \textit{s})\texttt{en}\ \texttt{lobby})) &amp;=&amp; \psi((\lambda \textit{l}.  \lambda \textit{s}.  \textit{l}\ \textit{s})\texttt{en}\ \texttt{lobby})
\end{eqnarray*}\]

<p>The individual $match$ reductions are</p>

\[\begin{eqnarray*}
&amp; match(\psi(\omega(\texttt{fi lobby})),\ \psi(\omega(\texttt{en lobby}))) \\ 
&amp; match(\texttt{fi lobby},\ \texttt{en lobby}) \\ 
&amp; BV(\texttt{fi lobby}) \supseteq BV(\texttt{en lobby})\\
&amp; \{ \texttt{fi}, \texttt{lobby} \} \supseteq \{ \texttt{en}, \texttt{lobby} \} \\
&amp; false
\end{eqnarray*}\]

\[\begin{eqnarray*}
&amp; match(\psi(\omega(\texttt{fi games})),\ \psi(\omega(\texttt{en lobby}))) \\ 
&amp; match(\texttt{fi games},\ \texttt{en lobby}) \\ 
&amp; BV(\texttt{fi games}) \supseteq BV(\texttt{en lobby}) \\
&amp; \{ \texttt{fi}, \texttt{games} \} \supseteq \{ \texttt{en}, \texttt{lobby} \} \\
&amp; false
\end{eqnarray*}\]

\[\begin{eqnarray*}
&amp; match(\psi(\omega(\texttt{en games})),\ \psi(\omega(\texttt{en lobby}))) \\ 
&amp; match(\texttt{en games},\ \texttt{en lobby}) \\ 
&amp; BV(\texttt{en games}) \supseteq BV(\texttt{en lobby}) \\
&amp; \{ \texttt{en}, \texttt{games} \} \supseteq \{ \texttt{en}, \texttt{lobby} \} \\
&amp; false
\end{eqnarray*}\]

\[\begin{eqnarray*}
&amp; match(\psi(\omega(\texttt{en lobby})),\ \psi(\omega(\texttt{en lobby}))) \\
&amp; match(\texttt{en lobby},\ \texttt{en lobby}) \\  
&amp; BV(\texttt{en lobby}) \supseteq BV(\texttt{en lobby}) \\
&amp; \{ \texttt{en}, \texttt{lobby} \} \supseteq \{ \texttt{en}, \texttt{lobby} \} \\
&amp; true
\end{eqnarray*}\]

<h2 id="freed-context-search">Freed context search</h2>
<p>Searching for a bound expression tree will not yield meaningful results. In general we are interested in searching for expression trees  which are <em>similar</em> to a search expression tree.  In order to generalise a normalised expression  tree we will substitute one or more <code class="language-plaintext highlighter-rouge">constants</code> with free variables.  Consider the following expression set</p>

<blockquote>
  <p>In general one would search for a bound expression tree to uniquely identify the expression tree within an expression set</p>
</blockquote>

\[\begin{eqnarray*}
\mathcal{RS} = (\lambda \textit{l}.  \lambda \textit{s}.  \textit{l}\ \textit{s}){c}_1{c}_2
\end{eqnarray*}\]

<p>where $c_1 \in \{\texttt{en}, \texttt{fi}\}$ and $c_2 \in \{\texttt{lobby}, \texttt{games}\}$.</p>

<p><img class="step minimal" style="width: 700px" src="/images/lambda/10.png" /></p>

<p>The normalised reduction for the node with the $\dagger$ symbol is $\texttt{en}\ \texttt{lobby}$.  In order to retrieve similar nodes one needs to substitute <code class="language-plaintext highlighter-rouge">constants</code> with free variables.  Such a substitution marginalises all constant values for the given variable $c_{k}$ making such a variable (in the context) irrelevant to the search.  For instance in order to find similar $\texttt{lobby}$ expression trees, we retain the bound $\texttt{lobby}$ constant and replace the $\texttt{en}$ value with the free variable $\ast$.  Searching for the expression tree $\psi(\lambda \textit{lang}.  (\lambda \textit{slug}.  \textit{lang}\ \textit{slug})\ast\ \texttt{lobby})$ will yield</p>

\[\begin{equation*}
search(\mathcal{RS}, \psi((\lambda \textit{lang}.  (\lambda \textit{slug}.  \textit{lang}\ \textit{slug})) \ast\  \texttt{lobby})) = \{ \psi(\omega(\texttt{en lobby})), \psi(\omega(\texttt{fi lobby})) \}
\end{equation*}\]

<p>The individual $match$ reductions are</p>

\[\begin{eqnarray*}
&amp; match(\psi(\omega(\texttt{fi lobby})),\ \psi(\omega(\ast\ \texttt{lobby}))) \\ 
&amp; match(\texttt{fi lobby},\ \ast\ \texttt{lobby}) \\ 
&amp; BV(\texttt{fi lobby}) \supseteq BV(\ast\ \texttt{lobby}) \\
&amp; \{ \texttt{fi}, \texttt{lobby} \} \supseteq \{ \texttt{lobby} \} \\
&amp; true
\end{eqnarray*}\]

\[\begin{eqnarray*}
&amp; match(\psi(\omega(\texttt{fi games})),\ \psi(\omega(\ast\ \texttt{lobby}))) \\ 
&amp; match(\texttt{fi games},\ \ast\ \texttt{lobby}) \\ 
&amp; BV(\texttt{fi games})) \supseteq BV(\ast\ \texttt{lobby}) \\
&amp; \{ \texttt{fi}, \texttt{games} \} \supseteq \{ \texttt{lobby} \} \\
&amp; false
\end{eqnarray*}\]

\[\begin{eqnarray*}
&amp; match(\psi(\omega(\texttt{en lobby})),\ \psi(\omega(\ast\ \texttt{lobby}))) \\
&amp; match(\texttt{en lobby},\ \ast\ \texttt{lobby}) \\ 
&amp; BV(\texttt{en lobby}) \supseteq BV(\ast\ \texttt{lobby}) \\
&amp; \{ \texttt{en}, \texttt{lobby} \} \supseteq \{ \texttt{lobby} \} \\
&amp; true
\end{eqnarray*}\]

\[\begin{eqnarray*}
&amp; match(\psi(\omega(\texttt{en games})),\ \psi(\omega(\ast\ \texttt{lobby}))) \\
&amp; match(\texttt{en games},\ \ast\ \texttt{lobby}) \\ 
&amp; BV(\texttt{en games}) \supseteq BV(\ast\ \texttt{lobby}) \\
&amp; \{ \texttt{en}, \texttt{games} \} \supseteq \{ \texttt{lobby} \} \\
&amp; false
\end{eqnarray*}\]

<h1 id="nothing-give-me-nothing">Nothing! Give me Nothing!</h1>
<p>Given the $\lambda$-expression</p>

\[\begin{eqnarray*}
(\lambda n_1\lambda n_2\lambda n_3\ldots\lambda n_{k} \cdot n_1n_2n_3\ldots n_{k})c_1c_2c_3\ldots c_{k}
\end{eqnarray*}\]

<p>there may be cases where the context $c_k$ is <em>undefined</em> or <em>nothing</em>.  We will represent nothing using the token constant $\varnothing$.  We require that the types $\mathcal{C}_{k}$ include a dummy bound value $\varnothing$ to represent nothing.  A configuration $c_1,\ldots,c_{k}$ is considered valid if</p>

\[\begin{eqnarray*}
\exists c_i.\ c_i=\emptyset\ |\ \forall c_{j}.c_{j}=\emptyset, j&gt;i
\end{eqnarray*}\]

<p>Informally, this requires that if a variable in a particular position within a configuration is $\varnothing$, all subsequent variables within the configuration need to be $\varnothing$.</p>

<p>As an example, let us consider the $\lambda$-expression</p>

\[\begin{eqnarray*}
(\lambda a.  \lambda b.  \lambda c.  abc)c_1c_2c_3
\end{eqnarray*}\]

<p>where</p>

\[\begin{eqnarray*} 
&amp; c_1 \in \{\texttt{a}, \texttt{b}\} \\ 
&amp; c_2 \in \{\texttt{c} \} \\ 
&amp; c_3 \in \{\texttt{d} \} \\
\end{eqnarray*}\]

<p>In order to introduce nothing, we will add the constant $\varnothing$ to all type sets</p>

\[\begin{eqnarray*} 
&amp; c_1 \in \{\texttt{a}, \texttt{b}, \varnothing \} \\ 
&amp; c_2 \in \{\texttt{c}, \varnothing\} \\ 
&amp; c_3 \in \{\texttt{d}, \varnothing\} \\
\end{eqnarray*}\]

<p>and restrict the configuration $c_1c_2c_3$ to be in the set</p>

\[\begin{eqnarray*}
\{\texttt{a}\texttt{c}\texttt{d}, \texttt{b}\texttt{c}\texttt{d},\ \texttt{a}\texttt{c}\varnothing, \texttt{b}\texttt{c}\varnothing, \texttt{a}\varnothing\varnothing, \texttt{b}\varnothing\varnothing, \varnothing\varnothing\varnothing \} \\
\end{eqnarray*}\]

<p>$\varnothing$ does not affect $\beta-$reduction, it is after all a <code class="language-plaintext highlighter-rouge">constant</code>.  As an example let us consider</p>

\[\begin{eqnarray*}
&amp;(\lambda \textit{lang}.  (\lambda \textit{slug}.  \textit{lang}\ \textit{slug}))\texttt{en}\ \varnothing \\
&amp;(\lambda \textit{slug}.  \texttt{en}\ \textit{slug})\ \varnothing \\ 
&amp;\texttt{en}\ \varnothing
\end{eqnarray*}\]

<p>We will typically omit $\varnothing$ from the expression set for clarity.</p>

<h3 id="search-including-nothing">Search including nothing</h3>
<p>As the $\varnothing$ is a constant, search does not need to be modified. Lets search for the expression tree $\psi(\omega({\texttt{en }\varnothing}))$ in the expression set</p>

\[\begin{eqnarray*}
\mathcal{RS}&amp;=&amp;\lambda \textit{lang}.  (\lambda \textit{slug}.  \textit{lang}\ \textit{slug})
\end{eqnarray*}\]

<p>where $lang \in \{\texttt{en},\ \varnothing\}$ and $slug \in \{\texttt{lobby},\ \varnothing\}$.</p>

<p><img class="step minimal" style="width: 400px" src="/images/lambda/11.png" /></p>

\[\begin{eqnarray*}
search(\mathcal{RS}, \psi(\omega({\texttt{en }\varnothing}))) = \{ \psi(\omega({\texttt{en }\varnothing})) \}
\end{eqnarray*}\]

<p>The individual $match$ reductions are</p>

\[\begin{eqnarray*}
&amp; match(\psi(\omega(\texttt{en lobby})),\ \psi(\omega(\texttt{en }\varnothing))) \\ 
&amp; match(\texttt{en lobby},\ \texttt{en }\varnothing) \\ 
&amp; BV(\texttt{en lobby}) \supseteq BV(\texttt{en }\varnothing) \\
&amp; \{ \texttt{en, lobby} \} \supseteq \{ \texttt{en }\varnothing \} \\
&amp; false
\end{eqnarray*}\]

\[\begin{eqnarray*}
&amp; match(\psi(\omega(\texttt{en } \varnothing)),\ \psi(\omega(\texttt{en }\varnothing))) \\ 
&amp; match(\texttt{en } \varnothing,\ \texttt{en }\varnothing) \\ 
&amp; BV(\texttt{en }\varnothing) \supseteq BV(\texttt{en }\varnothing)\\
&amp; \{ \texttt{en }\varnothing \} \supseteq \{ \texttt{en }\varnothing \} \\
&amp; true
\end{eqnarray*}\]

\[\begin{eqnarray*}
&amp; match(\psi(\omega(\varnothing\ \varnothing)),\ \psi(\omega(\texttt{en }\varnothing))) \\ 
&amp; match(\varnothing\ \varnothing,\ \texttt{en }\varnothing) \\ 
&amp; BV(\varnothing\ \varnothing) \supseteq BV(\texttt{en }\varnothing) \\
&amp; \{ \varnothing\ \varnothing \} \supseteq \{ \texttt{en }\varnothing \} \\
&amp; false
\end{eqnarray*}\]

<p>This comes as no surprise due to the search identity! Note that $\psi(\omega(\varnothing\ \texttt{lobby}))$ is not included in $\mathcal{RS}$ since this would violate</p>

\[\begin{eqnarray*}
\exists c_i.\ c_i=\emptyset\ |\ \forall c_{j}.c_{j}=\emptyset, j&gt;i
\end{eqnarray*}\]

<h1 id="integrating-this-with-the-content-management-system">Integrating this with the Content Management System</h1>
<p>In this section we shall discuss how the $\lambda$-calculus can be applied to solve two SEO problems: getting all the paths of the site and getting a path’s alternates in other languages.</p>

<h2 id="constructing-the-partial-expression-set">Constructing the Partial Expression Set</h2>
<p>Constructing an internationalised sitemap can be translated to the problem of serialising a bound expression set.  But how does one construct such a bound expression set? All URLs on our website are saved in a Content Management System (CMS) and follow one of the following forms:</p>

\[\begin{eqnarray*}
&amp;\texttt{/:lang/}\\
&amp;\texttt{/:lang/slots/}\\
&amp;\texttt{/:lang/slots/:slug/}
\end{eqnarray*}\]

<p>One can interpret the above URLs as a serialisation originating from the expression set</p>

\[\begin{eqnarray*}
(\lambda n_{1}. \lambda n_{2}. \lambda n_3. n_{1}n_{2}n_{3})	c_{1}c_{2}c_{3}
\end{eqnarray*}\]

<p>where $c_{1}=\textit{lang}$, $c_{2} \in \{ \texttt{slots}, \varnothing \}$ and $c_{3}=\textit{slug}$.</p>

<p><img class="step minimal" style="width: 350px" src="/images/lambda/12.png" /></p>

<p>Such an expression set is a partial expression set and needs to be bound in order to retrieve a site’s sitemap. Recall from earlier that free variables represent a marginalisation of <code class="language-plaintext highlighter-rouge">constants</code> for a particular type $\mathcal{C}_{k}$.  In this case <em>lang</em> represents a marginalisation of all constants of type $\mathcal{C}_{lang}$ and $\textit{slug}$ represents a marginalisation of all constants of type $\mathcal{C}_{slug}$.  Resolvers provide a means of finding the set of <code class="language-plaintext highlighter-rouge">constants</code> $c_{k}$ for a type $\mathcal{C}_{k}$ when $c_{k}$ is a <em>free variable</em>.</p>

<h3 id="constructing-the-bound-expression-set---resolvers">Constructing the Bound Expression Set - Resolvers</h3>
<p>A resolver function $r$ is a function which takes a context $c_{k}$ and returns the set of all possible <strong>bound</strong> values $\mathcal{C}_{k}$.  This is required when the value $c_{k}$  has been marginalised by a free variable.</p>

\[\begin{equation*}
r(c_{k}) = \mathcal{C}_{k}
\end{equation*}\]

<p>To convert the partial expression set</p>

\[\begin{eqnarray*}
(\lambda n_{1}. \lambda n_{2}. \lambda n_3. n_{1}n_{2}n_{3})	c_{1}c_{2}c_{3}
\end{eqnarray*}\]

<p>where $c_{1}=\textit{lang}$, $c_{2} \in \{ \texttt{slots}, \varnothing \}$ and $c_{3}=\textit{slug}$, 
we need to resolve context $c_{1}$ and $c_{3}$ through the resolvers $r(c_{1})$ and $r(c_{3})$  to obtain the bound values for types $\mathcal{C}_{lang}$ and $\mathcal{C}_{slug}$ respectively. Using the CMS one can implemented $r(c_{1})$ by retrieving the set of all supported languages and $r(c_{3})$ by enumerating all games supported by the system.    For our example we will assume that the set $\mathcal{C}_{lang}$ and $\mathcal{C}_{slug}$ are</p>

\[\begin{eqnarray*}
&amp;\mathcal{C}_{lang} = r(\textit{lang}) = \{ \texttt{en}, \texttt{fi}, \varnothing \}\\
&amp;\mathcal{C}_{slug} = r(\textit{slug}) = \{ \texttt{gonzo}, \texttt{starburst}, \varnothing \}
\end{eqnarray*}\]

<p>Substituting $\textit{lang}$ and $\textit{slug}$ with the set of bound variables $\mathcal{C}_{lang}$ and $\mathcal{C}_{slug}$</p>

\[\begin{eqnarray*}
&amp;(\lambda n_1.\lambda n_2.\lambda n_3\cdot n_1n_2n_3)c_1 c_2 c_3\\
&amp;\textrm{where}\\
&amp;c_1 \in \{ \texttt{en, fi, }\varnothing \}\\
&amp;c_2 \in \{ \texttt{slots, }\varnothing \}\\
&amp;c_3 \in \{ \texttt{gonzo, starburst, }\varnothing \}\\
\end{eqnarray*}\]

<p>results in the bound expression set $\mathcal{RS}$.</p>

<p><img class="step minimal" style="width: 700px" src="/images/lambda/13.png" /></p>

<p>We omitted $\varnothing$ for simplicity but there exist expression tree including $\varnothing$ in the expression set $\mathcal{RS}$ namely:</p>

\[\begin{eqnarray*} 
&amp;\psi(\omega(\varnothing\ \varnothing\ \varnothing)) \\
&amp;\psi(\omega(\texttt{en}\ \varnothing\ \varnothing)) \\
&amp;\psi(\omega(\texttt{fi}\ \varnothing\ \varnothing)) \\
&amp;\psi(\omega(\texttt{en}\ \texttt{slots}\ \varnothing)) \\
&amp;\psi(\omega(\texttt{fi}\ \texttt{slots}\ \varnothing))
\end{eqnarray*}\]

<h1 id="99-problems-sitemap-and-alternates-aint-one">99 Problems! Sitemap and Alternates ain’t one!</h1>
<p>Having constructed the bound expression set we will now tackle the problem of serialising the complete sitemap and the problem of finding a list of alternate URLs from any given URL.</p>

<h2 id="getting-all-the-paths-of-the-site-for-sitemap">Getting all the paths of the site for sitemap</h2>
<p>Having constructed the bound expression set we can obtain the set of URLs by  passing each normalised expression through an internationalisation serialisation function $f_{int}$.  For visualisation purposes, we shall display the serialised form after passing it through the serialisation function handling internationalisation $f_{int}$ below the node.  Due to space limitations, we shall omit drawing the $\varnothing$ nodes.</p>

<p><img class="step minimal" style="width: 750px" src="/images/lambda/14.png" /></p>

<p>Since some paths might not be desired in the final list of URLs (sitemap) we will filter some deserialised URLs by passing them through a predicate $p$. Such a predicate needs to be based on the value of the variable $c_{k}$ present in the context.  As an example the predicate $p(c) \rightarrow c_{1} \ne \texttt{en}$ will filter the serialised set</p>

<blockquote>
  <p>As an implementation detail the CMS should include a flag on each sitemap and game element to indicate whether such an element is to be included in the sitemap. Such a flag needs to be encoded in a variable $c_{k}$ within the context.</p>
</blockquote>

\[\begin{eqnarray*}
&amp;\{ \texttt{/en/slots/gonzo/}, \\
&amp;	\texttt{/en/slots/starburst/}, \\
&amp;	\texttt{/fi/kolikkopelit/gonzofi/}, \\ 
&amp;	\texttt{/fi/kolikkopelit/starburstfi/} \}
\end{eqnarray*}\]

<p>to</p>

\[\begin{eqnarray*}
&amp;\{\texttt{/fi/kolikkopelit/gonzofi/}, \\
&amp;	\texttt{/fi/kolikkopelit/starburstfi/} \}
\end{eqnarray*}\]

<h2 id="getting-alternate-paths">Getting alternate paths</h2>
<p>Given a bound expression set $\mathcal{RS}$ how does one find all alternate URLs from a source URL?  This problem can be solved by using the search functionality discussed in Section <a href="#search">search</a> .  In essence we want to search the bound expression set $\mathcal{RS}$ using the normalised expression tree deserialised from the source URL.  Since the language is not important the context $c_{1}$ - representing the language - will be marginalised in the search expression tree.</p>

<p>As an example, let us assume that a client requested the page <code class="language-plaintext highlighter-rouge">/fi/kolikkopelit/gonzofi/</code> annotated with $^\dagger$ below.</p>

<p><img class="step minimal" style="width: 750px" src="/images/lambda/15.png" /></p>

<p>We can find the original normalised expression which serialised to $\texttt{/fi/kolikkopelit/gonzofi/}$ by using the inverse function $\bar{f_{int}}$</p>

\[\begin{equation*}
\bar{f_{int}}(/fi/kolikkopelit/gonzofi/) = \texttt{fi slots gonzo} 
\end{equation*}\]

<p>We convert the normalised expression $\texttt{fi slots gonzo}$ to the expression tree - $\psi(\omega(\texttt{fi slots gonzo}))$ - by using the $\omega$ function and work through the $\beta$-reductions.  To search for similar expression trees which vary only in language we marginalise the language context by introducing a $\textit{free}$ variable $\ast$.  We can obtain the set of alternate expression trees by applying</p>

\[\begin{eqnarray*}
\mathcal{RS}_{alternates}&amp;=&amp;search(\mathcal{RS}, \psi(\omega(\ast\ \texttt{slots gonzo}))\\
&amp;=&amp;\{\psi(\omega(\texttt{fi slots gonzo})), \psi(\omega(\texttt{en slots gonzo}))\}
\end{eqnarray*}\]

<p>The expression set $\mathcal{RS}_{alternates}$ is then serialised using $f_{int}$ to obtain the set of alternate URLs</p>

\[\begin{eqnarray*}
f_{int}(\texttt{en slots gonzo})&amp;=&amp;\texttt{/en/slots/gonzo/}\\
f_{int}(\texttt{fi slots gonzo})&amp;=&amp;\texttt{/fi/kolikkopelit/gonzofi/}
\end{eqnarray*}\]

<p>We will use the filter function $p(c) \rightarrow c_{1}\ne \texttt{en} \wedge c_{2} \ne \texttt{slots} \wedge c_{3} \ne \texttt{gonzo} $ to filter out the original URL.</p>

<h1 id="conclusion">Conclusion</h1>
<p>In this post we have defined a model using $\lambda$-calculus which can be applied to common SEO problems namely the problem of retrieving all site URLs and the problem of retrieving all alternate URLs. Hopefully you find these ideas interesting! Stay safe and keep hacking!</p>]]></content><author><name>Mark Galea</name></author><summary type="html"><![CDATA[Introduced by Alonzo Church in the 1930s, $\lambda$-calculus can be considered as the smallest computation programming language of the world. Reading through the various tutorials one can find various examples which showcase its universality; addition, conditional operators, equality and inequality and recursion. One thing which always intrigued me is how applicable is $\lambda$-calculus to everyday problems such as finding the set of URLs in a sitemap or a set of alternate language urls? The question is obviously rhetorical since we know that $\lambda$-calculus is Turing complete! Can we model a “modern” problem in terms of $\lambda$-calculus and will such a problem still feel natural? The answer is yes! In this post we are going to apply $\lambda$-calculus in an SEO domain, specifically to construct a Sitemap and to find the hreflang for a language.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://cloudmark.github.io/images/lambda/haskell.png" /><media:content medium="image" url="http://cloudmark.github.io/images/lambda/haskell.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">An efficient headless CMS on top of Wordpress - a.k.a the ACF Compiler!</title><link href="http://cloudmark.github.io/ACF-Fields/" rel="alternate" type="text/html" title="An efficient headless CMS on top of Wordpress - a.k.a the ACF Compiler!" /><published>2017-12-13T00:00:00+00:00</published><updated>2017-12-13T00:00:00+00:00</updated><id>http://cloudmark.github.io/ACF-Fields</id><content type="html" xml:base="http://cloudmark.github.io/ACF-Fields/"><![CDATA[<p><img class="title" src="/images/acf/acf.png" /> Headless CMSs are becoming quite popular and make up one of the important ingredients of a <a href="https://headlesscms.org/">JAMstack site</a>. At <a href="http://www.suprnation.io/">SuprNation</a> we have been tinkering with headless CMSs for quite a while and we have succesfully implemented one using <a href="https://wordpress.org/">Wordpress</a> (WP), <a href="https://www.advancedcustomfields.com/">Advanced Custom Fields</a> (ACF) and <a href="https://wordpress.org/plugins/acf-to-rest-api/">ACF-to-Rest</a> API in one of our experiments.  This trio can be used to implement a cheap and flexible headless CMS but as anyone who has worked with ACF knows, retrieving the underlying data can be slow if one relies on the current WP plugins. In this post I am going to describe how we have overcome this problem and introduce our <a href="https://github.com/suprnation/wordpress-acf">open source</a> initiative that drastically reduces the number of queries and round trips to the database.</p>

<h1 id="introduction">Introduction</h1>
<p>ACF together with WP custom types and ACF-to-Rest can provide the basis for a great headless CMS however due to the way ACF stores the data in the <code class="language-plaintext highlighter-rouge">wp_postmeta</code> and due to the API design of ACF (and ACF-to-Rest) this approach tends to be quite expensive.</p>

<p>In order to understand the problem, let us create an object hierarchy using Person, Address and Pet types (:cat::dog::mouse::hamster::rabbit::wolf::frog::tiger::koala::bear:). A Person will have a one-to-one relationship (Post-Object) with an Address and a one-to-many relationship (Relationship) with a Pet as illustrated below:</p>

<p><img class="center" src="/images/acf/hierarchy.png" /></p>

<p>In ACF we can add properties to types by associating a custom field group with each related custom type i.e. Person, Address and Pet.  <em>To create the Person, Address and Pet custom type one can use the <a href="https://wordpress.org/plugins/custom-post-type-ui/">custom-post-type-ui</a> plugin or define these programatically</em>.  Let’s start by defining the Pet Field Group</p>

<table>
  <thead>
    <tr>
      <th>Field Name</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">pet_name</code></td>
      <td>The name of the pet. Type: <code class="language-plaintext highlighter-rouge">Text</code>.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">pet_age</code></td>
      <td>The age of the pet.  Type: <code class="language-plaintext highlighter-rouge">Number</code>.</td>
    </tr>
  </tbody>
</table>

<p>and the Address Field Group</p>

<table>
  <thead>
    <tr>
      <th>Field Name</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">address_line_1</code></td>
      <td>The address first line. Type <code class="language-plaintext highlighter-rouge">Text</code>.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">address_line_2</code></td>
      <td>The address second line. Type <code class="language-plaintext highlighter-rouge">Text</code>.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">address_town</code></td>
      <td>The address town. Type <code class="language-plaintext highlighter-rouge">Text</code>.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">address_country</code></td>
      <td>The address country. Type <code class="language-plaintext highlighter-rouge">Text</code>.</td>
    </tr>
  </tbody>
</table>

<p>Finally, let’s define the Person Field Group</p>

<table>
  <thead>
    <tr>
      <th>Field Name</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">person_name</code></td>
      <td>The name of the person.  Type: <code class="language-plaintext highlighter-rouge">Text</code>.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">person_surname</code></td>
      <td>The surname of the person  Type: <code class="language-plaintext highlighter-rouge">Text</code>.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">person_address</code></td>
      <td>The address of the person.  Type: <code class="language-plaintext highlighter-rouge">Post Object</code> of type <code class="language-plaintext highlighter-rouge">address</code>.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">person_pets</code></td>
      <td>The list of pets.  Type: <code class="language-plaintext highlighter-rouge">Relationship</code> of type <code class="language-plaintext highlighter-rouge">pet</code>.</td>
    </tr>
  </tbody>
</table>

<h2 id="data-creation">Data Creation</h2>
<p>Having modelled our types using custom post types and ACF fields, let us create a small data set of 5 posts: 3 Pets, 1 Address and 1 Person so that we can understand the inefficiencies.</p>

<p>Our 3 Pets will be</p>

<table>
  <thead>
    <tr>
      <th style="text-align: center"><code class="language-plaintext highlighter-rouge">pet_name</code></th>
      <th style="text-align: center"><code class="language-plaintext highlighter-rouge">pet_age</code></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center">Muccu</td>
      <td style="text-align: center">4</td>
    </tr>
    <tr>
      <td style="text-align: center">Puccu</td>
      <td style="text-align: center">2</td>
    </tr>
    <tr>
      <td style="text-align: center">Tuccu</td>
      <td style="text-align: center">1</td>
    </tr>
  </tbody>
</table>

<p>Our person, Mark, will live in a newly renovated area in Mars</p>

<table>
  <thead>
    <tr>
      <th><code class="language-plaintext highlighter-rouge">field_name</code></th>
      <th><code class="language-plaintext highlighter-rouge">value</code></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>address_line_1</td>
      <td>23, Mawrth Vallis Street</td>
    </tr>
    <tr>
      <td>address_line_2</td>
      <td>N/A</td>
    </tr>
    <tr>
      <td>address_town</td>
      <td>Viking 1</td>
    </tr>
    <tr>
      <td>address_country</td>
      <td>Mars</td>
    </tr>
  </tbody>
</table>

<p>and Mark will have Muccu, Puccu and Tuccu keeping him company</p>

<table>
  <thead>
    <tr>
      <th><code class="language-plaintext highlighter-rouge">fieldname</code></th>
      <th><code class="language-plaintext highlighter-rouge">value</code></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">person_name</code></td>
      <td>Mark</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">person_surname</code></td>
      <td>Galea</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">person_address</code></td>
      <td><em>Previous Address</em></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">person_pets</code></td>
      <td>Muccu, Puccu and Tuccu</td>
    </tr>
  </tbody>
</table>

<p>If you have created the data successfully the post Mark should look as follows:</p>

<p><img class="step" src="/images/acf/wordpress.png" /></p>

<h2 id="data-retrieval---the-n1-resource-problem">Data Retrieval - The n+1 resource problem</h2>
<p>Now that we have modelled our data and created our one person dataset (we went a bit overboard!), let’s install the <a href="https://wordpress.org/plugins/acf-to-rest-api/">acf-to-rest</a> API to retrieve this (awesome, great, adorable.. ok I’ll stop!) person.  Once the plugin is installed, we can retrieve all person data by accessing the endpoint <code class="language-plaintext highlighter-rouge">http://&lt;base-url&gt;/wp-json/acf/v3/person</code>.</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="w">
  </span><span class="p">{</span><span class="w">
    </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">16</span><span class="p">,</span><span class="w">
    </span><span class="nl">"acf"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"person_name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Mark"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"person_surname"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Galea"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"person_address"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"ID"</span><span class="p">:</span><span class="w"> </span><span class="mi">15</span><span class="p">,</span><span class="w">
        </span><span class="nl">"post_author"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"post_content"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="p">,</span><span class="w">
        </span><span class="nl">"post_title"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Mark's Address"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"post_excerpt"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="w">
      </span><span class="p">},</span><span class="w">
      </span><span class="nl">"person_pets"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
          </span><span class="nl">"ID"</span><span class="p">:</span><span class="w"> </span><span class="mi">11</span><span class="p">,</span><span class="w">
          </span><span class="nl">"post_author"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"post_content"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="p">,</span><span class="w">
          </span><span class="nl">"post_title"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Muccu"</span><span class="w">
        </span><span class="p">},</span><span class="w">
        </span><span class="p">{</span><span class="w">
          </span><span class="nl">"ID"</span><span class="p">:</span><span class="w"> </span><span class="mi">12</span><span class="p">,</span><span class="w">
          </span><span class="nl">"post_author"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"post_content"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="p">,</span><span class="w">
          </span><span class="nl">"post_title"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Puccu"</span><span class="w">
        </span><span class="p">},</span><span class="w">
        </span><span class="p">{</span><span class="w">
          </span><span class="nl">"ID"</span><span class="p">:</span><span class="w"> </span><span class="mi">13</span><span class="p">,</span><span class="w">
          </span><span class="nl">"post_author"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"post_content"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="p">,</span><span class="w">
          </span><span class="nl">"post_title"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Tuccu"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">]</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">]</span><span class="w">
</span></code></pre></div></div>

<p>From the data we can observe that <strong>only the first level objects</strong> are resolved.  To <strong>fully resolve</strong> the object graph, one would need to perform additional HTTP calls for each pet</p>

<ul>
  <li>http://<base-url>/wp-json/acf/v3/pet/11</base-url></li>
  <li>http://<base-url>/wp-json/acf/v3/pet/12</base-url></li>
  <li>http://<base-url>/wp-json/acf/v3/pet/13</base-url></li>
</ul>

<p>and address</p>

<ul>
  <li>http://<base-url>/wp-json/acf/v3/address/15</base-url></li>
</ul>

<p>Ok, you get the idea. This is quite inefficient! There must be another way!</p>

<p>Well it turns out that retrieving additional data by querying additional resource endpoints is not uncommon in the headless CMSs universe.  In fact, most pricing models use this to their advantage.  Apart from the price implications, such back and forth chatter imposes limits: limits on the number of data elements we can show to a user at once (no user will wait ad-infinitum) and limits in our modelling capabilities (we start flattening relationships to reduce API calls and costs).</p>

<h1 id="data-retrieval---a-tale-of-multiple-woes-part-2">Data Retrieval - A tale of multiple woes (Part 2)</h1>
<p>In the previous section we have outlined <em>the n+1 resource problem</em> but there is more… not in a Steve Jobs way.   Each relationship in our object graph comes with an expensive query cost which grows linearly with the number of results.  In order to understand the costs let us analyse the query log associated with retrieving all posts of type <code class="language-plaintext highlighter-rouge">Person</code>.  The query log which we will analyse is the following:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="n">SQL_CALC_FOUND_ROWS</span>  <span class="n">wp_posts</span><span class="p">.</span><span class="n">ID</span> <span class="k">FROM</span> <span class="n">wp_posts</span>  <span class="k">WHERE</span> <span class="mi">1</span><span class="o">=</span><span class="mi">1</span>  <span class="k">AND</span> <span class="n">wp_posts</span><span class="p">.</span><span class="n">post_type</span> <span class="o">=</span> <span class="s1">'person'</span> <span class="k">AND</span> <span class="p">(</span><span class="n">wp_posts</span><span class="p">.</span><span class="n">post_status</span> <span class="o">=</span> <span class="s1">'publish'</span><span class="p">)</span>  <span class="k">ORDER</span> <span class="k">BY</span> <span class="n">wp_posts</span><span class="p">.</span><span class="n">ID</span> <span class="k">DESC</span> <span class="k">LIMIT</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">10</span>
<span class="k">SELECT</span> <span class="n">FOUND_ROWS</span><span class="p">()</span>
<span class="k">SELECT</span> <span class="n">wp_posts</span><span class="p">.</span><span class="o">*</span> <span class="k">FROM</span> <span class="n">wp_posts</span> <span class="k">WHERE</span> <span class="n">ID</span> <span class="k">IN</span> <span class="p">(</span><span class="mi">16</span><span class="p">)</span>
<span class="k">SELECT</span> <span class="n">post_id</span><span class="p">,</span> <span class="n">meta_key</span><span class="p">,</span> <span class="n">meta_value</span> <span class="k">FROM</span> <span class="n">wp_postmeta</span> <span class="k">WHERE</span> <span class="n">post_id</span> <span class="k">IN</span> <span class="p">(</span><span class="mi">16</span><span class="p">)</span> <span class="k">ORDER</span> <span class="k">BY</span> <span class="n">meta_id</span> <span class="k">ASC</span>
<span class="k">SELECT</span> <span class="n">meta_value</span> <span class="k">FROM</span> <span class="n">wp_postmeta</span> <span class="k">WHERE</span> <span class="n">post_id</span> <span class="o">=</span> <span class="mi">16</span> <span class="k">and</span> <span class="n">meta_key</span> <span class="k">LIKE</span> <span class="s1">'_%'</span> <span class="k">AND</span> <span class="n">meta_value</span> <span class="k">LIKE</span> <span class="s1">'field_%'</span>
<span class="k">SELECT</span> <span class="n">post_id</span><span class="p">,</span> <span class="n">meta_value</span> <span class="k">FROM</span> <span class="n">wp_postmeta</span> <span class="k">WHERE</span> <span class="n">meta_key</span> <span class="o">=</span> <span class="s1">'field_59e4ace78916b'</span>
<span class="k">SELECT</span> <span class="o">*</span> <span class="k">FROM</span> <span class="n">wp_posts</span> <span class="k">WHERE</span> <span class="n">ID</span> <span class="o">=</span> <span class="mi">10</span> <span class="k">LIMIT</span> <span class="mi">1</span>
<span class="k">SELECT</span> <span class="n">post_id</span><span class="p">,</span> <span class="n">meta_value</span> <span class="k">FROM</span> <span class="n">wp_postmeta</span> <span class="k">WHERE</span> <span class="n">meta_key</span> <span class="o">=</span> <span class="s1">'field_59e4add78916c'</span>
<span class="k">SELECT</span> <span class="n">post_id</span><span class="p">,</span> <span class="n">meta_value</span> <span class="k">FROM</span> <span class="n">wp_postmeta</span> <span class="k">WHERE</span> <span class="n">meta_key</span> <span class="o">=</span> <span class="s1">'field_59e4ade58916d'</span>
<span class="k">SELECT</span> <span class="o">*</span> <span class="k">FROM</span> <span class="n">wp_posts</span> <span class="k">WHERE</span> <span class="n">ID</span> <span class="o">=</span> <span class="mi">15</span> <span class="k">LIMIT</span> <span class="mi">1</span>
<span class="k">SELECT</span> <span class="n">post_id</span><span class="p">,</span> <span class="n">meta_value</span> <span class="k">FROM</span> <span class="n">wp_postmeta</span> <span class="k">WHERE</span> <span class="n">meta_key</span> <span class="o">=</span> <span class="s1">'field_59e4ae348916e'</span>
<span class="k">SELECT</span>   <span class="n">wp_posts</span><span class="p">.</span><span class="o">*</span> <span class="k">FROM</span> <span class="n">wp_posts</span>  <span class="k">WHERE</span> <span class="mi">1</span><span class="o">=</span><span class="mi">1</span>  <span class="k">AND</span> <span class="n">wp_posts</span><span class="p">.</span><span class="n">ID</span> <span class="k">IN</span> <span class="p">(</span><span class="mi">11</span><span class="p">,</span><span class="mi">12</span><span class="p">,</span><span class="mi">13</span><span class="p">)</span> <span class="k">AND</span> <span class="n">wp_posts</span><span class="p">.</span><span class="n">post_type</span> <span class="k">IN</span> <span class="p">(</span><span class="s1">'post'</span><span class="p">,</span> <span class="s1">'page'</span><span class="p">,</span> <span class="s1">'attachment'</span><span class="p">,</span> <span class="s1">'custom_css'</span><span class="p">,</span> <span class="s1">'customize_changeset'</span><span class="p">,</span> <span class="s1">'person'</span><span class="p">,</span> <span class="s1">'address'</span><span class="p">,</span> <span class="s1">'pet'</span><span class="p">)</span> <span class="k">AND</span> <span class="p">((</span><span class="n">wp_posts</span><span class="p">.</span><span class="n">post_status</span> <span class="o">&lt;&gt;</span> <span class="s1">'trash'</span> <span class="k">AND</span> <span class="n">wp_posts</span><span class="p">.</span><span class="n">post_status</span> <span class="o">&lt;&gt;</span> <span class="s1">'auto-draft'</span><span class="p">))</span>  <span class="k">ORDER</span> <span class="k">BY</span> <span class="n">wp_posts</span><span class="p">.</span><span class="n">post_date</span> <span class="k">DESC</span>
<span class="k">SELECT</span>  <span class="n">t</span><span class="p">.</span><span class="o">*</span><span class="p">,</span> <span class="n">tt</span><span class="p">.</span><span class="o">*</span><span class="p">,</span> <span class="n">tr</span><span class="p">.</span><span class="n">object_id</span> <span class="k">FROM</span> <span class="n">wp_terms</span> <span class="k">AS</span> <span class="n">t</span>  <span class="k">INNER</span> <span class="k">JOIN</span> <span class="n">wp_term_taxonomy</span> <span class="k">AS</span> <span class="n">tt</span> <span class="k">ON</span> <span class="n">t</span><span class="p">.</span><span class="n">term_id</span> <span class="o">=</span> <span class="n">tt</span><span class="p">.</span><span class="n">term_id</span> <span class="k">INNER</span> <span class="k">JOIN</span> <span class="n">wp_term_relationships</span> <span class="k">AS</span> <span class="n">tr</span> <span class="k">ON</span> <span class="n">tr</span><span class="p">.</span><span class="n">term_taxonomy_id</span> <span class="o">=</span> <span class="n">tt</span><span class="p">.</span><span class="n">term_taxonomy_id</span> <span class="k">WHERE</span> <span class="n">tt</span><span class="p">.</span><span class="n">taxonomy</span> <span class="k">IN</span> <span class="p">(</span><span class="s1">'category'</span><span class="p">,</span> <span class="s1">'post_tag'</span><span class="p">,</span> <span class="s1">'post_format'</span><span class="p">)</span> <span class="k">AND</span> <span class="n">tr</span><span class="p">.</span><span class="n">object_id</span> <span class="k">IN</span> <span class="p">(</span><span class="mi">13</span><span class="p">,</span> <span class="mi">12</span><span class="p">,</span> <span class="mi">11</span><span class="p">)</span> <span class="k">ORDER</span> <span class="k">BY</span> <span class="n">t</span><span class="p">.</span><span class="n">name</span> <span class="k">ASC</span>
<span class="k">SELECT</span> <span class="n">post_id</span><span class="p">,</span> <span class="n">meta_key</span><span class="p">,</span> <span class="n">meta_value</span> <span class="k">FROM</span> <span class="n">wp_postmeta</span> <span class="k">WHERE</span> <span class="n">post_id</span> <span class="k">IN</span> <span class="p">(</span><span class="mi">13</span><span class="p">,</span><span class="mi">12</span><span class="p">,</span><span class="mi">11</span><span class="p">)</span> <span class="k">ORDER</span> <span class="k">BY</span> <span class="n">meta_id</span> <span class="k">ASC</span>
</code></pre></div></div>

<p>When a call is made to the <em>ACF-to-Rest</em> <em>person</em> endpoint (<code class="language-plaintext highlighter-rouge">http://&lt;base-url&gt;/wp-json/acf/v3/person</code>), a database query is performed to retrieve all post types of <code class="language-plaintext highlighter-rouge">post_type=person</code> from the <code class="language-plaintext highlighter-rouge">wp_posts</code> table.</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="n">SQL_CALC_FOUND_ROWS</span>  <span class="n">wp_posts</span><span class="p">.</span><span class="n">ID</span> 
    <span class="k">FROM</span> <span class="n">wp_posts</span> 
        <span class="k">WHERE</span> <span class="mi">1</span><span class="o">=</span><span class="mi">1</span>  
        <span class="k">AND</span> <span class="n">wp_posts</span><span class="p">.</span><span class="n">post_type</span> <span class="o">=</span> <span class="s1">'person'</span> 
        <span class="k">AND</span> <span class="p">(</span><span class="n">wp_posts</span><span class="p">.</span><span class="n">post_status</span> <span class="o">=</span> <span class="s1">'publish'</span><span class="p">)</span>  
        <span class="k">ORDER</span> <span class="k">BY</span> <span class="n">wp_posts</span><span class="p">.</span><span class="n">ID</span> <span class="k">DESC</span> <span class="k">LIMIT</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">10</span>
<span class="k">SELECT</span> <span class="n">wp_posts</span><span class="p">.</span><span class="o">*</span> 
    <span class="k">FROM</span> <span class="n">wp_posts</span> 
        <span class="k">WHERE</span> <span class="n">ID</span> <span class="k">IN</span> <span class="p">(</span><span class="mi">16</span><span class="p">)</span>
</code></pre></div></div>

<p>Once the list of post IDs are determined - in this case the Person with ID=16 - all ACF custom fields are retrieved by querying the <code class="language-plaintext highlighter-rouge">wp_postmeta</code> table.  The query</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="n">post_id</span><span class="p">,</span> <span class="n">meta_key</span><span class="p">,</span> <span class="n">meta_value</span> 
    <span class="k">FROM</span> <span class="n">wp_postmeta</span> 
    <span class="k">WHERE</span> <span class="n">post_id</span> <span class="k">IN</span> <span class="p">(</span><span class="mi">16</span><span class="p">)</span> 
    <span class="k">ORDER</span> <span class="k">BY</span> <span class="n">meta_id</span> <span class="k">ASC</span>
</code></pre></div></div>

<p>will retrieve the following ACF field values and metadata links:</p>

<table>
  <thead>
    <tr>
      <th style="text-align: center">PostId</th>
      <th style="text-align: left">Meta Key</th>
      <th style="text-align: left">Meta Value</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center">16</td>
      <td style="text-align: left">_edit_last</td>
      <td style="text-align: left">1</td>
    </tr>
    <tr>
      <td style="text-align: center">16</td>
      <td style="text-align: left">_edit_lock</td>
      <td style="text-align: left">1508161108:1</td>
    </tr>
    <tr>
      <td style="text-align: center">16</td>
      <td style="text-align: left">person_name</td>
      <td style="text-align: left">Mark</td>
    </tr>
    <tr>
      <td style="text-align: center">16</td>
      <td style="text-align: left">_person_name</td>
      <td style="text-align: left">field_59e4ace78916b</td>
    </tr>
    <tr>
      <td style="text-align: center">16</td>
      <td style="text-align: left">person_surname</td>
      <td style="text-align: left">Galea</td>
    </tr>
    <tr>
      <td style="text-align: center">16</td>
      <td style="text-align: left">_person_surname</td>
      <td style="text-align: left">field_59e4add78916c</td>
    </tr>
    <tr>
      <td style="text-align: center">16</td>
      <td style="text-align: left">person_address</td>
      <td style="text-align: left">15</td>
    </tr>
    <tr>
      <td style="text-align: center">16</td>
      <td style="text-align: left">_person_address</td>
      <td style="text-align: left">field_59e4ade58916d</td>
    </tr>
    <tr>
      <td style="text-align: center">16</td>
      <td style="text-align: left">person_pets</td>
      <td style="text-align: left">a:3:{i:0;s:2:”11”;i:1;s:2:”12”;i:2;s:2:”13”;}</td>
    </tr>
    <tr>
      <td style="text-align: center">16</td>
      <td style="text-align: left">_person_pets</td>
      <td style="text-align: left">field_59e4ae348916e</td>
    </tr>
  </tbody>
</table>

<p>Analysing the retrieved rows we note that</p>
<ul>
  <li>ACF Post Objects (one-to-one) store the referencing post ID in the <code class="language-plaintext highlighter-rouge">meta_value</code>.  E.g. <code class="language-plaintext highlighter-rouge">person_address</code> refers to the post with ID 15.</li>
  <li>ACF Relationships (one-to-many) store a serialised array of post IDs. E.g. <code class="language-plaintext highlighter-rouge">person_pets</code> are stored in the serialised array <code class="language-plaintext highlighter-rouge">a:3:{i:0;s:2:"11";i:1;s:2:"12";i:2;s:2:"13";}</code>; the associated pets can be retrieved by retrieving posts with IDs <code class="language-plaintext highlighter-rouge">11</code>, <code class="language-plaintext highlighter-rouge">12</code> and <code class="language-plaintext highlighter-rouge">13</code>.</li>
  <li>Normal fields encode their values as text and may require conversion. E.g. the value of <code class="language-plaintext highlighter-rouge">person_name</code> does not need any conversions.</li>
</ul>

<p>The semantics of what the values represent are based on our knowledge that <code class="language-plaintext highlighter-rouge">person_address</code> is a <code class="language-plaintext highlighter-rouge">PostObject</code>, <code class="language-plaintext highlighter-rouge">person_pet</code> is a <code class="language-plaintext highlighter-rouge">Relationship</code> and that <code class="language-plaintext highlighter-rouge">person_name</code> and <code class="language-plaintext highlighter-rouge">person_surname</code> are of type <code class="language-plaintext highlighter-rouge">text</code> (String).   <em>ACF-to-Rest</em> needs to determine this information and thus needs to store this information in <code class="language-plaintext highlighter-rouge">wp_postmeta</code> table.  ACF stores two key entries for each ACF field; <code class="language-plaintext highlighter-rouge">&lt;acf_field&gt;</code> and <code class="language-plaintext highlighter-rouge">_&lt;acf_field&gt;</code> (e.g. <code class="language-plaintext highlighter-rouge">person_name</code> and <code class="language-plaintext highlighter-rouge">_person_name</code>) in order to be able to retrieve the type metadata and value.  The meta value stored under the meta key <code class="language-plaintext highlighter-rouge">&lt;acf_field&gt;</code> contains the encoded field value while the meta value stored under the meta key <code class="language-plaintext highlighter-rouge">_&lt;acf_field&gt;</code> contains a link to the value’s type metadata (or loosely a pointer to its type).</p>

<p>Retrieving type metadata is critical to interpret values correctly and <em>ACF-to-Rest</em> will perform a series of queries to obtain such type information.  First <em>ACF-to-Rest</em> queries all field metadata to find all type metadata links</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="n">meta_value</span> 
    <span class="k">FROM</span> <span class="n">wp_postmeta</span> 
    <span class="k">WHERE</span> <span class="n">post_id</span> <span class="o">=</span> <span class="mi">16</span> 
    <span class="k">AND</span> <span class="n">meta_key</span> <span class="k">LIKE</span> <span class="s1">'_%'</span> 
    <span class="k">AND</span> <span class="n">meta_value</span> <span class="k">LIKE</span> <span class="s1">'field_%'</span>
</code></pre></div></div>

<p>then, using the result set</p>

<table>
  <thead>
    <tr>
      <th style="text-align: center">Meta Value</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center">field_59e4ace78916b</td>
    </tr>
    <tr>
      <td style="text-align: center">field_59e4add78916c</td>
    </tr>
    <tr>
      <td style="text-align: center">field_59e4ade58916d</td>
    </tr>
    <tr>
      <td style="text-align: center">field_59e4ae348916e</td>
    </tr>
  </tbody>
</table>

<p><em>ACF-to-Rest</em> retrieves the type metadata by issuing a separate query for each <code class="language-plaintext highlighter-rouge">meta_value</code></p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="n">post_id</span><span class="p">,</span> <span class="n">meta_value</span> <span class="k">FROM</span> <span class="n">wp_postmeta</span> <span class="k">WHERE</span> <span class="n">meta_key</span> <span class="o">=</span> <span class="s1">'field_59e4ace78916b'</span>
<span class="k">SELECT</span> <span class="n">post_id</span><span class="p">,</span> <span class="n">meta_value</span> <span class="k">FROM</span> <span class="n">wp_postmeta</span> <span class="k">WHERE</span> <span class="n">meta_key</span> <span class="o">=</span> <span class="s1">'field_59e4add78916c'</span>
<span class="k">SELECT</span> <span class="n">post_id</span><span class="p">,</span> <span class="n">meta_value</span> <span class="k">FROM</span> <span class="n">wp_postmeta</span> <span class="k">WHERE</span> <span class="n">meta_key</span> <span class="o">=</span> <span class="s1">'field_59e4ade58916d'</span>
<span class="k">SELECT</span> <span class="n">post_id</span><span class="p">,</span> <span class="n">meta_value</span> <span class="k">FROM</span> <span class="n">wp_postmeta</span> <span class="k">WHERE</span> <span class="n">meta_key</span> <span class="o">=</span> <span class="s1">'field_59e4ae348916e'</span>
</code></pre></div></div>

<p>In the query above, the <code class="language-plaintext highlighter-rouge">meta_value</code> corresponding to the <code class="language-plaintext highlighter-rouge">meta_key = field_59e4ace78916b</code> is</p>

<table>
  <thead>
    <tr>
      <th style="text-align: center">Post Id</th>
      <th style="text-align: center">Meta Value</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center">10</td>
      <td style="text-align: center">a:16:{s:4:”type”;s:4:”text”s:3:”key”;s:19:”field_59e4ace78916b”;…}</td>
    </tr>
  </tbody>
</table>

<p>From this <code class="language-plaintext highlighter-rouge">meta_value</code> ACF can determine that the type is <code class="language-plaintext highlighter-rouge">text</code>.  Since <code class="language-plaintext highlighter-rouge">person_name</code> is related to <code class="language-plaintext highlighter-rouge">_person_name</code> which links to <code class="language-plaintext highlighter-rouge">field_59e4ace78916b</code> and since <code class="language-plaintext highlighter-rouge">field_59e4ace78916b</code> is of type <code class="language-plaintext highlighter-rouge">text</code>, <em>ACF-to-Rest</em> can determine that the value <code class="language-plaintext highlighter-rouge">Mark</code> is of type <code class="language-plaintext highlighter-rouge">text</code> and hence needs no further conversions.</p>

<p>Having retrieved the type metadata and the values, <em>ACF-to-Rest</em> will fire a set of queries to perform some sanity checks.  First it will query all metadata links to make sure that they are of type <code class="language-plaintext highlighter-rouge">acf</code>.  E.g. <code class="language-plaintext highlighter-rouge">field_59e4ace78916b</code> is linked to Post ID <code class="language-plaintext highlighter-rouge">10</code> so <em>ACF-to-Rest</em> will issue a query to retrieve Post ID 10 in order to make sure that the <code class="language-plaintext highlighter-rouge">post_type</code> is indeed <code class="language-plaintext highlighter-rouge">acf</code>.</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="o">*</span> <span class="k">FROM</span> <span class="n">wp_posts</span> <span class="k">WHERE</span> <span class="n">ID</span> <span class="o">=</span> <span class="mi">10</span> <span class="k">LIMIT</span> <span class="mi">1</span>
</code></pre></div></div>

<p>Secondly, <em>ACF-to-Rest</em> will partially load post relations to determine that they are published and that the data is from the said <code class="language-plaintext highlighter-rouge">post_type</code>.  <em>ACF-to-Rest</em> checks the <code class="language-plaintext highlighter-rouge">person_address</code> by performing the query</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="o">*</span> <span class="k">FROM</span> <span class="n">wp_posts</span> <span class="k">WHERE</span> <span class="n">ID</span> <span class="o">=</span> <span class="mi">15</span> <span class="k">LIMIT</span> <span class="mi">1</span>
</code></pre></div></div>

<p>and the <code class="language-plaintext highlighter-rouge">person_pets</code> by firing multiple queries</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span>   <span class="n">wp_posts</span><span class="p">.</span><span class="o">*</span> <span class="k">FROM</span> <span class="n">wp_posts</span>  <span class="k">WHERE</span> <span class="mi">1</span><span class="o">=</span><span class="mi">1</span>  <span class="k">AND</span> <span class="n">wp_posts</span><span class="p">.</span><span class="n">ID</span> <span class="k">IN</span> <span class="p">(</span><span class="mi">11</span><span class="p">,</span><span class="mi">12</span><span class="p">,</span><span class="mi">13</span><span class="p">)</span> <span class="k">AND</span> <span class="n">wp_posts</span><span class="p">.</span><span class="n">post_type</span> <span class="k">IN</span> <span class="p">(</span><span class="s1">'post'</span><span class="p">,</span> <span class="s1">'page'</span><span class="p">,</span> <span class="s1">'attachment'</span><span class="p">,</span> <span class="s1">'custom_css'</span><span class="p">,</span> <span class="s1">'customize_changeset'</span><span class="p">,</span> <span class="s1">'person'</span><span class="p">,</span> <span class="s1">'address'</span><span class="p">,</span> <span class="s1">'pet'</span><span class="p">)</span> <span class="k">AND</span> <span class="p">((</span><span class="n">wp_posts</span><span class="p">.</span><span class="n">post_status</span> <span class="o">&lt;&gt;</span> <span class="s1">'trash'</span> <span class="k">AND</span> <span class="n">wp_posts</span><span class="p">.</span><span class="n">post_status</span> <span class="o">&lt;&gt;</span> <span class="s1">'auto-draft'</span><span class="p">))</span>  <span class="k">ORDER</span> <span class="k">BY</span> <span class="n">wp_posts</span><span class="p">.</span><span class="n">post_date</span> <span class="k">DESC</span>
<span class="k">SELECT</span>  <span class="n">t</span><span class="p">.</span><span class="o">*</span><span class="p">,</span> <span class="n">tt</span><span class="p">.</span><span class="o">*</span><span class="p">,</span> <span class="n">tr</span><span class="p">.</span><span class="n">object_id</span> <span class="k">FROM</span> <span class="n">wp_terms</span> <span class="k">AS</span> <span class="n">t</span>  <span class="k">INNER</span> <span class="k">JOIN</span> <span class="n">wp_term_taxonomy</span> <span class="k">AS</span> <span class="n">tt</span> <span class="k">ON</span> <span class="n">t</span><span class="p">.</span><span class="n">term_id</span> <span class="o">=</span> <span class="n">tt</span><span class="p">.</span><span class="n">term_id</span> <span class="k">INNER</span> <span class="k">JOIN</span> <span class="n">wp_term_relationships</span> <span class="k">AS</span> <span class="n">tr</span> <span class="k">ON</span> <span class="n">tr</span><span class="p">.</span><span class="n">term_taxonomy_id</span> <span class="o">=</span> <span class="n">tt</span><span class="p">.</span><span class="n">term_taxonomy_id</span> <span class="k">WHERE</span> <span class="n">tt</span><span class="p">.</span><span class="n">taxonomy</span> <span class="k">IN</span> <span class="p">(</span><span class="s1">'category'</span><span class="p">,</span> <span class="s1">'post_tag'</span><span class="p">,</span> <span class="s1">'post_format'</span><span class="p">)</span> <span class="k">AND</span> <span class="n">tr</span><span class="p">.</span><span class="n">object_id</span> <span class="k">IN</span> <span class="p">(</span><span class="mi">13</span><span class="p">,</span> <span class="mi">12</span><span class="p">,</span> <span class="mi">11</span><span class="p">)</span> <span class="k">ORDER</span> <span class="k">BY</span> <span class="n">t</span><span class="p">.</span><span class="n">name</span> 
<span class="k">SELECT</span> <span class="n">post_id</span><span class="p">,</span> <span class="n">meta_key</span><span class="p">,</span> <span class="n">meta_value</span> <span class="k">FROM</span> <span class="n">wp_postmeta</span> <span class="k">WHERE</span> <span class="n">post_id</span> <span class="k">IN</span> <span class="p">(</span><span class="mi">13</span><span class="p">,</span><span class="mi">12</span><span class="p">,</span><span class="mi">11</span><span class="p">)</span> <span class="k">ORDER</span> <span class="k">BY</span> <span class="n">meta_id</span> 
</code></pre></div></div>

<p>Heuristically if a post type has <code class="language-plaintext highlighter-rouge">m</code> instances, there would be around <code class="language-plaintext highlighter-rouge">9 + (5 * m)</code> queries fired to retrieve and check the data.  In our small hierarchy we would thus need</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">9 + (5 * 1)</code> queries to retrieve the person,</li>
  <li>another <code class="language-plaintext highlighter-rouge">(9 + (5 * 3))</code> queries to fully resolve all pets and</li>
  <li>another <code class="language-plaintext highlighter-rouge">(9 + (5 + 1))</code> queries to fully resolve the address.</li>
</ul>

<p>For a fully resolved object graph we would need around <code class="language-plaintext highlighter-rouge">14 + 24 + 14 = 52</code> queries. Ouch!</p>

<h1 id="so-doc-whats-the-problem">So doc, what’s the problem?</h1>
<p>So what causes all these inefficiencies? From the analysis above we can summaries the inefficiencies as follows:</p>

<ol>
  <li>There is an impedance mismatch between the object hierarchy created using WP custom yypes and ACF custom fields and the underlying database storage.</li>
  <li>ACF-to-Rest only resolves first level objects and full object graph resolution is expensive.</li>
  <li>Metadata required to determine what is represented by a value has to be loaded every time at runtime on retrieval and is expensive to retrieve.</li>
</ol>

<p>The first problem is not WP specific.  The object graph created using custom types and fields does not fit the relational model and there is naturally an  impedance mismatch.   All headless CMSs using a relational datamodel as their backing store will have such an impedance mismatch.</p>

<p>The second problem is basically a mismatch in requirements between the ACF API and ACF-to-Rest.  Throughout the years the ACF API has been optimised to load single posts or a group of posts which have a certain type rather than objects or object graphs.  Posts are the atoms that make up the WP universe and objects created by using custom types and fields have to be simulated on top of posts (saved in <code class="language-plaintext highlighter-rouge">wp_post</code> and <code class="language-plaintext highlighter-rouge">wp_postmeta</code>). ACF-to-Rest attempts to resolve objects and object graphs but fails since the underlying API is still stuck in its posts roots.  The developers of ACF-to-Rest resolve the first level hierarchy but make no attempt to directly attack this problem.</p>

<p>Finally, the metadata problem.  If we look at the query log we can determine that a good number of queries are performed to retrieve type metadata.  Due to the fact that the end user is allowed to specify types and fields on these custom types dynamically, ACF is constrained to check the type metadata at runtime.  In a way the <em>ACF API</em> trades safety for performance (which is good) because it cannot do any better.  The biggest problem with this design is that normally one creates a type, associates some fields with that type and starts creating a number of posts. Very rarely does one change the initial type schema.</p>

<p>These three problems combined result in inefficient queries to the underlying database and hence slow retrieval of data.</p>

<h1 id="objects-objects-everywhere---the-acf-compiler">Objects, Objects Everywhere - The ACF Compiler!</h1>
<p>WP is a CMS rooted in the concept of <em>posts</em> but as the WP community matured, higher order concepts such as objects (or structures) were layered on top of the <em>posts</em> concept.  ACF is one of the clear leaders in the abstraction race and through the use of <a href="https://codex.wordpress.org/Post_Types">custom post types</a> and the <a href="https://codex.wordpress.org/Metadata_API">Metadata API</a> it has allowed users to shift from a <em>posts</em> world to an <em>object oriented</em> (or a <em>structures</em>) world.  The shift in paradigm together with the introduction of the REST API in WP v4.7 has allowed WP to compete as a headless CMS with heavyweight contenders such as <a href="https://www.contentful.com/">Contentful</a>.</p>

<p><img class="center" src="/images/acf/objects-objects-everywhere.jpg" /></p>

<p>This is great news! A free headless CMS! Well… just because you can, does not mean you should, at least not with standard WP plugins. In the previous section we have summarised the problems with using WP as a headless CMS.  If we had to reduce the last two points to their essence, we would end up with our opening statement “WP is a CMS rooted in the concept of <em>posts</em>” and this is <strong>the problem</strong> of using WP as a headless CMS.   Every WP plugin which attempts to provide abstractions has to simulate this on top of the lower level post abstraction.  Mapping between <em>post</em> world and <em>object</em> world is expensive and the <em>object</em> lie becomes less and less believable as the number of “objects” in the CMS increases.</p>

<p>Let’s look at the Person example again and work out an ACF equivalent in an OOP language.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@AllArgsConstructor</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">Person</span> <span class="o">{</span>
    <span class="kd">private</span> <span class="nc">String</span> <span class="n">name</span><span class="o">;</span>
    <span class="kd">private</span> <span class="nc">String</span> <span class="n">surname</span><span class="o">;</span>
    <span class="kd">private</span> <span class="nc">Address</span> <span class="n">addressDto</span><span class="o">;</span>
    <span class="kd">private</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Pet</span><span class="o">&gt;</span> <span class="n">pets</span><span class="o">;</span>
<span class="o">}</span>

<span class="nd">@AllArgsConstructor</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">Address</span> <span class="o">{</span>
    <span class="kd">private</span> <span class="nc">String</span> <span class="n">line1</span><span class="o">;</span>
    <span class="kd">private</span> <span class="nc">String</span> <span class="n">line2</span><span class="o">;</span>
    <span class="kd">private</span> <span class="nc">String</span> <span class="n">town</span><span class="o">;</span>
    <span class="kd">private</span> <span class="nc">String</span> <span class="n">country</span><span class="o">;</span>
<span class="o">}</span>

<span class="nd">@AllArgsConstructor</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">Pet</span> <span class="o">{</span>
    <span class="kd">private</span> <span class="nc">String</span> <span class="n">name</span><span class="o">;</span>
    <span class="kd">private</span> <span class="nc">Integer</span>  <span class="n">age</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Immediately we realise that the Person representation in an OO language is more succinct.  OO languages treat objects and relationships (between objects) as first class citizens and hence do not need to simulate objects on top of a <em>post abstraction</em>.  Apart from being more readable, using a typed OO language allows us to annotate type information statically rather than dynamically making type information readily available.  What if we could make use of the static type information present on the class and retrieve the posts directly from the WP database (without using any APIs)? Could this alleviate the problems identified in previous section?  The answer is yes as is demonstrated through this open source initiative.</p>

<p>We start of by reading the class metadata and match this with the WP metadata by calling</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">val</span> <span class="nv">executionPlan</span> <span class="k">=</span> <span class="nv">astCompiler</span><span class="o">.</span><span class="py">compile</span><span class="o">(</span><span class="n">classOf</span><span class="o">[</span><span class="kt">Person</span><span class="o">])</span>
</code></pre></div></div>

<p>Once verified, an execution plan is formulated which when executed will run the most optimal queries to retrieve the data .  To retrieve all Person entries one just needs to call <code class="language-plaintext highlighter-rouge">execute</code> on the <code class="language-plaintext highlighter-rouge">executionPlan</code></p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">val</span> <span class="nv">persons</span>  <span class="k">=</span> <span class="nv">executionPlan</span><span class="o">.</span><span class="py">execute</span><span class="o">()</span>
</code></pre></div></div>

<p>So what are the advantages of such an approach? First off, it does not use any of the inefficient WP APIs.  The query log for the <strong>full graph resolution</strong> is the following:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- Person </span>
<span class="k">select</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">ID</span> <span class="k">as</span> <span class="n">ID1_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_author</span> <span class="k">as</span> <span class="n">post_aut2_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_content</span> <span class="k">as</span> <span class="n">post_con3_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">guid</span> <span class="k">as</span> <span class="n">guid4_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_modified</span> <span class="k">as</span> <span class="n">post_mod5_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_name</span> <span class="k">as</span> <span class="n">post_nam6_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_date</span> <span class="k">as</span> <span class="n">post_dat7_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_status</span> <span class="k">as</span> <span class="n">post_sta8_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_title</span> <span class="k">as</span> <span class="n">post_tit9_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_type</span> <span class="k">as</span> <span class="n">post_ty10_1_</span> <span class="k">from</span> <span class="n">wp_posts</span> <span class="n">cmspost0_</span> <span class="k">where</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_type</span><span class="o">=</span><span class="s1">'person'</span> <span class="k">and</span> <span class="p">(</span><span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_status</span> <span class="k">in</span> <span class="p">(</span><span class="s1">'publish'</span> <span class="p">,</span> <span class="s1">'inherit'</span><span class="p">))</span>
<span class="k">select</span> <span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">meta_id</span> <span class="k">as</span> <span class="n">meta_id1_0_</span><span class="p">,</span> <span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">meta_key</span> <span class="k">as</span> <span class="n">meta_key2_0_</span><span class="p">,</span> <span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">meta_value</span> <span class="k">as</span> <span class="n">meta_val3_0_</span><span class="p">,</span> <span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">post_id</span> <span class="k">as</span> <span class="n">post_id4_0_</span> <span class="k">from</span> <span class="n">wp_postmeta</span> <span class="n">cmspostmet0_</span> <span class="k">where</span> <span class="p">(</span><span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">meta_key</span> <span class="k">in</span> <span class="p">(</span><span class="s1">'id'</span> <span class="p">,</span> <span class="s1">'content'</span> <span class="p">,</span> <span class="s1">'person_pets'</span> <span class="p">,</span> <span class="s1">'person_address'</span> <span class="p">,</span> <span class="s1">'person_name'</span> <span class="p">,</span> <span class="s1">'person_surname'</span><span class="p">))</span> <span class="k">and</span> <span class="p">(</span><span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">post_id</span> <span class="k">in</span> <span class="p">(</span><span class="mi">16</span><span class="p">))</span>

<span class="c1">-- Pet</span>
<span class="k">select</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">ID</span> <span class="k">as</span> <span class="n">ID1_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_author</span> <span class="k">as</span> <span class="n">post_aut2_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_content</span> <span class="k">as</span> <span class="n">post_con3_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">guid</span> <span class="k">as</span> <span class="n">guid4_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_modified</span> <span class="k">as</span> <span class="n">post_mod5_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_name</span> <span class="k">as</span> <span class="n">post_nam6_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_date</span> <span class="k">as</span> <span class="n">post_dat7_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_status</span> <span class="k">as</span> <span class="n">post_sta8_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_title</span> <span class="k">as</span> <span class="n">post_tit9_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_type</span> <span class="k">as</span> <span class="n">post_ty10_1_</span> <span class="k">from</span> <span class="n">wp_posts</span> <span class="n">cmspost0_</span> <span class="k">where</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_type</span><span class="o">=</span><span class="s1">'pet'</span> <span class="k">and</span> <span class="p">(</span><span class="n">cmspost0_</span><span class="p">.</span><span class="n">ID</span> <span class="k">in</span> <span class="p">(</span><span class="mi">11</span> <span class="p">,</span> <span class="mi">12</span> <span class="p">,</span> <span class="mi">13</span><span class="p">))</span> <span class="k">and</span> <span class="p">(</span><span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_status</span> <span class="k">in</span> <span class="p">(</span><span class="s1">'publish'</span><span class="p">))</span>
<span class="k">select</span> <span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">meta_id</span> <span class="k">as</span> <span class="n">meta_id1_0_</span><span class="p">,</span> <span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">meta_key</span> <span class="k">as</span> <span class="n">meta_key2_0_</span><span class="p">,</span> <span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">meta_value</span> <span class="k">as</span> <span class="n">meta_val3_0_</span><span class="p">,</span> <span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">post_id</span> <span class="k">as</span> <span class="n">post_id4_0_</span> <span class="k">from</span> <span class="n">wp_postmeta</span> <span class="n">cmspostmet0_</span> <span class="k">where</span> <span class="p">(</span><span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">meta_key</span> <span class="k">in</span> <span class="p">(</span><span class="s1">'pet_name'</span> <span class="p">,</span> <span class="s1">'pet_age'</span> <span class="p">,</span> <span class="s1">'id'</span><span class="p">))</span> <span class="k">and</span> <span class="p">(</span><span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">post_id</span> <span class="k">in</span> <span class="p">(</span><span class="mi">11</span> <span class="p">,</span> <span class="mi">12</span> <span class="p">,</span> <span class="mi">13</span><span class="p">))</span>

<span class="c1">-- Address</span>
<span class="k">select</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">ID</span> <span class="k">as</span> <span class="n">ID1_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_author</span> <span class="k">as</span> <span class="n">post_aut2_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_content</span> <span class="k">as</span> <span class="n">post_con3_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">guid</span> <span class="k">as</span> <span class="n">guid4_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_modified</span> <span class="k">as</span> <span class="n">post_mod5_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_name</span> <span class="k">as</span> <span class="n">post_nam6_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_date</span> <span class="k">as</span> <span class="n">post_dat7_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_status</span> <span class="k">as</span> <span class="n">post_sta8_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_title</span> <span class="k">as</span> <span class="n">post_tit9_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_type</span> <span class="k">as</span> <span class="n">post_ty10_1_</span> <span class="k">from</span> <span class="n">wp_posts</span> <span class="n">cmspost0_</span> <span class="k">where</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_type</span><span class="o">=</span><span class="s1">'address'</span> <span class="k">and</span> <span class="p">(</span><span class="n">cmspost0_</span><span class="p">.</span><span class="n">ID</span> <span class="k">in</span> <span class="p">(</span><span class="mi">15</span><span class="p">))</span> <span class="k">and</span> <span class="p">(</span><span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_status</span> <span class="k">in</span> <span class="p">(</span><span class="s1">'publish'</span><span class="p">))</span>
<span class="k">select</span> <span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">meta_id</span> <span class="k">as</span> <span class="n">meta_id1_0_</span><span class="p">,</span> <span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">meta_key</span> <span class="k">as</span> <span class="n">meta_key2_0_</span><span class="p">,</span> <span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">meta_value</span> <span class="k">as</span> <span class="n">meta_val3_0_</span><span class="p">,</span> <span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">post_id</span> <span class="k">as</span> <span class="n">post_id4_0_</span> <span class="k">from</span> <span class="n">wp_postmeta</span> <span class="n">cmspostmet0_</span> <span class="k">where</span> <span class="p">(</span><span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">meta_key</span> <span class="k">in</span> <span class="p">(</span><span class="s1">'address_town'</span> <span class="p">,</span> <span class="s1">'id'</span> <span class="p">,</span> <span class="s1">'address_country'</span> <span class="p">,</span> <span class="s1">'address_line_2'</span> <span class="p">,</span> <span class="s1">'address_line_1'</span><span class="p">))</span> <span class="k">and</span> <span class="p">(</span><span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">post_id</span> <span class="k">in</span> <span class="p">(</span><span class="mi">15</span><span class="p">))</span>
</code></pre></div></div>

<p>From the query log we can observe that for a complete object graph resolution we only need 6 queries as opposed to the 52 queries required when using the WP plugins.  The second advantage is that our system is aware of relationships between objects.  To understand this let us remove the Address relationship from the Person class as follows</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">Person</span> <span class="o">{</span>
    <span class="kd">private</span> <span class="nc">String</span> <span class="n">name</span><span class="o">;</span>
    <span class="kd">private</span> <span class="nc">String</span> <span class="n">surname</span><span class="o">;</span>
    <span class="kd">private</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Pet</span><span class="o">&gt;</span> <span class="n">pets</span><span class="o">;</span>
<span class="o">}</span>

<span class="kd">public</span> <span class="kd">class</span> <span class="nc">Pet</span> <span class="o">{</span>
    <span class="kd">private</span> <span class="nc">String</span> <span class="n">name</span><span class="o">;</span>
    <span class="kd">private</span> <span class="nc">Integer</span>  <span class="n">age</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Our system is able to identify that the relationship is no longer present and optimise the queries generated as follows:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- Person </span>
<span class="k">select</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">ID</span> <span class="k">as</span> <span class="n">ID1_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_author</span> <span class="k">as</span> <span class="n">post_aut2_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_content</span> <span class="k">as</span> <span class="n">post_con3_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">guid</span> <span class="k">as</span> <span class="n">guid4_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_modified</span> <span class="k">as</span> <span class="n">post_mod5_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_name</span> <span class="k">as</span> <span class="n">post_nam6_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_date</span> <span class="k">as</span> <span class="n">post_dat7_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_status</span> <span class="k">as</span> <span class="n">post_sta8_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_title</span> <span class="k">as</span> <span class="n">post_tit9_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_type</span> <span class="k">as</span> <span class="n">post_ty10_1_</span> <span class="k">from</span> <span class="n">wp_posts</span> <span class="n">cmspost0_</span> <span class="k">where</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_type</span><span class="o">=</span><span class="s1">'person'</span> <span class="k">and</span> <span class="p">(</span><span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_status</span> <span class="k">in</span> <span class="p">(</span><span class="s1">'publish'</span> <span class="p">,</span> <span class="s1">'inherit'</span><span class="p">))</span>
<span class="k">select</span> <span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">meta_id</span> <span class="k">as</span> <span class="n">meta_id1_0_</span><span class="p">,</span> <span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">meta_key</span> <span class="k">as</span> <span class="n">meta_key2_0_</span><span class="p">,</span> <span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">meta_value</span> <span class="k">as</span> <span class="n">meta_val3_0_</span><span class="p">,</span> <span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">post_id</span> <span class="k">as</span> <span class="n">post_id4_0_</span> <span class="k">from</span> <span class="n">wp_postmeta</span> <span class="n">cmspostmet0_</span> <span class="k">where</span> <span class="p">(</span><span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">meta_key</span> <span class="k">in</span> <span class="p">(</span><span class="s1">'id'</span> <span class="p">,</span> <span class="s1">'content'</span> <span class="p">,</span> <span class="s1">'person_pets'</span> <span class="p">,</span> <span class="s1">'person_address'</span> <span class="p">,</span> <span class="s1">'person_name'</span> <span class="p">,</span> <span class="s1">'person_surname'</span><span class="p">))</span> <span class="k">and</span> <span class="p">(</span><span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">post_id</span> <span class="k">in</span> <span class="p">(</span><span class="mi">16</span><span class="p">))</span>

<span class="c1">-- Pet</span>
<span class="k">select</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">ID</span> <span class="k">as</span> <span class="n">ID1_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_author</span> <span class="k">as</span> <span class="n">post_aut2_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_content</span> <span class="k">as</span> <span class="n">post_con3_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">guid</span> <span class="k">as</span> <span class="n">guid4_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_modified</span> <span class="k">as</span> <span class="n">post_mod5_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_name</span> <span class="k">as</span> <span class="n">post_nam6_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_date</span> <span class="k">as</span> <span class="n">post_dat7_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_status</span> <span class="k">as</span> <span class="n">post_sta8_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_title</span> <span class="k">as</span> <span class="n">post_tit9_1_</span><span class="p">,</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_type</span> <span class="k">as</span> <span class="n">post_ty10_1_</span> <span class="k">from</span> <span class="n">wp_posts</span> <span class="n">cmspost0_</span> <span class="k">where</span> <span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_type</span><span class="o">=</span><span class="s1">'pet'</span> <span class="k">and</span> <span class="p">(</span><span class="n">cmspost0_</span><span class="p">.</span><span class="n">ID</span> <span class="k">in</span> <span class="p">(</span><span class="mi">11</span> <span class="p">,</span> <span class="mi">12</span> <span class="p">,</span> <span class="mi">13</span><span class="p">))</span> <span class="k">and</span> <span class="p">(</span><span class="n">cmspost0_</span><span class="p">.</span><span class="n">post_status</span> <span class="k">in</span> <span class="p">(</span><span class="s1">'publish'</span><span class="p">))</span>
<span class="k">select</span> <span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">meta_id</span> <span class="k">as</span> <span class="n">meta_id1_0_</span><span class="p">,</span> <span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">meta_key</span> <span class="k">as</span> <span class="n">meta_key2_0_</span><span class="p">,</span> <span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">meta_value</span> <span class="k">as</span> <span class="n">meta_val3_0_</span><span class="p">,</span> <span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">post_id</span> <span class="k">as</span> <span class="n">post_id4_0_</span> <span class="k">from</span> <span class="n">wp_postmeta</span> <span class="n">cmspostmet0_</span> <span class="k">where</span> <span class="p">(</span><span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">meta_key</span> <span class="k">in</span> <span class="p">(</span><span class="s1">'pet_name'</span> <span class="p">,</span> <span class="s1">'pet_age'</span> <span class="p">,</span> <span class="s1">'id'</span><span class="p">))</span> <span class="k">and</span> <span class="p">(</span><span class="n">cmspostmet0_</span><span class="p">.</span><span class="n">post_id</span> <span class="k">in</span> <span class="p">(</span><span class="mi">11</span> <span class="p">,</span> <span class="mi">12</span> <span class="p">,</span> <span class="mi">13</span><span class="p">))</span>
</code></pre></div></div>

<h1 id="class-annotations">Class Annotations</h1>
<p>Our previous example is a bit simplified.  In reality we would need to annotate the classes so that the <em>ACF Compiler</em> can work out the most optimal queries and verify that the metadata in WP matches the static metadata on the class.  Fortunately, the annotations are pretty self explanatory.  The complete Person example is as follows:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Getter</span>
<span class="nd">@PostType</span><span class="o">(</span><span class="s">"person"</span><span class="o">)</span>
<span class="n">public</span> <span class="k">class</span> <span class="nc">Person</span> <span class="o">{</span>
    <span class="nd">@Alias</span><span class="o">(</span><span class="s">"person_name"</span><span class="o">)</span>
    <span class="k">private</span> <span class="nc">String</span> <span class="n">name</span><span class="o">;</span>
    <span class="nd">@Alias</span><span class="o">(</span><span class="s">"person_surname"</span><span class="o">)</span>
    <span class="k">private</span> <span class="nc">String</span> <span class="n">surname</span><span class="o">;</span>
    <span class="nd">@Alias</span><span class="o">(</span><span class="s">"person_address"</span><span class="o">)</span>
    <span class="k">private</span> <span class="nc">Address</span> <span class="n">addresses</span><span class="o">;</span>
    <span class="nd">@Alias</span><span class="o">(</span><span class="s">"person_pets"</span><span class="o">)</span>
    <span class="k">private</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Pet</span><span class="o">&gt;</span> <span class="n">pets</span><span class="o">;</span>
<span class="o">}</span>

<span class="nd">@Getter</span>
<span class="nd">@PostType</span><span class="o">(</span><span class="s">"address"</span><span class="o">)</span>
<span class="n">public</span> <span class="k">class</span> <span class="nc">Address</span> <span class="o">{</span>
    <span class="nd">@Alias</span><span class="o">(</span><span class="s">"address_line_1"</span><span class="o">)</span>
    <span class="k">private</span> <span class="nc">String</span> <span class="n">line1</span><span class="o">;</span>
    <span class="nd">@Alias</span><span class="o">(</span><span class="s">"address_line_2"</span><span class="o">)</span>
    <span class="k">private</span> <span class="nc">String</span> <span class="n">line2</span><span class="o">;</span>
    <span class="nd">@Alias</span><span class="o">(</span><span class="s">"address_town"</span><span class="o">)</span>
    <span class="k">private</span> <span class="nc">String</span> <span class="n">town</span><span class="o">;</span>
    <span class="nd">@Alias</span><span class="o">(</span><span class="s">"address_country"</span><span class="o">)</span>
    <span class="k">private</span> <span class="nc">String</span> <span class="n">country</span><span class="o">;</span>
<span class="o">}</span>

<span class="nd">@Getter</span>
<span class="nd">@PostType</span><span class="o">(</span><span class="s">"pet"</span><span class="o">)</span>
<span class="n">public</span> <span class="k">class</span> <span class="nc">Pet</span> <span class="o">{</span>
    <span class="nd">@Alias</span><span class="o">(</span><span class="s">"pet_name"</span><span class="o">)</span>
    <span class="k">private</span> <span class="nc">String</span> <span class="n">name</span><span class="o">;</span>
    <span class="nd">@Alias</span><span class="o">(</span><span class="s">"pet_age"</span><span class="o">)</span>
    <span class="k">private</span> <span class="nc">Integer</span>  <span class="n">age</span><span class="o">;</span>
<span class="o">}</span>

<span class="k">val</span> <span class="nv">executionPlan</span> <span class="k">=</span> <span class="nv">astCompiler</span><span class="o">.</span><span class="py">compile</span><span class="o">(</span><span class="n">classOf</span><span class="o">[</span><span class="kt">Person</span><span class="o">])</span>
<span class="k">val</span> <span class="nv">persons</span>  <span class="k">=</span> <span class="nv">executionPlan</span><span class="o">.</span><span class="py">execute</span><span class="o">()</span>
</code></pre></div></div>

<h1 id="graph-cycles-and-caching">Graph Cycles and Caching</h1>
<p>Objects in an object graph may be referenced from multiple objects and may contain cycles.  Cycles and multiple references lead to inefficient queries and hence we need a way to identify whether two objects are equal.  In WP equality can be based on the post identifier (finally some good came out of posts!).    In the <em>ACF Compiler</em> we will detect whether a class implements the <code class="language-plaintext highlighter-rouge">CmsPostIdentifier</code> interface and if it does, the compiler will reuse objects which have already been loaded through multiple references or cycles.  The Person example above can be update as follows:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Getter</span>
<span class="nd">@PostType</span><span class="o">(</span><span class="s">"person"</span><span class="o">)</span>
<span class="n">public</span> <span class="k">class</span> <span class="nc">Person</span> <span class="n">implements</span> <span class="nc">CmsPostIdentifier</span> <span class="o">{</span>
    <span class="nd">@Alias</span><span class="o">(</span><span class="s">"id"</span><span class="o">)</span>
    <span class="k">private</span> <span class="nc">Long</span> <span class="n">wordpressId</span><span class="o">;</span>
    <span class="nd">@Alias</span><span class="o">(</span><span class="s">"person_name"</span><span class="o">)</span>
    <span class="k">private</span> <span class="nc">String</span> <span class="n">name</span><span class="o">;</span>
    <span class="nd">@Alias</span><span class="o">(</span><span class="s">"person_surname"</span><span class="o">)</span>
    <span class="k">private</span> <span class="nc">String</span> <span class="n">surname</span><span class="o">;</span>
    <span class="nd">@Alias</span><span class="o">(</span><span class="s">"person_address"</span><span class="o">)</span>
    <span class="k">private</span> <span class="nc">Address</span> <span class="n">addresses</span><span class="o">;</span>
    <span class="nd">@Alias</span><span class="o">(</span><span class="s">"person_pets"</span><span class="o">)</span>
    <span class="k">private</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Pet</span><span class="o">&gt;</span> <span class="n">pets</span><span class="o">;</span>
<span class="o">}</span>

<span class="nd">@Getter</span>
<span class="nd">@PostType</span><span class="o">(</span><span class="s">"address"</span><span class="o">)</span>
<span class="n">public</span> <span class="k">class</span> <span class="nc">Address</span> <span class="n">implements</span> <span class="nc">CmsPostIdentifier</span> <span class="o">{</span>
    <span class="nd">@Alias</span><span class="o">(</span><span class="s">"id"</span><span class="o">)</span>
    <span class="k">private</span> <span class="nc">Long</span> <span class="n">wordpressId</span><span class="o">;</span>
    <span class="nd">@Alias</span><span class="o">(</span><span class="s">"address_line_1"</span><span class="o">)</span>
    <span class="k">private</span> <span class="nc">String</span> <span class="n">line1</span><span class="o">;</span>
    <span class="nd">@Alias</span><span class="o">(</span><span class="s">"address_line_2"</span><span class="o">)</span>
    <span class="k">private</span> <span class="nc">String</span> <span class="n">line2</span><span class="o">;</span>
    <span class="nd">@Alias</span><span class="o">(</span><span class="s">"address_town"</span><span class="o">)</span>
    <span class="k">private</span> <span class="nc">String</span> <span class="n">town</span><span class="o">;</span>
    <span class="nd">@Alias</span><span class="o">(</span><span class="s">"address_country"</span><span class="o">)</span>
    <span class="k">private</span> <span class="nc">String</span> <span class="n">country</span><span class="o">;</span>
<span class="o">}</span>

<span class="nd">@Getter</span>
<span class="nd">@PostType</span><span class="o">(</span><span class="s">"pet"</span><span class="o">)</span>
<span class="n">public</span> <span class="k">class</span> <span class="nc">Pet</span> <span class="n">implements</span> <span class="nc">CmsPostIdentifier</span> <span class="o">{</span>
    <span class="nd">@Alias</span><span class="o">(</span><span class="s">"id"</span><span class="o">)</span>
    <span class="k">private</span> <span class="nc">Long</span> <span class="n">wordpressId</span><span class="o">;</span>
    <span class="nd">@Alias</span><span class="o">(</span><span class="s">"pet_name"</span><span class="o">)</span>
    <span class="k">private</span> <span class="nc">String</span> <span class="n">name</span><span class="o">;</span>
    <span class="nd">@Alias</span><span class="o">(</span><span class="s">"pet_age"</span><span class="o">)</span>
    <span class="k">private</span> <span class="nc">Integer</span>  <span class="n">age</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Note that we added a field <code class="language-plaintext highlighter-rouge">wordpressId</code> in the above example which stores the WP identifier and hence hold the definition of equality. The compiler will take care of setting the correct value to this field.</p>

<h1 id="conclusion">Conclusion</h1>
<p>Historically WP was a CMS rooted in the concept of a “post” however as of version 3.0, WP enabled users to add <a href="https://codex.wordpress.org/Post_Types">custom post types</a> and also opened the <a href="https://codex.wordpress.org/Metadata_API">Metadata API</a>.  Custom Post Types and ACF (which builds on top of the Metadata API) have allowed WP to move up the abstraction hierarchy and allow users to think in terms of objects rather than posts. Mapping between <em>post world</em> and <em>object world</em> is expensive in WP and might be a limiting factor in real world applications.</p>

<p>In this blog post I have outlined our efforts to directly address this issue and reduce retrieval time drastically.  On our production environments we have seen bootstrap times drop from 1 minute to a couple of seconds. We have tested this system extensively and we would love to share our initiative with the community.</p>

<p>In the coming days  we will create a generic test suite (our tests are too domain specific) to make sure things do not regress.  We will also explain in more depth how one can use this library as well as give some design outline so that you guys can understand how everything fits together.   We are also experimenting with execution of queries in parallel (some queries are independent) but it’s still early days.</p>

<p>If you have been working with WP and you are using a similar approach, please reach out - we would love to collaborate. I feel super excited to be in a position where we can give something back! We owe it to the community.  If you want to contribute have a look at the project page <a href="https://github.com/suprnation/wordpress-acf">Github</a> - we will be updating it in the coming days.  If you have questions, comments (or insults) please comment below.  Stay safe, stay tuned and keep hacking!</p>]]></content><author><name>Mark Galea</name></author><summary type="html"><![CDATA[Headless CMSs are becoming quite popular and make up one of the important ingredients of a JAMstack site. At SuprNation we have been tinkering with headless CMSs for quite a while and we have succesfully implemented one using Wordpress (WP), Advanced Custom Fields (ACF) and ACF-to-Rest API in one of our experiments. This trio can be used to implement a cheap and flexible headless CMS but as anyone who has worked with ACF knows, retrieving the underlying data can be slow if one relies on the current WP plugins. In this post I am going to describe how we have overcome this problem and introduce our open source initiative that drastically reduces the number of queries and round trips to the database.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://cloudmark.github.io/images/acf/acf.png" /><media:content medium="image" url="http://cloudmark.github.io/images/acf/acf.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>